GPv3: Lock unselect materials operator #115278

Merged
Antonio Vazquez merged 13 commits from antoniov/blender:GPv3_mat_lock_unselect into main 2023-11-28 16:39:08 +01:00
87 changed files with 1411 additions and 557 deletions
Showing only changes of commit 316cc8a47d - Show all commits

View File

@ -599,7 +599,7 @@ doc_dna: .FORCE
@echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'"
doc_man: .FORCE
@$(PYTHON) doc/manpage/blender.1.py --blender="$(BLENDER_BIN)" --output=blender.1 --verbose
@$(BLENDER_BIN) --background --python doc/manpage/blender.1.py -- --output=blender.1 --verbose
help_features: .FORCE
@$(PYTHON) "$(BLENDER_DIR)/build_files/cmake/cmake_print_build_options.py" $(BLENDER_DIR)"/CMakeLists.txt"

View File

@ -41,7 +41,7 @@ def blender_extract_info() -> Dict[str, str]:
# Happens when built without WITH_BUILD_INFO e.g.
blender_date = time.strftime("%B %d, %Y", time.gmtime(int(os.environ.get('SOURCE_DATE_EPOCH', time.time()))))
else:
blender_date = time.strftime("%B %d, %Y", time.strptime(blender_build_date_text, "%Y-%m-%d"))
blender_date = time.strftime("%B %d, %Y", time.strptime(blender_build_date_text.decode(), "%Y-%m-%d"))
return {
"help": blender_help_text,

View File

@ -0,0 +1,92 @@
"""
Custom compute shader (using image store) and vertex/fragment shader
--------------------------------------------------------------------
This is an example of how to use a custom compute shader to write to a texture and then use that texture in a vertex/fragment shader.
The expected result is a 2x2 plane (size of the default cube), which changes color from a green-black gradient to a green-red gradient,
based on current time.
"""
import bpy
import gpu
from mathutils import Matrix
from gpu_extras.batch import batch_for_shader
import array
import time
start_time = time.time()
size = 128
texture = gpu.types.GPUTexture((size, size), format='RGBA32F')
# Create the compute shader to write to the texture
compute_shader_info = gpu.types.GPUShaderCreateInfo()
compute_shader_info.image(0, 'RGBA32F', "FLOAT_2D", "img_output", qualifiers={"WRITE"})
compute_shader_info.compute_source('''
void main()
{
vec4 pixel = vec4(
sin(time / 1.0),
gl_GlobalInvocationID.y/128.0,
0.0,
1.0
);
imageStore(img_output, ivec2(gl_GlobalInvocationID.xy), pixel);
}''')
compute_shader_info.push_constant('FLOAT', "time")
compute_shader_info.local_group_size(1, 1)
compute_shader = gpu.shader.create_from_info(compute_shader_info)
# Create the shader to draw the texture
vert_out = gpu.types.GPUStageInterfaceInfo("my_interface")
vert_out.smooth('VEC2', "uvInterp")
shader_info = gpu.types.GPUShaderCreateInfo()
shader_info.push_constant('MAT4', "viewProjectionMatrix")
shader_info.push_constant('MAT4', "modelMatrix")
shader_info.sampler(0, 'FLOAT_2D', "img_input")
shader_info.vertex_in(0, 'VEC2', "position")
shader_info.vertex_in(1, 'VEC2', "uv")
shader_info.vertex_out(vert_out)
shader_info.fragment_out(0, 'VEC4', "FragColor")
shader_info.vertex_source(
"void main()"
"{"
" uvInterp = uv;"
" gl_Position = viewProjectionMatrix * modelMatrix * vec4(position, 0.0, 1.0);"
"}"
)
shader_info.fragment_source(
"void main()"
"{"
" FragColor = texture(img_input, uvInterp);"
"}"
)
shader = gpu.shader.create_from_info(shader_info)
batch = batch_for_shader(
shader, 'TRI_FAN',
{
"position": ((-1, -1), (1, -1), (1, 1), (-1, 1)),
"uv": ((0, 0), (1, 0), (1, 1), (0, 1)),
},
)
def draw():
shader.uniform_float("modelMatrix", Matrix.Translation((0, 0, 0)) @ Matrix.Scale(1, 4))
shader.uniform_float("viewProjectionMatrix", bpy.context.region_data.perspective_matrix)
shader.uniform_sampler("img_input", texture)
batch.draw(shader)
compute_shader.image('img_output', texture)
compute_shader.uniform_float("time", time.time() - start_time)
gpu.compute.dispatch(compute_shader, 128, 128, 1)
def drawTimer():
for area in bpy.context.screen.areas:
if area.type == 'VIEW_3D':
area.tag_redraw()
return 1.0 / 60.0
bpy.app.timers.register(drawTimer)
bpy.types.SpaceView3D.draw_handler_add(draw, (), 'WINDOW', 'POST_VIEW')

View File

@ -66,10 +66,10 @@ template<> struct AttributeConverter<blender::ColorGeometry4b> {
static constexpr auto type_desc = TypeRGBA;
static CyclesT convert(const blender::ColorGeometry4b &value)
{
return color_srgb_to_linear(make_float4(byte_to_float(value[0]),
byte_to_float(value[1]),
byte_to_float(value[2]),
byte_to_float(value[3])));
return color_srgb_to_linear_v4(make_float4(byte_to_float(value[0]),
byte_to_float(value[1]),
byte_to_float(value[2]),
byte_to_float(value[3])));
}
};
template<> struct AttributeConverter<bool> {

View File

@ -253,7 +253,7 @@ ccl_device float3 xyY_to_xyz(float x, float y, float Y)
* exp = exponent, encoded as uint32_t
* e2coeff = 2^(127/exponent - 127) * bias_coeff^(1/exponent), encoded as uint32_t
*/
template<unsigned exp, unsigned e2coeff> ccl_device_inline float4 fastpow(const float4 &arg)
template<unsigned exp, unsigned e2coeff> ccl_device_inline float4 fastpow_sse2(const float4 &arg)
{
float4 ret = arg * cast(make_int4(e2coeff));
ret = make_float4(cast(ret));
@ -263,7 +263,7 @@ template<unsigned exp, unsigned e2coeff> ccl_device_inline float4 fastpow(const
}
/* Improve x ^ 1.0f/5.0f solution with Newton-Raphson method */
ccl_device_inline float4 improve_5throot_solution(const float4 &old_result, const float4 &x)
ccl_device_inline float4 improve_5throot_solution_sse2(const float4 &old_result, const float4 &x)
{
float4 approx2 = old_result * old_result;
float4 approx4 = approx2 * approx2;
@ -273,7 +273,7 @@ ccl_device_inline float4 improve_5throot_solution(const float4 &old_result, cons
}
/* Calculate powf(x, 2.4). Working domain: 1e-10 < x < 1e+10 */
ccl_device_inline float4 fastpow24(const float4 &arg)
ccl_device_inline float4 fastpow24_sse2(const float4 &arg)
{
/* max, avg and |avg| errors were calculated in gcc without FMA instructions
* The final precision should be better than powf in glibc */
@ -281,27 +281,27 @@ ccl_device_inline float4 fastpow24(const float4 &arg)
/* Calculate x^4/5, coefficient 0.994 was constructed manually to minimize avg error */
/* 0x3F4CCCCD = 4/5 */
/* 0x4F55A7FB = 2^(127/(4/5) - 127) * 0.994^(1/(4/5)) */
float4 x = fastpow<0x3F4CCCCD, 0x4F55A7FB>(
float4 x = fastpow_sse2<0x3F4CCCCD, 0x4F55A7FB>(
arg); // error max = 0.17 avg = 0.0018 |avg| = 0.05
float4 arg2 = arg * arg;
float4 arg4 = arg2 * arg2;
/* error max = 0.018 avg = 0.0031 |avg| = 0.0031 */
x = improve_5throot_solution(x, arg4);
x = improve_5throot_solution_sse2(x, arg4);
/* error max = 0.00021 avg = 1.6e-05 |avg| = 1.6e-05 */
x = improve_5throot_solution(x, arg4);
x = improve_5throot_solution_sse2(x, arg4);
/* error max = 6.1e-07 avg = 5.2e-08 |avg| = 1.1e-07 */
x = improve_5throot_solution(x, arg4);
x = improve_5throot_solution_sse2(x, arg4);
return x * (x * x);
}
ccl_device float4 color_srgb_to_linear(const float4 &c)
ccl_device float4 color_srgb_to_linear_sse2(const float4 &c)
{
int4 cmp = c < make_float4(0.04045f);
float4 lt = max(c * make_float4(1.0f / 12.92f), make_float4(0.0f));
float4 gtebase = (c + make_float4(0.055f)) * make_float4(1.0f / 1.055f); /* fma */
float4 gte = fastpow24(gtebase);
float4 gte = fastpow24_sse2(gtebase);
return select(cmp, lt, gte);
}
#endif /* __KERNEL_SSE2__ */
@ -328,7 +328,7 @@ ccl_device float4 color_srgb_to_linear_v4(float4 c)
{
#ifdef __KERNEL_SSE2__
float4 r = c;
r = color_srgb_to_linear(r);
r = color_srgb_to_linear_sse2(r);
r.w = c.w;
return r;
#else

View File

@ -13,8 +13,8 @@ CCL_NAMESPACE_BEGIN
thread::thread(function<void()> run_cb) : run_cb_(run_cb), joined_(false)
{
#ifdef __APPLE__
/* Set the stack size to 2MB to match Linux. The default 512KB on macOS is
#if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__)
/* Set the stack size to 2MB to match glibc. The default 512KB on macOS is
* too small for Embree, and consistent stack size also makes things more
* predictable in general. */
pthread_attr_t attribute;
@ -43,7 +43,7 @@ void *thread::run(void *arg)
bool thread::join()
{
joined_ = true;
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__)
return pthread_join(pthread_id, NULL) == 0;
#else
try {

View File

@ -43,7 +43,7 @@ class thread {
protected:
function<void()> run_cb_;
#ifdef __APPLE__
#if defined(__APPLE__) || defined(__linux__) && !defined(__GLIBC__)
pthread_t pthread_id;
#else
std::thread std_thread;

View File

@ -19,7 +19,14 @@ class GPENCIL_MT_material_context_menu(Menu):
layout = self.layout
if context.preferences.experimental.use_grease_pencil_version3:
layout.operator("grease_pencil.material_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
layout.operator("grease_pencil.material_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").invert = True
layout.separator()
layout.operator("grease_pencil.material_lock_all", icon='LOCKED', text="Lock All")
layout.operator("grease_pencil.material_unlock_all", icon='UNLOCKED', text="Unlock All")
layout.operator("grease_pencil.material_lock_unselected", text="Lock Unselected")
layout.operator("grease_pencil.material_lock_unused", text="Lock Unused")
else:
layout.operator("gpencil.material_reveal", icon='RESTRICT_VIEW_OFF', text="Show All")
layout.operator("gpencil.material_hide", icon='RESTRICT_VIEW_ON', text="Hide Others").unselected = True

View File

@ -6732,7 +6732,7 @@ class VIEW3D_PT_shading_render_pass(Panel):
bl_region_type = 'HEADER'
bl_label = "Render Pass"
bl_parent_id = "VIEW3D_PT_shading"
COMPAT_ENGINES = {'BLENDER_EEVEE'}
COMPAT_ENGINES = {'BLENDER_EEVEE', 'BLENDER_EEVEE_NEXT'}
@classmethod
def poll(cls, context):

View File

@ -132,7 +132,7 @@ bool is_autokey_on(const Scene *scene);
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode);
/** Check if a flag is set for auto-key-framing (per scene takes precedence). */
bool is_autokey_flag(const Scene *scene, eAutokey_Flag flag);
bool is_autokey_flag(const Scene *scene, eKeyInsert_Flag flag);
/**
* Auto-keyframing feature - checks for whether anything should be done for the current frame.

View File

@ -48,7 +48,7 @@ bool is_autokey_mode(const Scene *scene, const eAutokey_Mode mode)
return U.autokey_mode == mode;
}
bool is_autokey_flag(const Scene *scene, const eAutokey_Flag flag)
bool is_autokey_flag(const Scene *scene, const eKeyInsert_Flag flag)
{
if (scene) {
return (scene->toolsettings->autokey_flag & flag) || (U.autokey_flag & flag);
@ -114,7 +114,7 @@ void autokeyframe_object(
C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAIL)) {
else if (is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
/* Only key on available channels. */
AnimData *adt = ob->adt;
ToolSettings *ts = scene->toolsettings;
@ -280,7 +280,7 @@ void autokeyframe_pose(bContext *C, Scene *scene, Object *ob, int tmode, short t
C, &sources, active_ks, MODIFYKEY_MODE_INSERT, anim_eval_context.eval_time);
}
/* only insert into available channels? */
else if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAIL)) {
else if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
if (act) {
LISTBASE_FOREACH (FCurve *, fcu, &act->curves) {
/* only insert keyframes for this F-Curve if it affects the current bone */

View File

@ -891,6 +891,14 @@ void gather_attributes_group_to_group(AttributeAccessor src_attributes,
const IndexMask &selection,
MutableAttributeAccessor dst_attributes);
void gather_attributes_to_groups(AttributeAccessor src_attributes,
eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
OffsetIndices<int> dst_offsets,
const IndexMask &src_selection,
MutableAttributeAccessor dst_attributes);
void copy_attributes(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,

View File

@ -14,6 +14,7 @@
#include "BLI_math_quaternion.hh"
#include "BLI_math_vector.h"
#include "BLI_math_vector.hh"
#include "BLI_offset_indices.hh"
#include "BKE_customdata.hh"
@ -634,6 +635,15 @@ template<typename T> using DefaultMixer = typename DefaultMixerStruct<T>::type;
void gather(GSpan src, Span<int> map, GMutableSpan dst);
void gather(const GVArray &src, Span<int> map, GMutableSpan dst);
void gather_group_to_group(OffsetIndices<int> src_offsets,
OffsetIndices<int> dst_offsets,
const IndexMask &selection,
GSpan src,
GMutableSpan dst);
void gather_to_groups(OffsetIndices<int> dst_offsets,
const IndexMask &src_selection,
GSpan src,
GMutableSpan dst);
/** \} */

View File

@ -312,6 +312,10 @@ bool BKE_collection_validate(struct Collection *collection);
/* .blend file I/O */
/** Perform some pre-writing cleanup on the COllection data itself (_not_ in any sub-data
* referenced by pointers). To be called before writing the Collection struct itself. */
void BKE_collection_blend_write_prepare_nolib(struct BlendWriter *writer,
struct Collection *collection);
void BKE_collection_blend_write_nolib(struct BlendWriter *writer, struct Collection *collection);
void BKE_collection_blend_read_data(struct BlendDataReader *reader,
struct Collection *collection,

View File

@ -905,7 +905,7 @@ static bool indices_are_range(const Span<int> indices, const IndexRange range)
}
return true;
},
[](const bool a, const bool b) { return a && b; });
std::logical_and());
}
void gather_attributes(const AttributeAccessor src_attributes,
@ -942,30 +942,6 @@ void gather_attributes(const AttributeAccessor src_attributes,
}
}
template<typename T>
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const Span<T> src,
MutableSpan<T> dst)
{
selection.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
});
}
static void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const GSpan src,
GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
gather_group_to_group(src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
});
}
void gather_attributes_group_to_group(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
@ -991,7 +967,37 @@ void gather_attributes_group_to_group(const AttributeAccessor src_attributes,
if (!dst) {
return true;
}
gather_group_to_group(src_offsets, dst_offsets, selection, src, dst.span);
attribute_math::gather_group_to_group(src_offsets, dst_offsets, selection, src, dst.span);
dst.finish();
return true;
});
}
void gather_attributes_to_groups(const AttributeAccessor src_attributes,
const eAttrDomain domain,
const AnonymousAttributePropagationInfo &propagation_info,
const Set<std::string> &skip,
const OffsetIndices<int> dst_offsets,
const IndexMask &src_selection,
MutableAttributeAccessor dst_attributes)
{
src_attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.domain != domain) {
return true;
}
if (id.is_anonymous() && !propagation_info.propagate(id.anonymous_id())) {
return true;
}
if (skip.contains(id.name())) {
return true;
}
const GVArraySpan src = *src_attributes.lookup(id, domain);
bke::GSpanAttributeWriter dst = dst_attributes.lookup_or_add_for_write_only_span(
id, domain, meta_data.data_type);
if (!dst) {
return true;
}
attribute_math::gather_to_groups(dst_offsets, src_selection, src, dst.span);
dst.finish();
return true;
});

View File

@ -176,4 +176,28 @@ void gather(const GVArray &src, const Span<int> map, GMutableSpan dst)
});
}
void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const GSpan src,
GMutableSpan dst)
{
attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::gather_group_to_group(
src_offsets, dst_offsets, selection, src.typed<T>(), dst.typed<T>());
});
}
void gather_to_groups(const OffsetIndices<int> dst_offsets,
const IndexMask &src_selection,
const GSpan src,
GMutableSpan dst)
{
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
array_utils::gather_to_groups(dst_offsets, src_selection, src.typed<T>(), dst.typed<T>());
});
}
} // namespace blender::bke::attribute_math

View File

@ -179,7 +179,7 @@ static void collection_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_ID(
data,
collection->runtime.owner_id,
collection->owner_id,
(IDWALK_CB_LOOPBACK | IDWALK_CB_NEVER_SELF | IDWALK_CB_READFILE_IGNORE));
LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) {
@ -225,12 +225,18 @@ static ID **collection_owner_pointer_get(ID *id)
Collection *master_collection = (Collection *)id;
BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0);
BLI_assert(master_collection->runtime.owner_id != nullptr);
BLI_assert(GS(master_collection->runtime.owner_id->name) == ID_SCE);
BLI_assert(((Scene *)master_collection->runtime.owner_id)->master_collection ==
master_collection);
BLI_assert(master_collection->owner_id != nullptr);
BLI_assert(GS(master_collection->owner_id->name) == ID_SCE);
BLI_assert(((Scene *)master_collection->owner_id)->master_collection == master_collection);
return &master_collection->runtime.owner_id;
return &master_collection->owner_id;
}
void BKE_collection_blend_write_prepare_nolib(BlendWriter * /*writer*/, Collection *collection)
{
memset(&collection->runtime, 0, sizeof(collection->runtime));
/* Clean up, important in undo case to reduce false detection of changed data-blocks. */
collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
}
void BKE_collection_blend_write_nolib(BlendWriter *writer, Collection *collection)
@ -253,9 +259,7 @@ static void collection_blend_write(BlendWriter *writer, ID *id, const void *id_a
{
Collection *collection = (Collection *)id;
memset(&collection->runtime, 0, sizeof(collection->runtime));
/* Clean up, important in undo case to reduce false detection of changed data-blocks. */
collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
BKE_collection_blend_write_prepare_nolib(writer, collection);
/* write LibData */
BLO_write_id_struct(writer, Collection, id_address, &collection->id);
@ -294,7 +298,7 @@ void BKE_collection_blend_read_data(BlendDataReader *reader, Collection *collect
memset(&collection->runtime, 0, sizeof(collection->runtime));
collection->flag &= ~COLLECTION_FLAG_ALL_RUNTIME;
collection->runtime.owner_id = owner_id;
collection->owner_id = owner_id;
BLO_read_list(reader, &collection->gobject);
BLO_read_list(reader, &collection->children);
@ -872,7 +876,7 @@ Collection *BKE_collection_master_add(Scene *scene)
Collection *master_collection = static_cast<Collection *>(
BKE_libblock_alloc(nullptr, ID_GR, BKE_SCENE_COLLECTION_NAME, LIB_ID_CREATE_NO_MAIN));
master_collection->id.flag |= LIB_EMBEDDED_DATA;
master_collection->runtime.owner_id = &scene->id;
master_collection->owner_id = &scene->id;
master_collection->flag |= COLLECTION_IS_MASTER;
master_collection->color_tag = COLLECTION_COLOR_NONE;

View File

@ -278,7 +278,7 @@ static void scene_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int
(ID *)scene_src->master_collection,
(ID **)&scene_dst->master_collection,
flag_private_id_data);
scene_dst->master_collection->runtime.owner_id = &scene_dst->id;
scene_dst->master_collection->owner_id = &scene_dst->id;
}
/* View Layers */
@ -1186,6 +1186,9 @@ static void scene_blend_write(BlendWriter *writer, ID *id, const void *id_addres
if (sce->master_collection) {
BLO_write_init_id_buffer_from_id(
temp_embedded_id_buffer, &sce->master_collection->id, BLO_write_is_undo(writer));
BKE_collection_blend_write_prepare_nolib(
writer,
reinterpret_cast<Collection *>(BLO_write_get_id_buffer_temp_id(temp_embedded_id_buffer)));
BLO_write_struct_at_address(writer,
Collection,
sce->master_collection,

View File

@ -165,6 +165,29 @@ inline void gather(const VArray<T> &src,
});
}
template<typename T>
inline void gather_group_to_group(const OffsetIndices<int> src_offsets,
const OffsetIndices<int> dst_offsets,
const IndexMask &selection,
const Span<T> src,
MutableSpan<T> dst)
{
selection.foreach_index(GrainSize(512), [&](const int64_t src_i, const int64_t dst_i) {
dst.slice(dst_offsets[dst_i]).copy_from(src.slice(src_offsets[src_i]));
});
}
template<typename T>
inline void gather_to_groups(const OffsetIndices<int> dst_offsets,
const IndexMask &src_selection,
const Span<T> src,
MutableSpan<T> dst)
{
src_selection.foreach_index(GrainSize(1024), [&](const int src_i, const int dst_i) {
dst.slice(dst_offsets[dst_i]).fill(src[src_i]);
});
}
/**
* Copy the \a src data from the groups defined by \a src_offsets to the groups in \a dst defined
* by \a dst_offsets. Groups to use are masked by \a selection, and it is assumed that the

View File

@ -85,7 +85,7 @@ template<typename T> class OffsetIndices {
*/
OffsetIndices slice(const IndexRange range) const
{
BLI_assert(offsets_.index_range().drop_back(1).contains(range.last()));
BLI_assert(range.is_empty() || offsets_.index_range().drop_back(1).contains(range.last()));
return OffsetIndices(offsets_.slice(range.start(), range.size() + 1));
}

View File

@ -1912,18 +1912,18 @@ static void after_liblink_id_embedded_id_process(BlendLibReader *reader, ID *id)
if (scene->master_collection != nullptr) {
after_liblink_id_process(reader, &scene->master_collection->id);
if (scene->master_collection->runtime.owner_id == nullptr) {
if (scene->master_collection->owner_id == nullptr) {
CLOG_WARN(&LOG,
"NULL owner_id pointer for embedded Scene Collection of %s, should never happen",
id->name);
scene->master_collection->runtime.owner_id = id;
scene->master_collection->owner_id = id;
}
else if (scene->master_collection->runtime.owner_id != id) {
else if (scene->master_collection->owner_id != id) {
CLOG_WARN(&LOG,
"Inconsistent owner_id pointer for embedded Scene Collection of %s, should "
"never happen",
id->name);
scene->master_collection->runtime.owner_id = id;
scene->master_collection->owner_id = id;
}
}
}

View File

@ -89,8 +89,24 @@ void Camera::sync()
CameraData &data = data_;
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
float2 resolution = float2(inst_.film.display_extent_get());
float2 overscan_margin = float2(overscan_ * math::max(UNPACK2(resolution)));
float2 overscan_resolution = resolution + overscan_margin * 2.0f;
float2 camera_min = overscan_margin;
float2 camera_max = camera_min + resolution;
if (inst_.drw_view) {
/* Viewport camera view. */
float2 camera_uv_scale = float2(inst_.rv3d->viewcamtexcofac);
float2 camera_uv_bias = float2(inst_.rv3d->viewcamtexcofac + 2);
float2 camera_region_min = (-camera_uv_bias * resolution) / camera_uv_scale;
float2 camera_region_size = resolution / camera_uv_scale;
camera_min = overscan_margin + camera_region_min;
camera_max = camera_min + camera_region_size;
}
data.uv_scale = overscan_resolution / (camera_max - camera_min);
data.uv_bias = -camera_min / (camera_max - camera_min);
if (inst_.is_baking()) {
/* Any view so that shadows and light culling works during irradiance bake. */
@ -106,6 +122,8 @@ void Camera::sync()
data.fisheye_fov = data.fisheye_lens = -1.0f;
data.equirect_bias = float2(0.0f);
data.equirect_scale = float2(0.0f);
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
}
else if (inst_.drw_view) {
DRW_view_viewmat_get(inst_.drw_view, data.viewmat.ptr(), false);
@ -129,9 +147,6 @@ void Camera::sync()
RE_GetWindowMatrixWithOverscan(
is_ortho, clip_start, clip_end, viewplane, overscan_, data.winmat.ptr());
}
/* TODO(fclem): Derive from rv3d instead. */
data.uv_scale = float2(1.0f);
data.uv_bias = float2(0.0f);
}
else if (inst_.render) {
RE_GetCameraModelMatrix(inst_.render->re, camera_eval, data.viewinv.ptr());

View File

@ -295,11 +295,13 @@ void Film::init(const int2 &extent, const rcti *output_rect)
EEVEE_RENDER_PASS_ENVIRONMENT |
EEVEE_RENDER_PASS_MIST |
EEVEE_RENDER_PASS_SHADOW | EEVEE_RENDER_PASS_AO;
const eViewLayerEEVEEPassType color_passes_3 = EEVEE_RENDER_PASS_TRANSPARENT;
data_.exposure_scale = pow2f(scene.view_settings.exposure);
data_.has_data = (enabled_passes_ & data_passes) != 0;
data_.any_render_pass_1 = (enabled_passes_ & color_passes_1) != 0;
data_.any_render_pass_2 = (enabled_passes_ & color_passes_2) != 0;
data_.any_render_pass_3 = (enabled_passes_ & color_passes_3) != 0;
}
{
/* Set pass offsets. */
@ -341,6 +343,7 @@ void Film::init(const int2 &extent, const rcti *output_rect)
data_.environment_id = pass_index_get(EEVEE_RENDER_PASS_ENVIRONMENT);
data_.shadow_id = pass_index_get(EEVEE_RENDER_PASS_SHADOW);
data_.ambient_occlusion_id = pass_index_get(EEVEE_RENDER_PASS_AO);
data_.transparent_id = pass_index_get(EEVEE_RENDER_PASS_TRANSPARENT);
data_.aov_color_id = data_.color_len;
data_.aov_value_id = data_.value_len;
@ -629,7 +632,7 @@ void Film::update_sample_table()
}
}
void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
void Film::accumulate(View &view, GPUTexture *combined_final_tx)
{
if (inst_.is_viewport()) {
DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get();
@ -650,9 +653,7 @@ void Film::accumulate(const DRWView *view, GPUTexture *combined_final_tx)
data_.display_only = false;
inst_.push_uniform_data();
draw::View drw_view("MainView", view);
inst_.manager->submit(accumulate_ps_, drw_view);
inst_.manager->submit(accumulate_ps_, view);
combined_tx_.swap();
weight_tx_.swap();

View File

@ -90,7 +90,7 @@ class Film {
void end_sync();
/** Accumulate the newly rendered sample contained in #RenderBuffers and blit to display. */
void accumulate(const DRWView *view, GPUTexture *combined_final_tx);
void accumulate(View &view, GPUTexture *combined_final_tx);
/** Sort and normalize cryptomatte samples. */
void cryptomatte_sort();
@ -180,6 +180,8 @@ class Film {
return data_.shadow_id;
case EEVEE_RENDER_PASS_AO:
return data_.ambient_occlusion_id;
case EEVEE_RENDER_PASS_TRANSPARENT:
return data_.transparent_id;
case EEVEE_RENDER_PASS_CRYPTOMATTE_OBJECT:
return data_.cryptomatte_object_id;
case EEVEE_RENDER_PASS_CRYPTOMATTE_ASSET:

View File

@ -190,11 +190,8 @@ MaterialPass MaterialModule::material_pass_get(Object *ob,
break;
case GPU_MAT_FAILED:
default:
matpass.gpumat = inst_.shaders.material_shader_get(error_mat_,
error_mat_->nodetree,
pipeline_type,
geometry_type,
false);
matpass.gpumat = inst_.shaders.material_shader_get(
error_mat_, error_mat_->nodetree, pipeline_type, geometry_type, false);
break;
}
/* Returned material should be ready to be drawn. */

View File

@ -371,7 +371,7 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob,
::Material *blender_mat,
GPUMaterial *gpumat)
{
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_LESS_EQUAL;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL;
if (blender_mat->blend_flag & MA_BL_CULL_BACKFACE) {
state |= DRW_STATE_CULL_BACK;
}
@ -382,24 +382,14 @@ PassMain::Sub *ForwardPipeline::material_transparent_add(const Object *ob,
return pass;
}
void ForwardPipeline::render(View &view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
GPUTexture * /*combined_tx*/)
void ForwardPipeline::render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb)
{
DRW_stats_group_start("Forward.Opaque");
prepass_fb.bind();
inst_.manager->submit(prepass_ps_, view);
// if (!DRW_pass_is_empty(prepass_ps_)) {
inst_.hiz_buffer.set_dirty();
// }
// if (inst_.raytracing.enabled()) {
// rt_buffer.radiance_copy(combined_tx);
// inst_.hiz_buffer.update();
// }
inst_.shadows.set_view(view);
inst_.irradiance_cache.set_view(view);
@ -413,10 +403,6 @@ void ForwardPipeline::render(View &view,
combined_fb.bind();
inst_.manager->submit(transparent_ps_, view);
// if (inst_.raytracing.enabled()) {
// gbuffer.ray_radiance_tx.release();
// }
}
/** \} */
@ -483,8 +469,8 @@ void DeferredLayer::begin_sync()
inst_.cryptomatte.bind_resources(gbuffer_ps_);
}
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL |
DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL |
DRW_STATE_STENCIL_ALWAYS;
gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided");
gbuffer_double_sided_ps_->state_set(state);
@ -1032,8 +1018,8 @@ void DeferredProbeLayer::begin_sync()
inst_.cryptomatte.bind_resources(gbuffer_ps_);
}
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL |
DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL |
DRW_STATE_STENCIL_ALWAYS;
gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided");
gbuffer_double_sided_ps_->state_set(state);
@ -1191,7 +1177,7 @@ void PlanarProbePipeline::begin_sync()
gbuffer_ps_.bind_image(RBUFS_VALUE_SLOT, &inst_.render_buffers.rp_value_tx);
inst_.cryptomatte.bind_resources(gbuffer_ps_);
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM | DRW_STATE_DEPTH_EQUAL;
DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL;
gbuffer_double_sided_ps_ = &gbuffer_ps_.sub("DoubleSided");
gbuffer_double_sided_ps_->state_set(state);

View File

@ -148,8 +148,6 @@ class ForwardPipeline {
PassSortable transparent_ps_ = {"Forward.Transparent"};
float3 camera_forward_;
// GPUTexture *input_screen_radiance_tx_ = nullptr;
public:
ForwardPipeline(Instance &inst) : inst_(inst){};
@ -165,10 +163,7 @@ class ForwardPipeline {
::Material *blender_mat,
GPUMaterial *gpumat);
void render(View &view,
Framebuffer &prepass_fb,
Framebuffer &combined_fb,
GPUTexture *combined_tx);
void render(View &view, Framebuffer &prepass_fb, Framebuffer &combined_fb);
};
/** \} */

View File

@ -50,6 +50,7 @@ void RenderBuffers::sync()
data.environment_id = pass_index_get(EEVEE_RENDER_PASS_ENVIRONMENT);
data.shadow_id = pass_index_get(EEVEE_RENDER_PASS_SHADOW);
data.ambient_occlusion_id = pass_index_get(EEVEE_RENDER_PASS_AO);
data.transparent_id = pass_index_get(EEVEE_RENDER_PASS_TRANSPARENT);
data.aovs = inst_.film.aovs_info;
}

View File

@ -268,9 +268,9 @@ struct FilmData {
/** Is true if accumulation of filtered passes is needed. */
bool1 any_render_pass_1;
bool1 any_render_pass_2;
bool1 any_render_pass_3;
/** Controlled by user in lookdev mode or by render settings. */
float background_opacity;
float _pad0, _pad1;
/** Output counts per type. */
int color_len, value_len;
/** Index in color_accum_img or value_accum_img of each pass. -1 if pass is not enabled. */
@ -287,6 +287,7 @@ struct FilmData {
int environment_id;
int shadow_id;
int ambient_occlusion_id;
int transparent_id;
/** Not indexed but still not -1 if enabled. */
int depth_id;
int combined_id;
@ -376,11 +377,12 @@ struct RenderBuffersInfoData {
int volume_light_id;
int emission_id;
int environment_id;
int transparent_id;
/* Value */
int value_len;
int shadow_id;
int ambient_occlusion_id;
int _pad0, _pad1, _pad2;
int _pad0, _pad1;
};
BLI_STATIC_ASSERT_ALIGN(RenderBuffersInfoData, 16)

View File

@ -28,11 +28,7 @@ namespace blender::eevee {
/** \name ShadingView
* \{ */
void ShadingView::init()
{
// dof_.init();
// mb_.init();
}
void ShadingView::init() {}
void ShadingView::sync()
{
@ -59,31 +55,21 @@ void ShadingView::sync()
const CameraData &cam = inst_.camera.data_get();
float4x4 viewmat, winmat;
const float(*viewmat_p)[4] = viewmat.ptr(), (*winmat_p)[4] = winmat.ptr();
if (false /* inst_.camera.is_panoramic() */) {
/* TODO(@fclem) Over-scans. */
/* For now a mandatory 5% over-scan for DoF. */
float side = cam.clip_near * 1.05f;
float near = cam.clip_near;
float far = cam.clip_far;
perspective_m4(winmat.ptr(), -side, side, -side, side, near, far);
winmat = math::projection::perspective(-side, side, -side, side, near, far);
viewmat = face_matrix_ * cam.viewmat;
}
else {
viewmat_p = cam.viewmat.ptr();
winmat_p = cam.winmat.ptr();
viewmat = cam.viewmat;
winmat = cam.winmat;
}
main_view_ = DRW_view_create(viewmat_p, winmat_p, nullptr, nullptr, nullptr);
sub_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p);
render_view_ = DRW_view_create_sub(main_view_, viewmat_p, winmat_p);
// dof_.sync(winmat_p, extent_);
// rt_buffer_opaque_.sync(extent_);
// rt_buffer_refract_.sync(extent_);
// inst_.hiz_back.view_sync(extent_);
// inst_.hiz_front.view_sync(extent_);
// inst_.gbuffer.view_sync(extent_);
main_view_.sync(viewmat, winmat);
}
void ShadingView::render()
@ -103,9 +89,8 @@ void ShadingView::render()
update_view();
DRW_stats_group_start(name_);
DRW_view_set_active(render_view_);
inst_.planar_probes.set_view(render_view_new_, extent_);
inst_.planar_probes.set_view(render_view_, extent_);
/* If camera has any motion, compute motion vector in the film pass. Otherwise, we avoid float
* precision issue by setting the motion of all static geometry to 0. */
@ -121,42 +106,42 @@ void ShadingView::render()
inst_.hiz_buffer.set_source(&inst_.render_buffers.depth_tx);
inst_.hiz_buffer.set_dirty();
inst_.pipelines.background.render(render_view_new_);
inst_.pipelines.background.render(render_view_);
/* TODO(fclem): Move it after the first prepass (and hiz update) once pipeline is stabilized. */
inst_.lights.set_view(render_view_new_, extent_);
inst_.reflection_probes.set_view(render_view_new_);
inst_.lights.set_view(render_view_, extent_);
inst_.reflection_probes.set_view(render_view_);
inst_.volume.draw_prepass(render_view_new_);
inst_.volume.draw_prepass(render_view_);
/* TODO: cleanup. */
View main_view_new("MainView", main_view_);
/* TODO(Miguel Pozo): Deferred and forward prepass should happen before the GBuffer pass. */
inst_.pipelines.deferred.render(main_view_new,
render_view_new_,
inst_.pipelines.deferred.render(main_view_,
render_view_,
prepass_fb_,
combined_fb_,
extent_,
rt_buffer_opaque_,
rt_buffer_refract_);
inst_.volume.draw_compute(render_view_new_);
inst_.volume.draw_compute(render_view_);
// inst_.lookdev.render_overlay(view_fb_);
inst_.pipelines.forward.render(render_view_new_, prepass_fb_, combined_fb_, rbufs.combined_tx);
inst_.pipelines.forward.render(render_view_, prepass_fb_, combined_fb_);
inst_.lights.debug_draw(render_view_new_, combined_fb_);
inst_.hiz_buffer.debug_draw(render_view_new_, combined_fb_);
inst_.shadows.debug_draw(render_view_new_, combined_fb_);
inst_.irradiance_cache.viewport_draw(render_view_new_, combined_fb_);
inst_.reflection_probes.viewport_draw(render_view_new_, combined_fb_);
inst_.planar_probes.viewport_draw(render_view_new_, combined_fb_);
render_transparent_pass(rbufs);
inst_.ambient_occlusion.render_pass(render_view_new_);
inst_.lights.debug_draw(render_view_, combined_fb_);
inst_.hiz_buffer.debug_draw(render_view_, combined_fb_);
inst_.shadows.debug_draw(render_view_, combined_fb_);
inst_.irradiance_cache.viewport_draw(render_view_, combined_fb_);
inst_.reflection_probes.viewport_draw(render_view_, combined_fb_);
inst_.planar_probes.viewport_draw(render_view_, combined_fb_);
inst_.ambient_occlusion.render_pass(render_view_);
GPUTexture *combined_final_tx = render_postfx(rbufs.combined_tx);
inst_.film.accumulate(sub_view_, combined_final_tx);
inst_.film.accumulate(jitter_view_, combined_final_tx);
rbufs.release();
postfx_tx_.release();
@ -164,6 +149,20 @@ void ShadingView::render()
DRW_stats_group_end();
}
void ShadingView::render_transparent_pass(RenderBuffers &rbufs)
{
if (rbufs.data.transparent_id != -1) {
transparent_fb_.ensure(
GPU_ATTACHMENT_TEXTURE(rbufs.depth_tx),
GPU_ATTACHMENT_TEXTURE_LAYER(rbufs.rp_color_tx, rbufs.data.transparent_id));
/* Alpha stores transmittance. So start at 1. */
float4 clear_color = {0.0f, 0.0f, 0.0f, 1.0f};
GPU_framebuffer_bind(transparent_fb_);
GPU_framebuffer_clear_color(transparent_fb_, clear_color);
inst_.pipelines.forward.render(render_view_, prepass_fb_, transparent_fb_);
}
}
GPUTexture *ShadingView::render_postfx(GPUTexture *input_tx)
{
if (!inst_.depth_of_field.postfx_enabled() && !inst_.motion_blur.postfx_enabled()) {
@ -174,17 +173,16 @@ GPUTexture *ShadingView::render_postfx(GPUTexture *input_tx)
GPUTexture *output_tx = postfx_tx_;
/* Swapping is done internally. Actual output is set to the next input. */
inst_.depth_of_field.render(render_view_new_, &input_tx, &output_tx, dof_buffer_);
inst_.motion_blur.render(render_view_new_, &input_tx, &output_tx);
inst_.depth_of_field.render(render_view_, &input_tx, &output_tx, dof_buffer_);
inst_.motion_blur.render(render_view_, &input_tx, &output_tx);
return input_tx;
}
void ShadingView::update_view()
{
float4x4 viewmat, winmat;
DRW_view_viewmat_get(main_view_, viewmat.ptr(), false);
DRW_view_winmat_get(main_view_, winmat.ptr(), false);
float4x4 viewmat = main_view_.viewmat();
float4x4 winmat = main_view_.winmat();
/* TODO(fclem): Mixed-resolution rendering: We need to make sure we render with exactly the same
* distances between pixels to line up render samples and target pixels.
@ -197,14 +195,12 @@ void ShadingView::update_view()
jitter *= 2.0f;
window_translate_m4(winmat.ptr(), winmat.ptr(), UNPACK2(jitter));
DRW_view_update_sub(sub_view_, viewmat.ptr(), winmat.ptr());
jitter_view_.sync(winmat, winmat);
/* FIXME(fclem): The offset may be noticeably large and the culling might make object pop
* out of the blurring radius. To fix this, use custom enlarged culling matrix. */
inst_.depth_of_field.jitter_apply(winmat, viewmat);
DRW_view_update_sub(render_view_, viewmat.ptr(), winmat.ptr());
render_view_new_.sync(viewmat, winmat);
render_view_.sync(viewmat, winmat);
}
/** \} */

View File

@ -48,16 +48,16 @@ class ShadingView {
Framebuffer prepass_fb_;
Framebuffer combined_fb_;
Framebuffer transparent_fb_ = {"transparent"};
TextureFromPool postfx_tx_;
/** Main views is created from the camera (or is from the viewport). It is not jittered. */
DRWView *main_view_ = nullptr;
View main_view_ = {"main_view"};
/** Sub views is jittered versions or the main views. This allows jitter updates without trashing
* the visibility culling cache. */
DRWView *sub_view_ = nullptr;
/** Same as sub_view_ but has Depth Of Field jitter applied. */
DRWView *render_view_ = nullptr;
View render_view_new_;
View jitter_view_ = {"jitter_view"};
/** Same as jitter_view_ but has Depth Of Field jitter applied. */
View render_view_;
/** Render size of the view. Can change between scene sample eval. */
int2 extent_ = {-1, -1};
@ -66,7 +66,7 @@ class ShadingView {
public:
ShadingView(Instance &inst, const char *name, const float4x4 &face_matrix)
: inst_(inst), name_(name), face_matrix_(face_matrix), render_view_new_(name){};
: inst_(inst), name_(name), face_matrix_(face_matrix), render_view_(name){};
~ShadingView(){};
@ -76,9 +76,11 @@ class ShadingView {
void render();
private:
void render_transparent_pass(RenderBuffers &rbufs);
GPUTexture *render_postfx(GPUTexture *input_tx);
private:
void update_view();
};

View File

@ -4,7 +4,12 @@
#pragma BLENDER_REQUIRE(draw_model_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_vector_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_math_matrix_lib.glsl)
#pragma BLENDER_REQUIRE(gpu_shader_codegen_lib.glsl)
/* MAT_GEOM_POINT_CLOUD */
#pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
/* MAT_GEOM_CURVES */
#pragma BLENDER_REQUIRE(common_hair_lib.glsl) /* TODO rename to curve. */
#define EEVEE_ATTRIBUTE_LIB
@ -71,8 +76,6 @@ vec3 attr_load_uv(vec3 attr)
* Point Cloud objects loads attributes from buffers through sampler buffers.
* \{ */
# pragma BLENDER_REQUIRE(common_pointcloud_lib.glsl)
# ifdef OBINFO_LIB
vec3 attr_load_orco(vec4 orco)
{
@ -163,7 +166,7 @@ float attr_load_float(float attr)
/** \} */
#elif defined(MAT_GEOM_CURVES)
#elif defined(MAT_GEOM_CURVES) && defined(GPU_VERTEX_SHADER)
/* -------------------------------------------------------------------- */
/** \name Curve

View File

@ -759,6 +759,23 @@ void film_process_data(ivec2 texel_film, out vec4 out_color, out float out_depth
film_store_value(dst, uniform_buf.film.mist_id, mist_accum, out_color);
}
if (uniform_buf.film.any_render_pass_3) {
vec4 transparent_accum = vec4(0.0);
for (int i = 0; i < uniform_buf.film.samples_len; i++) {
FilmSample src = film_sample_get(i, texel_film);
film_sample_accum(src,
uniform_buf.film.transparent_id,
uniform_buf.render_pass.transparent_id,
rp_color_tx,
transparent_accum);
}
/* Alpha stores transmittance for transparent pass. */
transparent_accum.a = weight_accum - transparent_accum.a;
film_store_color(dst, uniform_buf.film.transparent_id, transparent_accum, out_color);
}
for (int aov = 0; aov < uniform_buf.film.aov_color_len; aov++) {
vec4 aov_accum = vec4(0.0);

View File

@ -207,9 +207,8 @@ void horizon_scan_context_slice_finish(inout HorizonScanContext context)
{
#ifdef HORIZON_OCCLUSION
float occlusion = horizon_scan_bitmask_to_occlusion_cosine(context.occlusion_common.bitmask);
/* Replace light by occlusion. Should eliminate any reference to the radiance texture fetch */
context.occlusion_common.light_slice = vec3(occlusion);
horizon_scan_context_slice_finish(context.occlusion_common);
context.occlusion_common.light_accum += vec4(occlusion) * context.occlusion_common.N_length;
context.occlusion_common.weight_accum += context.occlusion_common.N_length;
#endif
#ifdef HORIZON_DIFFUSE
horizon_scan_context_slice_finish(context.diffuse_common);

View File

@ -84,7 +84,7 @@ CullingTile tile_culling_get(uvec2 tile_co)
tile.bounds = (is_persp) ? tile_bound_cone(corners[0], corners[4], corners[7], corners[3]) :
tile_bound_cylinder(corners[0], corners[4], corners[7], corners[3]);
tile.frustum = isect_data_setup(shape_frustum(corners));
tile.frustum = isect_frustum_setup(shape_frustum(corners));
return tile;
}

View File

@ -27,10 +27,10 @@ void main()
return;
}
IsectBox box = isect_data_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
IsectBox box = isect_box_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
vec3 local_min = vec3(FLT_MAX);
vec3 local_max = vec3(-FLT_MAX);

View File

@ -507,7 +507,7 @@ vec3 coordinate_camera(vec3 P)
vP = P;
}
else {
#ifdef MAT_WORLD
#ifdef MAT_GEOM_WORLD
vP = drw_normal_world_to_view(P);
#else
vP = drw_point_world_to_view(P);
@ -525,8 +525,12 @@ vec3 coordinate_screen(vec3 P)
window.xy = vec2(0.5);
}
else {
#ifdef MAT_GEOM_WORLD
window.xy = drw_point_view_to_screen(interp.P).xy;
#else
/* TODO(fclem): Actual camera transform. */
window.xy = drw_point_world_to_screen(P).xy;
#endif
window.xy = window.xy * uniform_buf.camera.uv_scale + uniform_buf.camera.uv_bias;
}
return window;
@ -534,7 +538,7 @@ vec3 coordinate_screen(vec3 P)
vec3 coordinate_reflect(vec3 P, vec3 N)
{
#ifdef MAT_WORLD
#ifdef MAT_GEOM_WORLD
return N;
#else
return -reflect(drw_world_incident_vector(P), N);
@ -543,7 +547,7 @@ vec3 coordinate_reflect(vec3 P, vec3 N)
vec3 coordinate_incoming(vec3 P)
{
#ifdef MAT_WORLD
#ifdef MAT_GEOM_WORLD
return -P;
#else
return drw_world_incident_vector(P);

View File

@ -32,16 +32,16 @@ void main()
IsectPyramid frustum;
if (tilemap.projection_type == SHADOW_PROJECTION_CUBEFACE) {
Pyramid pyramid = shadow_tilemap_cubeface_bounds(tilemap, ivec2(0), ivec2(SHADOW_TILEMAP_RES));
frustum = isect_data_setup(pyramid);
frustum = isect_pyramid_setup(pyramid);
}
uint resource_id = resource_ids_buf[gl_GlobalInvocationID.x];
resource_id = (resource_id & 0x7FFFFFFFu);
IsectBox box = isect_data_setup(bounds_buf[resource_id].bounding_corners[0].xyz,
bounds_buf[resource_id].bounding_corners[1].xyz,
bounds_buf[resource_id].bounding_corners[2].xyz,
bounds_buf[resource_id].bounding_corners[3].xyz);
IsectBox box = isect_box_setup(bounds_buf[resource_id].bounding_corners[0].xyz,
bounds_buf[resource_id].bounding_corners[1].xyz,
bounds_buf[resource_id].bounding_corners[2].xyz,
bounds_buf[resource_id].bounding_corners[3].xyz);
int clipped = 0;
/* NDC space post projection [-1..1] (unclamped). */

View File

@ -30,14 +30,14 @@ void main()
resource_id = (resource_id & 0x7FFFFFFFu);
ObjectBounds bounds = bounds_buf[resource_id];
box = isect_data_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
box = isect_box_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
}
else {
/* Create a dummy box so initialization happens even when there are no shadow casters. */
box = isect_data_setup(
box = isect_box_setup(
vec3(-1.0), vec3(1.0, 0.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(0.0, 0.0, 1.0));
}

View File

@ -33,7 +33,6 @@
#pragma BLENDER_REQUIRE(eevee_sampling_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_velocity_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_volume_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_occupancy_lib.glsl)

View File

@ -12,7 +12,6 @@
*/
#pragma BLENDER_REQUIRE(draw_view_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_attributes_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_surf_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_nodetree_lib.glsl)
#pragma BLENDER_REQUIRE(eevee_transparency_lib.glsl)

View File

@ -77,10 +77,10 @@ void main()
}
ObjectBounds bounds = bounds_buf[gl_GlobalInvocationID.x];
IsectBox box = isect_data_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
IsectBox box = isect_box_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
#ifdef DYNAMIC_PASS_SELECTION
if (is_visible(box)) {

View File

@ -26,7 +26,7 @@ struct IsectPyramid {
vec4 planes[5];
};
IsectPyramid isect_data_setup(Pyramid shape)
IsectPyramid isect_pyramid_setup(Pyramid shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A2 = shape.corners[2] - shape.corners[0];
@ -52,7 +52,7 @@ struct IsectBox {
vec4 planes[6];
};
IsectBox isect_data_setup(Box shape)
IsectBox isect_box_setup(Box shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A3 = shape.corners[3] - shape.corners[0];
@ -73,7 +73,7 @@ IsectBox isect_data_setup(Box shape)
}
/* Construct box from 1 corner point + 3 side vectors. */
IsectBox isect_data_setup(vec3 origin, vec3 side_x, vec3 side_y, vec3 side_z)
IsectBox isect_box_setup(vec3 origin, vec3 side_x, vec3 side_y, vec3 side_z)
{
IsectBox data;
data.corners[0] = origin;
@ -101,7 +101,7 @@ struct IsectFrustum {
vec4 planes[6];
};
IsectFrustum isect_data_setup(Frustum shape)
IsectFrustum isect_frustum_setup(Frustum shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A3 = shape.corners[3] - shape.corners[0];
@ -157,7 +157,7 @@ bool intersect_view(Pyramid pyramid)
}
/* Now do Frustum vertices vs Pyramid planes. */
IsectPyramid i_pyramid = isect_data_setup(pyramid);
IsectPyramid i_pyramid = isect_pyramid_setup(pyramid);
for (int p = 0; p < 5; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -203,7 +203,7 @@ bool intersect_view(Box box)
}
/* Now do Frustum vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -317,7 +317,7 @@ bool intersect(IsectPyramid i_pyramid, Box box)
}
/* Now do Pyramid vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 5; ++v) {
@ -406,7 +406,7 @@ bool intersect(IsectFrustum i_frustum, Pyramid pyramid)
}
/* Now do Frustum vertices vs Pyramid planes. */
IsectPyramid i_pyramid = isect_data_setup(pyramid);
IsectPyramid i_pyramid = isect_pyramid_setup(pyramid);
for (int p = 0; p < 5; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -451,7 +451,7 @@ bool intersect(IsectFrustum i_frustum, Box box)
}
/* Now do Frustum vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {

View File

@ -27,7 +27,7 @@ struct IsectPyramid {
vec4 planes[5];
};
IsectPyramid isect_data_setup(Pyramid shape)
IsectPyramid isect_pyramid_setup(Pyramid shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A2 = shape.corners[2] - shape.corners[0];
@ -53,7 +53,7 @@ struct IsectBox {
vec4 planes[6];
};
IsectBox isect_data_setup(Box shape)
IsectBox isect_box_setup(Box shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A3 = shape.corners[3] - shape.corners[0];
@ -74,7 +74,7 @@ IsectBox isect_data_setup(Box shape)
}
/* Construct box from 1 corner point + 3 side vectors. */
IsectBox isect_data_setup(vec3 origin, vec3 side_x, vec3 side_y, vec3 side_z)
IsectBox isect_box_setup(vec3 origin, vec3 side_x, vec3 side_y, vec3 side_z)
{
IsectBox data;
data.corners[0] = origin;
@ -102,7 +102,7 @@ struct IsectFrustum {
vec4 planes[6];
};
IsectFrustum isect_data_setup(Frustum shape)
IsectFrustum isect_frustum_setup(Frustum shape)
{
vec3 A1 = shape.corners[1] - shape.corners[0];
vec3 A3 = shape.corners[3] - shape.corners[0];
@ -158,7 +158,7 @@ bool intersect_view(Pyramid pyramid)
}
/* Now do Frustum vertices vs Pyramid planes. */
IsectPyramid i_pyramid = isect_data_setup(pyramid);
IsectPyramid i_pyramid = isect_pyramid_setup(pyramid);
for (int p = 0; p < 5; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -204,7 +204,7 @@ bool intersect_view(Box box)
}
/* Now do Frustum vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -318,7 +318,7 @@ bool intersect(IsectPyramid i_pyramid, Box box)
}
/* Now do Pyramid vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 5; ++v) {
@ -407,7 +407,7 @@ bool intersect(IsectFrustum i_frustum, Pyramid pyramid)
}
/* Now do Frustum vertices vs Pyramid planes. */
IsectPyramid i_pyramid = isect_data_setup(pyramid);
IsectPyramid i_pyramid = isect_pyramid_setup(pyramid);
for (int p = 0; p < 5; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {
@ -452,7 +452,7 @@ bool intersect(IsectFrustum i_frustum, Box box)
}
/* Now do Frustum vertices vs Box planes. */
IsectBox i_box = isect_data_setup(box);
IsectBox i_box = isect_box_setup(box);
for (int p = 0; p < 6; ++p) {
bool is_any_vertex_on_positive_side = false;
for (int v = 0; v < 8; ++v) {

View File

@ -33,10 +33,10 @@ void main()
ObjectBounds bounds = bounds_buf[gl_GlobalInvocationID.x];
if (bounds.bounding_sphere.w != -1.0) {
IsectBox box = isect_data_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
IsectBox box = isect_box_setup(bounds.bounding_corners[0].xyz,
bounds.bounding_corners[1].xyz,
bounds.bounding_corners[2].xyz,
bounds.bounding_corners[3].xyz);
Sphere bounding_sphere = shape_sphere(bounds.bounding_sphere.xyz, bounds.bounding_sphere.w);
Sphere inscribed_sphere = shape_sphere(bounds.bounding_sphere.xyz,
bounds._inner_sphere_radius);

View File

@ -1133,7 +1133,7 @@ static void acf_nla_controls_name(bAnimListElem * /*ale*/, char *name)
BLI_strncpy_utf8(name, IFACE_("NLA Strip Controls"), ANIM_CHAN_NAME_SIZE);
}
/* check if some setting exists for this channel */
/* check if some setting exists for this track */
static bool acf_nla_controls_setting_valid(bAnimContext * /*ac*/,
bAnimListElem * /*ale*/,
eAnimChannel_Settings setting)
@ -1189,7 +1189,7 @@ static int acf_nla_controls_icon(bAnimListElem * /*ale*/)
/** NLA Control F-Curves expander type define. */
static bAnimChannelType ACF_NLACONTROLS = {
/*channel_type_name*/ "NLA Controls Expander",
/*channel_role*/ ACHANNEL_ROLE_EXPANDER,
/*track_role*/ ACHANNEL_ROLE_EXPANDER,
/*get_backdrop_color*/ acf_nla_controls_color,
/*get_channel_color*/ nullptr,
@ -4080,7 +4080,7 @@ static int acf_nlaaction_icon(bAnimListElem *ale)
return ICON_ACTION;
}
/* Backdrop color for nla action channel
/* Backdrop color for nla action track
* Although this can't be used directly for NLA Action drawing,
* it is still needed for use behind the RHS toggles
*/
@ -4090,19 +4090,19 @@ static void acf_nlaaction_color(bAnimContext * /*ac*/, bAnimListElem *ale, float
/* Action Line
* The alpha values action_get_color returns are only useful for drawing
* strips backgrounds but here we're doing channel list backgrounds instead
* strips backgrounds but here we're doing track list backgrounds instead
* so we ignore that and use our own when needed
*/
nla_action_get_color(ale->adt, (bAction *)ale->data, color);
/* NOTE: since the return types only allow rgb, we cannot do the alpha-blending we'd
* like for the solo-drawing case. Hence, this method isn't actually used for drawing
* most of the channel...
* most of the track...
*/
copy_v3_v3(r_color, color);
}
/* backdrop for nla action channel */
/* backdrop for nla action track */
static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float yminc, float ymaxc)
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@ -4113,7 +4113,7 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
/* Action Line
* The alpha values action_get_color returns are only useful for drawing
* strips backgrounds but here we're doing channel list backgrounds instead
* strips backgrounds but here we're doing track list backgrounds instead
* so we ignore that and use our own when needed
*/
nla_action_get_color(adt, (bAction *)ale->data, color);
@ -4125,19 +4125,19 @@ static void acf_nlaaction_backdrop(bAnimContext *ac, bAnimListElem *ale, float y
color[3] = (adt && (adt->flag & ADT_NLA_SOLO_TRACK)) ? 0.3f : 1.0f;
}
/* only on top left corner, to show that this channel sits on top of the preceding ones
/* only on top left corner, to show that this track sits on top of the preceding ones
* while still linking into the action line strip to the right
*/
UI_draw_roundbox_corner_set(UI_CNR_TOP_LEFT);
/* draw slightly shifted up vertically to look like it has more separation from other channels,
/* draw slightly shifted up vertically to look like it has more separation from other tracks,
* but we then need to slightly shorten it so that it doesn't look like it overlaps
*/
rctf box;
box.xmin = offset;
box.xmax = float(v2d->cur.xmax);
box.ymin = yminc + NLACHANNEL_SKIP;
box.ymax = ymaxc + NLACHANNEL_SKIP - 1;
box.ymin = yminc + NLATRACK_SKIP;
box.ymax = ymaxc + NLATRACK_SKIP - 1;
UI_draw_roundbox_4fv(&box, true, 8, color);
}
@ -4170,7 +4170,7 @@ static bool acf_nlaaction_name_prop(bAnimListElem *ale, PointerRNA *r_ptr, Prope
return false;
}
/* check if some setting exists for this channel */
/* check if some setting exists for this track */
static bool acf_nlaaction_setting_valid(bAnimContext * /*ac*/,
bAnimListElem *ale,
eAnimChannel_Settings setting)
@ -4853,9 +4853,9 @@ void ANIM_channel_draw(
/* NOTE: technically, NLA Action "pushdown" should be here too,
* but there are no sliders there. */
/* NLA action channels have slightly different spacing requirements... */
/* NLA action tracks have slightly different spacing requirements... */
if (ale->type == ANIMTYPE_NLAACTION) {
ymin_ofs = NLACHANNEL_SKIP;
ymin_ofs = NLATRACK_SKIP;
}
}

View File

@ -1340,7 +1340,7 @@ static bool rearrange_animchannel_islands(ListBase *list,
* ! NLA tracks are displayed in opposite order, so directions need care
* mode: REARRANGE_ANIMCHAN_*
*/
static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
static void rearrange_nla_tracks(bAnimContext *ac, AnimData *adt, eRearrangeAnimChan_Mode mode)
{
AnimChanRearrangeFp rearrange_func;
ListBase anim_data_visible = {nullptr, nullptr};
@ -1773,7 +1773,7 @@ static int animchannels_rearrange_exec(bContext *C, wmOperator *op)
switch (ac.datatype) {
case ANIMCONT_NLA: /* NLA-tracks only */
rearrange_nla_channels(&ac, adt, mode);
rearrange_nla_tracks(&ac, adt, mode);
DEG_id_tag_update(ale->id, ID_RECALC_ANIMATION);
break;
@ -2983,7 +2983,7 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm
float ymax;
if (ac->datatype == ANIMCONT_NLA) {
ymax = NLACHANNEL_FIRST_TOP(ac);
ymax = NLATRACK_FIRST_TOP(ac);
}
else {
ymax = ANIM_UI_get_first_channel_top(v2d);
@ -2999,7 +2999,7 @@ static void box_select_anim_channels(bAnimContext *ac, rcti *rect, short selectm
}
if (ac->datatype == ANIMCONT_NLA) {
ymin = ymax - NLACHANNEL_STEP(snla);
ymin = ymax - NLATRACK_STEP(snla);
}
else {
ymin = ymax - ANIM_UI_get_channel_step();
@ -3209,10 +3209,10 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2])
if (ac->datatype == ANIMCONT_NLA) {
SpaceNla *snla = (SpaceNla *)ac->sl;
UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH,
NLACHANNEL_STEP(snla),
UI_view2d_listview_view_to_cell(NLATRACK_NAMEWIDTH,
NLATRACK_STEP(snla),
0,
NLACHANNEL_FIRST_TOP(ac),
NLATRACK_FIRST_TOP(ac),
x,
y,
nullptr,
@ -3821,7 +3821,7 @@ static int mouse_anim_channels(bContext *C,
}
/* action to take depends on what channel we've got */
/* WARNING: must keep this in sync with the equivalent function in `nla_channels.cc`. */
/* WARNING: must keep this in sync with the equivalent function in `nla_tracks.cc`. */
switch (ale->type) {
case ANIMTYPE_SCENE:
notifierFlags |= click_select_channel_scene(ale, selectmode);

View File

@ -83,7 +83,7 @@ eInsertKeyFlags ANIM_get_keyframing_flags(Scene *scene, const bool use_autokey_m
/* standard flags */
{
/* visual keying */
if (is_autokey_flag(scene, AUTOKEY_FLAG_AUTOMATKEY)) {
if (is_autokey_flag(scene, AUTOKEY_FLAG_VISUALKEY)) {
flag |= INSERTKEY_MATRIX;
}

View File

@ -699,7 +699,7 @@ KeyingSet *ANIM_get_keyingset_for_autokeying(const Scene *scene, const char *tra
return ANIM_scene_get_active_keyingset(scene);
}
if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAIL)) {
if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE)) {
return ANIM_builtin_keyingset_get_named(ANIM_KS_AVAILABLE_ID);
}

View File

@ -19,6 +19,9 @@
#include "ED_grease_pencil.hh"
#include "RNA_access.hh"
#include "RNA_define.hh"
#include "WM_api.hh"
namespace blender::ed::greasepencil {
@ -66,6 +69,193 @@ static void GREASE_PENCIL_OT_material_reveal(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Hide Others Materials Operator
* \{ */
static int grease_pencil_material_hide_exec(bContext *C, wmOperator *op)
{
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
const bool invert = RNA_boolean_get(op->ptr, "invert");
bool changed = false;
const int material_index = object->actcol - 1;
for (const int i : IndexRange(object->totcol)) {
if (invert && i == material_index) {
continue;
}
if (!invert && i != material_index) {
continue;
}
if (Material *ma = BKE_object_material_get(object, i + 1)) {
MaterialGPencilStyle &gp_style = *ma->gp_style;
gp_style.flag |= GP_MATERIAL_HIDE;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
changed = true;
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_material_hide(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Hide Materials";
ot->idname = "GREASE_PENCIL_OT_material_hide";
ot->description = "Hide active/inactive Grease Pencil material(s)";
/* Callbacks. */
ot->exec = grease_pencil_material_hide_exec;
ot->poll = active_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
RNA_def_boolean(
ot->srna, "invert", false, "Invert", "Hide inactive materials instead of the active one");
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lock All Materials Operator
* \{ */
static int grease_pencil_material_lock_all_exec(bContext *C, wmOperator * /*op*/)
{
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
bool changed = false;
for (const int i : IndexRange(object->totcol)) {
if (Material *ma = BKE_object_material_get(object, i + 1)) {
MaterialGPencilStyle &gp_style = *ma->gp_style;
gp_style.flag |= GP_MATERIAL_LOCKED;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
changed = true;
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_material_lock_all(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Lock All Materials";
ot->idname = "GREASE_PENCIL_OT_material_lock_all";
ot->description =
"Lock all Grease Pencil materials to prevent them from being accidentally modified";
/* Callbacks. */
ot->exec = grease_pencil_material_lock_all_exec;
ot->poll = active_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Unlock All Materials Operator
* \{ */
static int grease_pencil_material_unlock_all_exec(bContext *C, wmOperator * /*op*/)
{
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
bool changed = false;
for (const int i : IndexRange(object->totcol)) {
if (Material *ma = BKE_object_material_get(object, i + 1)) {
MaterialGPencilStyle &gp_style = *ma->gp_style;
gp_style.flag &= ~GP_MATERIAL_LOCKED;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
changed = true;
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_material_unlock_all(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Unclock All Materials";
ot->idname = "GREASE_PENCIL_OT_material_unlock_all";
ot->description = "Unlock all Grease Pencil materials so that they can be edited";
/* Callbacks. */
ot->exec = grease_pencil_material_unlock_all_exec;
ot->poll = active_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lock Unused Materials Operator
* \{ */
static int grease_pencil_material_lock_unused_exec(bContext *C, wmOperator * /*op*/)
{
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
bool changed = false;
for (const int material_index : IndexRange(object->totcol)) {
if (!BKE_object_material_slot_used(object, material_index + 1)) {
if (Material *ma = BKE_object_material_get(object, material_index + 1)) {
MaterialGPencilStyle &gp_style = *ma->gp_style;
gp_style.flag |= GP_MATERIAL_HIDE | GP_MATERIAL_LOCKED;
DEG_id_tag_update(&ma->id, ID_RECALC_COPY_ON_WRITE);
changed = true;
}
}
}
if (changed) {
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GEOM | ND_DATA | NA_EDITED, &grease_pencil);
}
return OPERATOR_FINISHED;
}
static void GREASE_PENCIL_OT_material_lock_unused(wmOperatorType *ot)
{
/* Identifiers. */
ot->name = "Lock Unused Materials";
ot->idname = "GREASE_PENCIL_OT_material_lock_unused";
ot->description = "Lock and hide any material not used";
/* Callbacks. */
ot->exec = grease_pencil_material_lock_unused_exec;
ot->poll = active_grease_pencil_poll;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Lock Unselected Materials Operator
* \{ */
@ -152,5 +342,9 @@ void ED_operatortypes_grease_pencil_material()
{
using namespace blender::ed::greasepencil;
WM_operatortype_append(GREASE_PENCIL_OT_material_reveal);
WM_operatortype_append(GREASE_PENCIL_OT_material_hide);
WM_operatortype_append(GREASE_PENCIL_OT_material_lock_all);
WM_operatortype_append(GREASE_PENCIL_OT_material_unlock_all);
WM_operatortype_append(GREASE_PENCIL_OT_material_lock_unused);
WM_operatortype_append(GREASE_PENCIL_OT_material_lock_unselected);
}

View File

@ -440,22 +440,22 @@ ENUM_OPERATORS(eAnimFilter_Flags, ANIMFILTER_TMP_IGNORE_ONLYSEL);
* \{ */
/** NLA track heights */
#define NLACHANNEL_FIRST_TOP(ac) \
(UI_view2d_scale_get_y(&(ac)->region->v2d) * -UI_TIME_SCRUB_MARGIN_Y - NLACHANNEL_SKIP)
#define NLACHANNEL_HEIGHT(snla) \
#define NLATRACK_FIRST_TOP(ac) \
(UI_view2d_scale_get_y(&(ac)->region->v2d) * -UI_TIME_SCRUB_MARGIN_Y - NLATRACK_SKIP)
#define NLATRACK_HEIGHT(snla) \
(((snla) && ((snla)->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : \
(1.2f * U.widget_unit))
#define NLACHANNEL_SKIP (0.1f * U.widget_unit)
#define NLACHANNEL_STEP(snla) (NLACHANNEL_HEIGHT(snla) + NLACHANNEL_SKIP)
#define NLATRACK_SKIP (0.1f * U.widget_unit)
#define NLATRACK_STEP(snla) (NLATRACK_HEIGHT(snla) + NLATRACK_SKIP)
/** Additional offset to give some room at the end. */
#define NLACHANNEL_TOT_HEIGHT(ac, item_amount) \
(-NLACHANNEL_FIRST_TOP(ac) + NLACHANNEL_STEP(((SpaceNla *)(ac)->sl)) * (item_amount + 1))
#define NLATRACK_TOT_HEIGHT(ac, item_amount) \
(-NLATRACK_FIRST_TOP(ac) + NLATRACK_STEP(((SpaceNla *)(ac)->sl)) * (item_amount + 1))
/** Channel widths */
#define NLACHANNEL_NAMEWIDTH (10 * U.widget_unit)
/** Track widths */
#define NLATRACK_NAMEWIDTH (10 * U.widget_unit)
/** Channel toggle-buttons */
#define NLACHANNEL_BUTTON_WIDTH (0.8f * U.widget_unit)
/** Track toggle-buttons */
#define NLATRACK_BUTTON_WIDTH (0.8f * U.widget_unit)
/** \} */

View File

@ -4355,13 +4355,25 @@ static void ui_def_but_rna__menu(bContext *C, uiLayout *layout, void *but_p)
}
if (item->name && item->name[0]) {
float item_width = BLF_width(BLF_default(), item->name, BLF_DRAW_STR_DUMMY_MAX);
col_width = MAX2(col_width, item_width + (120.0f * UI_SCALE_FAC));
col_width = MAX2(col_width, item_width + (100.0f * UI_SCALE_FAC));
}
rows = MAX2(rows, col_rows);
}
text_width += col_width;
text_width /= but->block->aspect;
/* Wrap long single-column lists. */
if (categories == 0) {
columns = MAX2((totitems + 20) / 20, 1);
if (columns > 8) {
columns = (totitems + 25) / 25;
}
rows = MAX2(totitems / columns, 1);
while (rows * columns < totitems) {
rows++;
}
}
/* If the estimated width is greater than available size, collapse to one column. */
if (columns > 1 && text_width > win->sizex) {
columns = 1;

View File

@ -532,14 +532,18 @@ struct EraseOperationExecutor {
const bke::AnonymousAttributePropagationInfo propagation_info{};
/* Copy curves attributes. */
for (bke::AttributeTransferData &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_MASK_CURVE, propagation_info, {"cyclic"}))
{
bke::attribute_math::gather(attribute.src, dst_to_src_curve.as_span(), attribute.dst.span);
attribute.dst.finish();
bke::gather_attributes(src_attributes,
ATTR_DOMAIN_CURVE,
propagation_info,
{"cyclic"},
dst_to_src_curve,
dst_attributes);
if (src_cyclic.get_if_single().value_or(true)) {
array_utils::gather(
src_now_cyclic.as_span(), dst_to_src_curve.as_span(), dst.cyclic_for_write());
}
array_utils::gather(
src_now_cyclic.as_span(), dst_to_src_curve.as_span(), dst.cyclic_for_write());
dst.update_curve_types();
/* Display intersections with flat caps. */
if (!keep_caps) {

View File

@ -21,7 +21,7 @@ set(INC_SYS
set(SRC
nla_buttons.cc
nla_channels.cc
nla_tracks.cc
nla_draw.cc
nla_edit.cc
nla_ops.cc
@ -38,7 +38,6 @@ set(LIB
PRIVATE bf::intern::guardedalloc
)
blender_add_lib(bf_editor_space_nla "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
# RNA_prototypes.h dna_type_offsets.h

View File

@ -793,35 +793,36 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
const float pixelx = BLI_rctf_size_x(&v2d->cur) / BLI_rcti_size_x(&v2d->mask);
const float text_margin_x = (8 * UI_SCALE_FAC) * pixelx;
/* build list of channels to draw */
/* build list of tracks to draw */
ListBase anim_data = {nullptr, nullptr};
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
size_t items = ANIM_animdata_filter(
ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
/* Update max-extent of channels here (taking into account scrollers):
* - this is done to allow the channel list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because channels list is drawn first
* - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
/* Update max-extent of tracks here (taking into account scrollers):
* - this is done to allow the track list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because tracks list is drawn first
* - offset of NLATRACK_HEIGHT*2 is added to the height of the tracks, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
int height = NLACHANNEL_TOT_HEIGHT(ac, items);
int height = NLATRACK_TOT_HEIGHT(ac, items);
v2d->tot.ymin = -height;
/* Loop through channels, and set up drawing depending on their type. */
float ymax = NLACHANNEL_FIRST_TOP(ac);
/* Loop through tracks, and set up drawing depending on their type. */
float ymax = NLATRACK_FIRST_TOP(ac);
for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
ale = ale->next, ymax -= NLACHANNEL_STEP(snla))
ale = ale->next, ymax -= NLATRACK_STEP(snla))
{
float ymin = ymax - NLACHANNEL_HEIGHT(snla);
float ymin = ymax - NLATRACK_HEIGHT(snla);
float ycenter = (ymax + ymin) / 2.0f;
/* check if visible */
if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
/* data to draw depends on the type of channel */
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
{
/* data to draw depends on the type of track */
switch (ale->type) {
case ANIMTYPE_NLATRACK: {
AnimData *adt = ale->adt;
@ -873,16 +874,13 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
nla_action_get_color(adt, static_cast<bAction *>(ale->data), color);
immUniformColor4fv(color);
/* draw slightly shifted up for greater separation from standard channels,
/* draw slightly shifted up for greater separation from standard tracks,
* but also slightly shorter for some more contrast when viewing the strips
*/
switch (adt->act_extendmode) {
case NLASTRIP_EXTEND_HOLD: {
immRectf(pos,
v2d->cur.xmin,
ymin + NLACHANNEL_SKIP,
v2d->cur.xmax,
ymax - NLACHANNEL_SKIP);
immRectf(
pos, v2d->cur.xmin, ymin + NLATRACK_SKIP, v2d->cur.xmax, ymax - NLATRACK_SKIP);
break;
}
case NLASTRIP_EXTEND_HOLD_FORWARD: {
@ -891,7 +889,7 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
BKE_action_frame_range_get(static_cast<bAction *>(ale->data), &r_start, &r_end);
BKE_nla_clip_length_ensure_nonzero(&r_start, &r_end);
immRectf(pos, r_end, ymin + NLACHANNEL_SKIP, v2d->cur.xmax, ymax - NLACHANNEL_SKIP);
immRectf(pos, r_end, ymin + NLATRACK_SKIP, v2d->cur.xmax, ymax - NLATRACK_SKIP);
break;
}
case NLASTRIP_EXTEND_NOTHING:
@ -905,8 +903,8 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
adt,
static_cast<bAction *>(ale->data),
ycenter,
ymin + NLACHANNEL_SKIP,
ymax - NLACHANNEL_SKIP);
ymin + NLATRACK_SKIP,
ymax - NLATRACK_SKIP);
GPU_blend(GPU_BLEND_NONE);
break;
@ -915,14 +913,14 @@ void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region)
}
}
/* Free temporary channels. */
/* Free temporary tracks. */
ANIM_animdata_freelist(&anim_data);
}
/* *********************************************** */
/* Channel List */
/* Track List */
void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
void draw_nla_track_list(const bContext *C, bAnimContext *ac, ARegion *region)
{
ListBase anim_data = {nullptr, nullptr};
@ -930,63 +928,65 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
View2D *v2d = &region->v2d;
size_t items;
/* build list of channels to draw */
/* build list of tracks to draw */
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
/* Update max-extent of channels here (taking into account scrollers):
* - this is done to allow the channel list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because channels list is drawn first
* - offset of NLACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for
/* Update max-extent of tracks here (taking into account scrollers):
* - this is done to allow the track list to be scrollable, but must be done here
* to avoid regenerating the list again and/or also because tracks list is drawn first
* - offset of NLATRACK_HEIGHT*2 is added to the height of the tracks, as first is for
* start of list offset, and the second is as a correction for the scrollers.
*/
int height = NLACHANNEL_TOT_HEIGHT(ac, items);
int height = NLATRACK_TOT_HEIGHT(ac, items);
v2d->tot.ymin = -height;
/* need to do a view-sync here, so that the keys area doesn't jump around
* (it must copy this) */
UI_view2d_sync(nullptr, ac->area, v2d, V2D_LOCK_COPY);
/* draw channels */
/* draw tracks */
{ /* first pass: just the standard GL-drawing for backdrop + text */
size_t channel_index = 0;
float ymax = NLACHANNEL_FIRST_TOP(ac);
size_t track_index = 0;
float ymax = NLATRACK_FIRST_TOP(ac);
for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++)
ale = ale->next, ymax -= NLATRACK_STEP(snla), track_index++)
{
float ymin = ymax - NLACHANNEL_HEIGHT(snla);
float ymin = ymax - NLATRACK_HEIGHT(snla);
/* check if visible */
if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
/* draw all channels using standard channel-drawing API */
ANIM_channel_draw(ac, ale, ymin, ymax, channel_index);
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
{
/* draw all tracks using standard channel-drawing API */
ANIM_channel_draw(ac, ale, ymin, ymax, track_index);
}
}
}
{ /* second pass: UI widgets */
uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS);
size_t channel_index = 0;
float ymax = NLACHANNEL_FIRST_TOP(ac);
size_t track_index = 0;
float ymax = NLATRACK_FIRST_TOP(ac);
/* set blending again, as may not be set in previous step */
GPU_blend(GPU_BLEND_ALPHA);
/* Loop through channels, and set up drawing depending on their type. */
/* Loop through tracks, and set up drawing depending on their type. */
for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
ale = ale->next, ymax -= NLACHANNEL_STEP(snla), channel_index++)
ale = ale->next, ymax -= NLATRACK_STEP(snla), track_index++)
{
float ymin = ymax - NLACHANNEL_HEIGHT(snla);
float ymin = ymax - NLATRACK_HEIGHT(snla);
/* check if visible */
if (IN_RANGE(ymin, v2d->cur.ymin, v2d->cur.ymax) ||
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax)) {
/* draw all channels using standard channel-drawing API */
rctf channel_rect;
BLI_rctf_init(&channel_rect, 0, v2d->cur.xmax, ymin, ymax);
ANIM_channel_draw_widgets(C, ac, ale, block, &channel_rect, channel_index);
IN_RANGE(ymax, v2d->cur.ymin, v2d->cur.ymax))
{
/* draw all tracks using standard channel-drawing API */
rctf track_rect;
BLI_rctf_init(&track_rect, 0, v2d->cur.xmax, ymin, ymax);
ANIM_channel_draw_widgets(C, ac, ale, block, &track_rect, track_index);
}
}
@ -996,7 +996,7 @@ void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region)
GPU_blend(GPU_BLEND_NONE);
}
/* free temporary channels */
/* free temporary tracks */
ANIM_animdata_freelist(&anim_data);
}

View File

@ -322,9 +322,9 @@ static void get_nlastrip_extents(bAnimContext *ac, float *min, float *max, const
*min = 999999999.0f;
*max = -999999999.0f;
/* check if any channels to set range with */
/* check if any tracks to set range with */
if (anim_data.first) {
/* go through channels, finding max extents */
/* go through tracks, finding max extents */
LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) {
NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
@ -415,18 +415,18 @@ void NLA_OT_previewrange_set(wmOperatorType *ot)
* \{ */
/**
* Find the extents of the active channel
* Find the extents of the active track
*
* \param r_min: Bottom y-extent of channel.
* \param r_max: Top y-extent of channel.
* \return Success of finding a selected channel.
* \param r_min: Bottom y-extent of track.
* \param r_max: Top y-extent of track.
* \return Success of finding a selected track.
*/
static bool nla_channels_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
static bool nla_tracks_get_selected_extents(bAnimContext *ac, float *r_min, float *r_max)
{
ListBase anim_data = {nullptr, nullptr};
SpaceNla *snla = reinterpret_cast<SpaceNla *>(ac->sl);
/* NOTE: not bool, since we want prioritize individual channels over expanders. */
/* NOTE: not bool, since we want prioritize individual tracks over expanders. */
short found = 0;
/* get all items - we need to do it this way */
@ -434,11 +434,11 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *r_min, fl
ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
/* loop through all channels, finding the first one that's selected */
float ymax = NLACHANNEL_FIRST_TOP(ac);
/* loop through all tracks, finding the first one that's selected */
float ymax = NLATRACK_FIRST_TOP(ac);
for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
ale = ale->next, ymax -= NLACHANNEL_STEP(snla))
ale = ale->next, ymax -= NLATRACK_STEP(snla))
{
const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale);
@ -447,13 +447,13 @@ static bool nla_channels_get_selected_extents(bAnimContext *ac, float *r_min, fl
ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT))
{
/* update best estimate */
*r_min = ymax - NLACHANNEL_HEIGHT(snla);
*r_min = ymax - NLATRACK_HEIGHT(snla);
*r_max = ymax;
/* is this high enough priority yet? */
found = acf->channel_role;
/* only stop our search when we've found an actual channel
/* only stop our search when we've found an actual track
* - data-block expanders get less priority so that we don't abort prematurely
*/
if (found == ACHANNEL_ROLE_CHANNEL) {
@ -489,17 +489,17 @@ static int nlaedit_viewall(bContext *C, const bool only_sel)
/* set vertical range */
if (only_sel == false) {
/* view all -> the summary channel is usually the shows everything,
/* view all -> the summary track is usually the shows everything,
* and resides right at the top... */
v2d->cur.ymax = 0.0f;
v2d->cur.ymin = float(-BLI_rcti_size_y(&v2d->mask));
}
else {
/* locate first selected channel (or the active one), and frame those */
/* locate first selected track (or the active one), and frame those */
float ymin = v2d->cur.ymin;
float ymax = v2d->cur.ymax;
if (nla_channels_get_selected_extents(&ac, &ymin, &ymax)) {
if (nla_tracks_get_selected_extents(&ac, &ymin, &ymax)) {
/* recenter the view so that this range is in the middle */
float ymid = (ymax - ymin) / 2.0f + ymin;
float x_center;
@ -2164,7 +2164,8 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator * /*op*/)
* (transitions don't have scale) */
if ((strip->flag & NLASTRIP_FLAG_SELECT) && (strip->type == NLASTRIP_TYPE_CLIP)) {
if (strip->act == nullptr || ID_IS_OVERRIDE_LIBRARY(strip->act) ||
ID_IS_LINKED(strip->act)) {
ID_IS_LINKED(strip->act))
{
continue;
}
/* if the referenced action is used by other strips,

View File

@ -27,7 +27,7 @@ void nla_buttons_register(ARegionType *art);
/* `nla_draw.cc` */
void draw_nla_main_data(bAnimContext *ac, SpaceNla *snla, ARegion *region);
void draw_nla_channel_list(const bContext *C, bAnimContext *ac, ARegion *region);
void draw_nla_track_list(const bContext *C, bAnimContext *ac, ARegion *region);
/* **************************************** */
/* `nla_select.cc` */
@ -107,7 +107,7 @@ void NLA_OT_fmodifier_copy(wmOperatorType *ot);
void NLA_OT_fmodifier_paste(wmOperatorType *ot);
/* **************************************** */
/* `nla_channels.cc` */
/* `nla_tracks.cc` */
/**
* Helper - add NLA Tracks alongside existing ones.

View File

@ -194,7 +194,7 @@ void NLA_OT_select_all(wmOperatorType *ot)
* - BKEY - 1: all strips within region are selected #NLAEDIT_BOX_ALLSTRIPS.
* - ALT-BKEY - depending on which axis of the region was larger.
* - 2: x-axis, so select all frames within frame range #NLAEDIT_BOXSEL_FRAMERANGE.
* - 3: y-axis, so select all frames within channels that region included
* - 3: y-axis, so select all frames within tracks that region included
* #NLAEDIT_BOXSEL_CHANNELS.
*/
@ -226,11 +226,11 @@ static void box_select_nla_strips(bAnimContext *ac, rcti rect, short mode, short
selectmode = selmodes_to_flagmodes(selectmode);
/* loop over data, doing box select */
float ymax = NLACHANNEL_FIRST_TOP(ac);
float ymax = NLATRACK_FIRST_TOP(ac);
for (bAnimListElem *ale = static_cast<bAnimListElem *>(anim_data.first); ale;
ale = ale->next, ymax -= NLACHANNEL_STEP(snla))
ale = ale->next, ymax -= NLATRACK_STEP(snla))
{
float ymin = ymax - NLACHANNEL_HEIGHT(snla);
float ymin = ymax - NLATRACK_HEIGHT(snla);
/* perform vertical suitability check (if applicable) */
if ((mode == NLA_BOXSEL_FRAMERANGE) || !((ymax < rectf.ymin) || (ymin > rectf.ymax))) {
@ -241,7 +241,8 @@ static void box_select_nla_strips(bAnimContext *ac, rcti rect, short mode, short
/* only select strips if they fall within the required ranges (if applicable) */
LISTBASE_FOREACH (NlaStrip *, strip, &nlt->strips) {
if ((mode == NLA_BOXSEL_CHANNELS) ||
BKE_nlastrip_within_bounds(strip, rectf.xmin, rectf.xmax)) {
BKE_nlastrip_within_bounds(strip, rectf.xmin, rectf.xmax))
{
/* set selection */
ACHANNEL_SET_FLAG(strip, selectmode, NLASTRIP_FLAG_SELECT);
@ -269,16 +270,10 @@ static void nlaedit_strip_at_region_position(
View2D *v2d = &ac->region->v2d;
float view_x, view_y;
int channel_index;
int track_index;
UI_view2d_region_to_view(v2d, region_x, region_y, &view_x, &view_y);
UI_view2d_listview_view_to_cell(0,
NLACHANNEL_STEP(snla),
0,
NLACHANNEL_FIRST_TOP(ac),
view_x,
view_y,
nullptr,
&channel_index);
UI_view2d_listview_view_to_cell(
0, NLATRACK_STEP(snla), 0, NLATRACK_FIRST_TOP(ac), view_x, view_y, nullptr, &track_index);
ListBase anim_data = {nullptr, nullptr};
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
@ -292,7 +287,7 @@ static void nlaedit_strip_at_region_position(
const float xmin = UI_view2d_region_to_view_x(v2d, region_x - 7);
const float xmax = UI_view2d_region_to_view_x(v2d, region_x + 7);
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, track_index));
if (ale != nullptr) {
if (ale->type == ANIMTYPE_NLATRACK) {
NlaTrack *nlt = static_cast<NlaTrack *>(ale->data);
@ -378,9 +373,9 @@ static int nlaedit_box_select_exec(bContext *C, wmOperator *op)
/* mode depends on which axis of the range is larger to determine which axis to use.
* - Checking this in region-space is fine,
* as it's fundamentally still going to be a different rect size.
* - The frame-range select option is favored over the channel one (x over y),
* - The frame-range select option is favored over the track one (x over y),
* as frame-range one is often.
* Used for tweaking timing when "blocking", while channels is not that useful.
* Used for tweaking timing when "blocking", while tracks is not that useful.
*/
if (BLI_rcti_size_x(&rect) >= BLI_rcti_size_y(&rect)) {
mode = NLA_BOXSEL_FRAMERANGE;
@ -459,12 +454,12 @@ static void nlaedit_select_leftright(bContext *C,
WM_operator_name_call(C, "NLA_OT_tweakmode_exit", WM_OP_EXEC_DEFAULT, nullptr, nullptr);
}
/* if select mode is replace, deselect all keyframes (and channels) first */
/* if select mode is replace, deselect all keyframes (and tracks) first */
if (select_mode == SELECT_REPLACE) {
select_mode = SELECT_ADD;
/* - deselect all other keyframes, so that just the newly selected remain
* - channels aren't deselected, since we don't re-select any as a consequence
* - tracks aren't deselected, since we don't re-select any as a consequence
*/
deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
}
@ -531,7 +526,7 @@ static int nlaedit_select_leftright_exec(bContext *C, wmOperator *op)
/* do the selecting now */
nlaedit_select_leftright(C, &ac, leftright, selectmode);
/* set notifier that keyframe selection (and channels too) have changed */
/* set notifier that keyframe selection (and tracks too) have changed */
WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, nullptr);
WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN | NA_SELECTED, nullptr);
@ -638,12 +633,12 @@ static int mouse_nla_strips(bContext *C,
/* deselect all strips */
deselect_nla_strips(ac, 0, SELECT_SUBTRACT);
/* deselect all other channels first */
/* deselect all other tracks first */
ANIM_anim_channels_select_set(ac, ACHANNEL_SETFLAG_CLEAR);
}
}
/* only select strip if we clicked on a valid channel and hit something */
/* only select strip if we clicked on a valid track and hit something */
if (ale != nullptr) {
/* select the strip accordingly (if a matching one was found) */
if (strip != nullptr) {
@ -672,7 +667,7 @@ static int mouse_nla_strips(bContext *C,
}
}
/* free this channel */
/* free this track */
MEM_freeN(ale);
}

View File

@ -52,40 +52,39 @@
* from the standard Animation Editor ones */
/* ******************** Mouse-Click Operator *********************** */
/* Depending on the channel that was clicked on, the mouse click will activate whichever
* part of the channel is relevant.
/* Depending on the track that was clicked on, the mouse click will activate whichever
* part of the track is relevant.
*
* NOTE: eventually,
* this should probably be phased out when many of these things are replaced with buttons
* --> Most channels are now selection only.
* --> Most tracks are now selection only.
*/
static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index, short selectmode)
static int mouse_nla_tracks(bContext *C, bAnimContext *ac, int track_index, short selectmode)
{
ListBase anim_data = {nullptr, nullptr};
int notifierFlags = 0;
/* get the channel that was clicked on */
/* filter channels */
/* get the track that was clicked on */
/* filter tracks */
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(ac, &anim_data, filter, ac->data, eAnimCont_Types(ac->datatype));
/* get channel from index */
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
/* get track from index */
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, track_index));
if (ale == nullptr) {
/* channel not found */
/* track not found */
if (G.debug & G_DEBUG) {
printf("Error: animation channel (index = %d) not found in mouse_anim_channels()\n",
channel_index);
printf("Error: animation track (index = %d) not found in mouse_nla_tracks()\n", track_index);
}
ANIM_animdata_freelist(&anim_data);
return 0;
}
/* action to take depends on what channel we've got */
/* action to take depends on what track we've got */
/* WARNING: must keep this in sync with the equivalent function in `anim_channels_edit.cc`. */
switch (ale->type) {
case ANIMTYPE_SCENE: {
@ -128,7 +127,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
}
else {
/* deselect all */
/* TODO: should this deselect all other types of channels too? */
/* TODO: should this deselect all other types of tracks too? */
BKE_view_layer_synced_ensure(ac->scene, view_layer);
LISTBASE_FOREACH (Base *, b, BKE_view_layer_object_bases_get(view_layer)) {
ED_object_base_select(b, BA_DESELECT);
@ -151,7 +150,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
adt->flag |= ADT_UI_ACTIVE;
}
/* notifiers - channel was selected */
/* notifiers - track was selected */
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
}
break;
@ -222,7 +221,7 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
ac, ac->data, eAnimCont_Types(ac->datatype), filter, nlt, ANIMTYPE_NLATRACK);
}
/* notifier flags - channel was selected */
/* notifier flags - track was selected */
notifierFlags |= (ND_ANIMCHAN | NA_SELECTED);
}
break;
@ -269,12 +268,12 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
}
default:
if (G.debug & G_DEBUG) {
printf("Error: Invalid channel type in mouse_nla_channels()\n");
printf("Error: Invalid track type in mouse_nla_tracks()\n");
}
break;
}
/* free channels */
/* free tracks */
ANIM_animdata_update(ac, &anim_data);
ANIM_animdata_freelist(&anim_data);
@ -285,12 +284,12 @@ static int mouse_nla_channels(bContext *C, bAnimContext *ac, int channel_index,
/* ------------------- */
/* handle clicking */
static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
static int nlatracks_mouseclick_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
bAnimContext ac;
ARegion *region;
View2D *v2d;
int channel_index;
int track_index;
int notifierFlags = 0;
short selectmode;
float x, y;
@ -313,19 +312,19 @@ static int nlachannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmEv
selectmode = SELECT_REPLACE;
}
/* Figure out which channel user clicked in. */
/* Figure out which track user clicked in. */
UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y);
UI_view2d_listview_view_to_cell(NLACHANNEL_NAMEWIDTH,
NLACHANNEL_STEP(snla),
UI_view2d_listview_view_to_cell(NLATRACK_NAMEWIDTH,
NLATRACK_STEP(snla),
0,
NLACHANNEL_FIRST_TOP(&ac),
NLATRACK_FIRST_TOP(&ac),
x,
y,
nullptr,
&channel_index);
&track_index);
/* handle mouse-click in the relevant channel then */
notifierFlags = mouse_nla_channels(C, &ac, channel_index, selectmode);
/* handle mouse-click in the relevant track then */
notifierFlags = mouse_nla_tracks(C, &ac, track_index, selectmode);
/* set notifier that things have changed */
WM_event_add_notifier(C, NC_ANIMATION | notifierFlags, nullptr);
@ -343,7 +342,7 @@ void NLA_OT_channels_click(wmOperatorType *ot)
ot->description = "Handle clicks to select NLA tracks";
/* api callbacks */
ot->invoke = nlachannels_mouseclick_invoke;
ot->invoke = nlatracks_mouseclick_invoke;
ot->poll = ED_operator_nla_active;
/* flags */
@ -359,12 +358,12 @@ void NLA_OT_channels_click(wmOperatorType *ot)
/* ******************** Action Push Down ******************************** */
static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
static int nlatracks_pushdown_exec(bContext *C, wmOperator *op)
{
bAnimContext ac;
ID *id = nullptr;
AnimData *adt = nullptr;
int channel_index = RNA_int_get(op->ptr, "channel_index");
int track_index = RNA_int_get(op->ptr, "track_index");
/* get editor data */
if (ANIM_animdata_get_context(C, &ac) == 0) {
@ -372,7 +371,7 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
}
/* get anim-channel to use (or more specifically, the animdata block behind it) */
if (channel_index == -1) {
if (track_index == -1) {
PointerRNA adt_ptr = {nullptr};
/* active animdata block */
@ -389,31 +388,31 @@ static int nlachannels_pushdown_exec(bContext *C, wmOperator *op)
adt = static_cast<AnimData *>(adt_ptr.data);
}
else {
/* indexed channel */
/* indexed track */
ListBase anim_data = {nullptr, nullptr};
/* filter channels */
/* filter tracks */
eAnimFilter_Flags filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE |
ANIMFILTER_LIST_CHANNELS | ANIMFILTER_FCURVESONLY);
ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, eAnimCont_Types(ac.datatype));
/* get channel from index */
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, channel_index));
/* get track from index */
bAnimListElem *ale = static_cast<bAnimListElem *>(BLI_findlink(&anim_data, track_index));
if (ale == nullptr) {
BKE_reportf(op->reports, RPT_ERROR, "No animation channel found at index %d", channel_index);
BKE_reportf(op->reports, RPT_ERROR, "No animation track found at index %d", track_index);
ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
if (ale->type != ANIMTYPE_NLAACTION) {
BKE_reportf(op->reports,
RPT_ERROR,
"Animation channel at index %d is not a NLA 'Active Action' channel",
channel_index);
"Animation track at index %d is not a NLA 'Active Action' track",
track_index);
ANIM_animdata_freelist(&anim_data);
return OPERATOR_CANCELLED;
}
/* grab AnimData from the channel */
/* grab AnimData from the track */
adt = ale->adt;
id = ale->id;
@ -460,7 +459,7 @@ void NLA_OT_action_pushdown(wmOperatorType *ot)
ot->description = "Push action down onto the top of the NLA stack as a new strip";
/* callbacks */
ot->exec = nlachannels_pushdown_exec;
ot->exec = nlatracks_pushdown_exec;
ot->poll = nlaop_poll_tweakmode_off;
/* flags */
@ -468,12 +467,12 @@ void NLA_OT_action_pushdown(wmOperatorType *ot)
/* properties */
ot->prop = RNA_def_int(ot->srna,
"channel_index",
"track_index",
-1,
-1,
INT_MAX,
"Channel Index",
"Index of NLA action channel to perform pushdown operation on",
"Track Index",
"Index of NLA action track to perform pushdown operation on",
0,
INT_MAX);
RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE | PROP_HIDDEN);

View File

@ -66,8 +66,8 @@ static SpaceLink *nla_create(const ScrArea *area, const Scene *scene)
region->regiontype = RGN_TYPE_HEADER;
region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP;
/* channel list region */
region = MEM_cnew<ARegion>("channel list for nla");
/* track list region */
region = MEM_cnew<ARegion>("track list for nla");
BLI_addtail(&snla->regionbase, region);
region->regiontype = RGN_TYPE_CHANNELS;
region->alignment = RGN_ALIGN_LEFT;
@ -151,7 +151,7 @@ static SpaceLink *nla_duplicate(SpaceLink *sl)
}
/* add handlers, stuff you only do once or on area/region changes */
static void nla_channel_region_init(wmWindowManager *wm, ARegion *region)
static void nla_track_region_init(wmWindowManager *wm, ARegion *region)
{
wmKeyMap *keymap;
@ -161,7 +161,7 @@ static void nla_channel_region_init(wmWindowManager *wm, ARegion *region)
UI_view2d_region_reinit(&region->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy);
/* own keymap */
/* own channels map first to override some channel keymaps */
/* own tracks map first to override some track keymaps */
keymap = WM_keymap_ensure(wm->defaultconf, "NLA Tracks", SPACE_NLA, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler_v2d_mask(&region->handlers, keymap);
/* now generic channels map for everything else that can apply */
@ -173,7 +173,7 @@ static void nla_channel_region_init(wmWindowManager *wm, ARegion *region)
}
/* draw entirely, view changes should be handled here */
static void nla_channel_region_draw(const bContext *C, ARegion *region)
static void nla_track_region_draw(const bContext *C, ARegion *region)
{
bAnimContext ac;
View2D *v2d = &region->v2d;
@ -185,10 +185,10 @@ static void nla_channel_region_draw(const bContext *C, ARegion *region)
/* data */
if (ANIM_animdata_get_context(C, &ac)) {
draw_nla_channel_list(C, &ac, region);
draw_nla_track_list(C, &ac, region);
}
/* channel filter next to scrubbing area */
/* track filter next to scrubbing area */
ED_time_scrub_channel_search_draw(C, region, ac.ads);
/* reset view matrix */
@ -430,13 +430,21 @@ static void nla_main_region_message_subscribe(const wmRegionMessageSubscribePara
}
}
static void nla_main_region_view2d_changed(const bContext * /*C*/, ARegion *region)
static void nla_main_region_view2d_changed(const bContext *C, ARegion *region)
{
SpaceNla *snla = CTX_wm_space_nla(C);
View2D *v2d = &region->v2d;
/* If markers are present add region padding
* so bottom strip isn't hidden.
*/
if (!BLI_listbase_is_empty(ED_context_get_markers(C))) {
v2d->tot.ymin -= (UI_MARKER_MARGIN_Y - NLATRACK_STEP(snla));
}
UI_view2d_curRect_clamp_y(v2d);
}
static void nla_channel_region_listener(const wmRegionListenerParams *params)
static void nla_track_region_listener(const wmRegionListenerParams *params)
{
ARegion *region = params->region;
const wmNotifier *wmn = params->notifier;
@ -478,7 +486,7 @@ static void nla_channel_region_listener(const wmRegionListenerParams *params)
}
}
static void nla_channel_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
static void nla_track_region_message_subscribe(const wmRegionMessageSubscribeParams *params)
{
wmMsgBus *mbus = params->message_bus;
ARegion *region = params->region;
@ -633,16 +641,16 @@ void ED_spacetype_nla()
BLI_addhead(&st->regiontypes, art);
/* regions: channels */
/* regions: tracks */
art = MEM_cnew<ARegionType>("spacetype nla region");
art->regionid = RGN_TYPE_CHANNELS;
art->prefsizex = 200;
art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES;
art->init = nla_channel_region_init;
art->draw = nla_channel_region_draw;
art->listener = nla_channel_region_listener;
art->message_subscribe = nla_channel_region_message_subscribe;
art->init = nla_track_region_init;
art->draw = nla_track_region_draw;
art->listener = nla_track_region_listener;
art->message_subscribe = nla_track_region_message_subscribe;
BLI_addhead(&st->regiontypes, art);

View File

@ -473,9 +473,19 @@ static void unlink_object_fn(bContext *C,
DEG_relations_tag_update(bmain);
}
else if (GS(tsep->id->name) == ID_SCE) {
/* Following execution is expected to happen exclusively in the Outliner scene view. */
#ifdef NDEBUG
SpaceOutliner *space_outliner = CTX_wm_space_outliner(C);
BLI_assert(space_outliner->outlinevis == SO_SCENES);
#endif
Scene *scene = (Scene *)tsep->id;
Collection *parent = scene->master_collection;
BKE_collection_object_remove(bmain, parent, ob, true);
FOREACH_SCENE_COLLECTION_BEGIN (scene, collection) {
if (BKE_collection_has_object(collection, ob)){
BKE_collection_object_remove(bmain, collection, ob, true);
}
}
FOREACH_SCENE_COLLECTION_END;
DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE | ID_RECALC_HIERARCHY);
DEG_relations_tag_update(bmain);
}

View File

@ -1201,8 +1201,8 @@ void animrecord_check_state(TransInfo *t, ID *id)
* - we're not only keying for available channels
* - the option to add new actions for each round is not enabled
*/
if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAIL) == 0 &&
(scene->toolsettings->autokey_flag & ANIMRECORD_FLAG_WITHNLA))
if (blender::animrig::is_autokey_flag(scene, AUTOKEY_FLAG_INSERTAVAILABLE) == 0 &&
(scene->toolsettings->autokey_flag & AUTOKEY_FLAG_LAYERED_RECORD))
{
/* if playback has just looped around,
* we need to add a new NLA track+strip to allow a clean pass to occur */

View File

@ -559,7 +559,7 @@ static void createTransNlaData(bContext *C, TransInfo *t)
tdn->trackIndex = BLI_findindex(&adt->nla_tracks, nlt);
tdn->signed_track_index = tdn->trackIndex;
yval = float(tdn->trackIndex * NLACHANNEL_STEP(snla));
yval = float(tdn->trackIndex * NLATRACK_STEP(snla));
tdn->h1[0] = strip->start;
tdn->h1[1] = yval;
@ -726,8 +726,8 @@ static void recalcData_nla(TransInfo *t)
continue;
}
delta_y1 = (int(tdn->h1[1]) / NLACHANNEL_STEP(snla) - tdn->signed_track_index);
delta_y2 = (int(tdn->h2[1]) / NLACHANNEL_STEP(snla) - tdn->signed_track_index);
delta_y1 = (int(tdn->h1[1]) / NLATRACK_STEP(snla) - tdn->signed_track_index);
delta_y2 = (int(tdn->h2[1]) / NLATRACK_STEP(snla) - tdn->signed_track_index);
/* Move strip into track in the requested direction. */
/* If we cannot find the strip in the track, this strip has moved tracks already (if multiple
@ -959,7 +959,7 @@ static void special_aftertrans_update__nla(bContext *C, TransInfo *t)
ListBase anim_data = {nullptr, nullptr};
short filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_FCURVESONLY);
/* get channels to work on */
/* get tracks to work on */
ANIM_animdata_filter(
&ac, &anim_data, eAnimFilter_Flags(filter), ac.data, eAnimCont_Types(ac.datatype));

View File

@ -80,8 +80,11 @@ typedef enum eGPUMaterialFlag {
GPU_MATFLAG_AO = (1 << 8),
GPU_MATFLAG_COAT = (1 << 9),
GPU_MATFLAG_OBJECT_INFO = (1 << 10),
GPU_MATFLAG_AOV = (1 << 11),
GPU_MATFLAG_VOLUME_SCATTER = (1 << 10),
GPU_MATFLAG_VOLUME_ABSORPTION = (1 << 11),
GPU_MATFLAG_OBJECT_INFO = (1 << 12),
GPU_MATFLAG_AOV = (1 << 13),
GPU_MATFLAG_BARYCENTRIC = (1 << 20),

View File

@ -171,6 +171,12 @@ void GLBackend::platform_init()
{
support_level = GPU_SUPPORT_LEVEL_LIMITED;
}
/* Latest Intel driver have bugs that won't allow Blender to start.
* Users must install different version of the driver.
* See #113124 for more information. */
if (strstr(version, "Build 20.19.15.51")) {
support_level = GPU_SUPPORT_LEVEL_UNSUPPORTED;
}
}
if ((device & GPU_DEVICE_ATI) && (os & GPU_OS_UNIX)) {
/* Platform seems to work when SB backend is disabled. This can be done

View File

@ -84,9 +84,6 @@ enum eCollectionLineArt_Flags {
};
typedef struct Collection_Runtime {
/** The ID owning this collection, in case it is an embedded one. */
ID *owner_id;
/**
* Cache of objects in this collection and all its children.
* This is created on demand when e.g. some physics simulation needs it,
@ -111,6 +108,9 @@ typedef struct Collection_Runtime {
typedef struct Collection {
ID id;
/** The ID owning this collection, in case it is an embedded one. */
ID *owner_id;
/** CollectionObject. */
ListBase gobject;
/** CollectionChild. */
@ -131,7 +131,6 @@ typedef struct Collection {
uint8_t lineart_intersection_mask;
uint8_t lineart_intersection_priority;
void *_pad1;
struct ViewLayer *view_layer DNA_DEPRECATED;
/* Keep last. */

View File

@ -1281,22 +1281,21 @@ typedef enum eZoomFrame_Mode {
} eZoomFrame_Mode;
/**
* Auto-Keying flag
* #UserDef.autokey_flag (not strictly used when autokeying only -
* is also used when keyframing these days).
* Defines how keyframes are inserted.
* Used for regular keying and auto-keying.
*/
typedef enum eAutokey_Flag {
AUTOKEY_FLAG_INSERTAVAIL = (1 << 0),
typedef enum eKeyInsert_Flag {
AUTOKEY_FLAG_INSERTAVAILABLE = (1 << 0),
AUTOKEY_FLAG_INSERTNEEDED = (1 << 1),
AUTOKEY_FLAG_AUTOMATKEY = (1 << 2),
AUTOKEY_FLAG_VISUALKEY = (1 << 2),
AUTOKEY_FLAG_XYZ2RGB = (1 << 3),
/* toolsettings->autokey_flag */
AUTOKEY_FLAG_ONLYKEYINGSET = (1 << 6),
AUTOKEY_FLAG_NOWARNING = (1 << 7),
AUTOKEY_FLAG_CYCLEAWARE = (1 << 8),
ANIMRECORD_FLAG_WITHNLA = (1 << 10),
} eAutokey_Flag;
AUTOKEY_FLAG_LAYERED_RECORD = (1 << 10),
} eKeyInsert_Flag;
typedef enum eKeyInsertChannels {
USER_ANIM_KEY_CHANNEL_LOCATION = (1 << 0),
@ -1309,7 +1308,7 @@ typedef enum eKeyInsertChannels {
/**
* Animation flags
* #UserDef.animation_flag, used for animation flags that aren't covered by more specific flags
* (like eAutokey_Flag).
* (like eKeyInsert_Flag).
*/
typedef enum eUserpref_Anim_Flags {
USER_ANIM_SHOW_CHANNEL_GROUP_COLORS = (1 << 0),

View File

@ -35,7 +35,7 @@
#endif
const EnumPropertyItem rna_enum_fmodifier_type_items[] = {
{FMODIFIER_TYPE_NULL, "nullptr", 0, "Invalid", ""},
{FMODIFIER_TYPE_NULL, "NULL", 0, "Invalid", ""},
{FMODIFIER_TYPE_GENERATOR,
"GENERATOR",
0,

View File

@ -3799,7 +3799,7 @@ static void rna_def_tool_settings(BlenderRNA *brna)
"Mode of automatic keyframe insertion for Objects, Bones and Masks");
prop = RNA_def_property(srna, "use_record_with_nla", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", ANIMRECORD_FLAG_WITHNLA);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_LAYERED_RECORD);
RNA_def_property_ui_text(
prop,
"Layered",

View File

@ -5422,7 +5422,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
"(default setting used for new Scenes)");
prop = RNA_def_property(srna, "use_keyframe_insert_available", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_INSERTAVAIL);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_INSERTAVAILABLE);
RNA_def_property_ui_text(prop,
"Auto Keyframe Insert Available",
"Automatic keyframe insertion in available F-Curves");
@ -5449,7 +5449,7 @@ static void rna_def_userdef_edit(BlenderRNA *brna)
prop, "Keyframe Insert Needed", "Keyframe insertion only when keyframe needed");
prop = RNA_def_property(srna, "use_visual_keying", PROP_BOOLEAN, PROP_NONE);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_AUTOMATKEY);
RNA_def_property_boolean_sdna(prop, nullptr, "autokey_flag", AUTOKEY_FLAG_VISUALKEY);
RNA_def_property_ui_text(
prop, "Visual Keying", "Use Visual keying automatically for constrained objects");

View File

@ -80,30 +80,6 @@ static OffsetIndices<int> accumulate_counts_to_offsets(const IndexMask &selectio
return OffsetIndices<int>(r_offset_data);
}
/* Utility functions for threaded copying of attribute data where possible. */
template<typename T>
static void threaded_slice_fill(const OffsetIndices<int> offsets,
const IndexMask &selection,
const Span<T> src,
MutableSpan<T> dst)
{
BLI_assert(offsets.total_size() == dst.size());
selection.foreach_index(GrainSize(512), [&](const int64_t index, const int64_t i) {
dst.slice(offsets[i]).fill(src[index]);
});
}
static void threaded_slice_fill(const OffsetIndices<int> offsets,
const IndexMask &selection,
const GSpan src,
GMutableSpan dst)
{
bke::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
using T = decltype(dummy);
threaded_slice_fill<T>(offsets, selection, src.typed<T>(), dst.typed<T>());
});
}
static void copy_hashed_ids(const Span<int> src, const int hash, MutableSpan<int> dst)
{
for (const int i : src.index_range()) {
@ -172,21 +148,6 @@ static void copy_stable_id_point(const OffsetIndices<int> offsets,
dst_attribute.finish();
}
static void copy_attributes_without_id(const OffsetIndices<int> offsets,
const IndexMask &selection,
const AnonymousAttributePropagationInfo &propagation_info,
const eAttrDomain domain,
const bke::AttributeAccessor src_attributes,
bke::MutableAttributeAccessor dst_attributes)
{
for (auto &attribute : bke::retrieve_attributes_for_transfer(
src_attributes, dst_attributes, ATTR_DOMAIN_AS_MASK(domain), propagation_info, {"id"}))
{
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
attribute.dst.finish();
}
}
/** \} */
/* -------------------------------------------------------------------- */
@ -215,7 +176,8 @@ static void copy_curve_attributes_without_id(
{
switch (attribute.meta_data.domain) {
case ATTR_DOMAIN_CURVE:
threaded_slice_fill(curve_offsets, selection, attribute.src, attribute.dst.span);
bke::attribute_math::gather_to_groups(
curve_offsets, selection, attribute.src, attribute.dst.span);
break;
case ATTR_DOMAIN_POINT:
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
@ -401,7 +363,8 @@ static void copy_face_attributes_without_id(
bke::attribute_math::gather(attribute.src, edge_mapping, attribute.dst.span);
break;
case ATTR_DOMAIN_FACE:
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
bke::attribute_math::gather_to_groups(
offsets, selection, attribute.src, attribute.dst.span);
break;
case ATTR_DOMAIN_CORNER:
bke::attribute_math::gather(attribute.src, loop_mapping, attribute.dst.span);
@ -597,7 +560,8 @@ static void copy_edge_attributes_without_id(
{
switch (attribute.meta_data.domain) {
case ATTR_DOMAIN_EDGE:
threaded_slice_fill(offsets, selection, attribute.src, attribute.dst.span);
bke::attribute_math::gather_to_groups(
offsets, selection, attribute.src, attribute.dst.span);
break;
case ATTR_DOMAIN_POINT:
bke::attribute_math::gather(attribute.src, point_mapping, attribute.dst.span);
@ -764,35 +728,31 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
Curves *new_curves_id = bke::curves_new_nomain(dst_num, dst_num);
bke::curves_copy_parameters(src_curves_id, *new_curves_id);
bke::CurvesGeometry &new_curves = new_curves_id->geometry.wrap();
MutableSpan<int> new_curve_offsets = new_curves.offsets_for_write();
array_utils::fill_index_range(new_curve_offsets);
offset_indices::fill_constant_group_size(1, 0, new_curves.offsets_for_write());
bke::gather_attributes_to_groups(src_curves.attributes(),
ATTR_DOMAIN_POINT,
propagation_info,
{},
duplicates,
selection,
new_curves.attributes_for_write());
for (auto &attribute : bke::retrieve_attributes_for_transfer(src_curves.attributes(),
new_curves.attributes_for_write(),
ATTR_DOMAIN_MASK_ALL,
ATTR_DOMAIN_MASK_CURVE,
propagation_info,
{"id"}))
{
switch (attribute.meta_data.domain) {
case ATTR_DOMAIN_CURVE:
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
using T = decltype(dummy);
const Span<T> src = attribute.src.typed<T>();
MutableSpan<T> dst = attribute.dst.span.typed<T>();
selection.foreach_index(GrainSize(512),
[&](const int64_t index, const int64_t i_selection) {
const T &src_value = src[point_to_curve_map[index]];
dst.slice(duplicates[i_selection]).fill(src_value);
});
});
break;
case ATTR_DOMAIN_POINT:
threaded_slice_fill(duplicates, selection, attribute.src, attribute.dst.span);
break;
default:
BLI_assert_unreachable();
break;
}
bke::attribute_math::convert_to_static_type(attribute.src.type(), [&](auto dummy) {
using T = decltype(dummy);
const Span<T> src = attribute.src.typed<T>();
MutableSpan<T> dst = attribute.dst.span.typed<T>();
selection.foreach_index(GrainSize(512), [&](const int64_t index, const int64_t i_selection) {
const T &src_value = src[point_to_curve_map[index]];
dst.slice(duplicates[i_selection]).fill(src_value);
});
});
attribute.dst.finish();
}
@ -837,12 +797,13 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
Mesh *new_mesh = BKE_mesh_new_nomain(duplicates.total_size(), 0, 0, 0);
copy_attributes_without_id(duplicates,
selection,
propagation_info,
ATTR_DOMAIN_POINT,
mesh.attributes(),
new_mesh->attributes_for_write());
bke::gather_attributes_to_groups(mesh.attributes(),
ATTR_DOMAIN_POINT,
propagation_info,
{"id"},
duplicates,
selection,
new_mesh->attributes_for_write());
copy_stable_id_point(duplicates, mesh.attributes(), new_mesh->attributes_for_write());
@ -887,12 +848,13 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
PointCloud *pointcloud = BKE_pointcloud_new_nomain(duplicates.total_size());
copy_attributes_without_id(duplicates,
selection,
propagation_info,
ATTR_DOMAIN_POINT,
src_points.attributes(),
pointcloud->attributes_for_write());
bke::gather_attributes_to_groups(src_points.attributes(),
ATTR_DOMAIN_POINT,
propagation_info,
{"id"},
duplicates,
selection,
pointcloud->attributes_for_write());
copy_stable_id_point(duplicates, src_points.attributes(), pointcloud->attributes_for_write());
@ -999,12 +961,13 @@ static void duplicate_instances(GeometrySet &geometry_set,
dst_instances->reference_handles().slice(range).fill(new_handle);
}
copy_attributes_without_id(duplicates,
selection,
propagation_info,
ATTR_DOMAIN_INSTANCE,
src_instances.attributes(),
dst_instances->attributes_for_write());
bke::gather_attributes_to_groups(src_instances.attributes(),
ATTR_DOMAIN_INSTANCE,
propagation_info,
{"id"},
duplicates,
selection,
dst_instances->attributes_for_write());
if (attribute_outputs.duplicate_index) {
create_duplicate_index_attribute(dst_instances->attributes_for_write(),

View File

@ -9,20 +9,34 @@ namespace blender::nodes::node_shader_volume_absorption_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Color").default_value({0.8f, 0.8f, 0.8f, 1.0f});
#define SOCK_COLOR_ID 0
b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f).max(1000.0f);
#define SOCK_DENSITY_ID 1
b.add_input<decl::Float>("Weight").unavailable();
b.add_output<decl::Shader>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
}
#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
#define socket_not_white(sock) \
(in[sock].link || \
(clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f && clamp_f(in[sock].vec[1], 0.0f, 1.0f) < 1.0f && \
clamp_f(in[sock].vec[2], 0.0f, 1.0f) < 1.0f))
static int node_shader_gpu_volume_absorption(GPUMaterial *mat,
bNode *node,
bNodeExecData * /*execdata*/,
GPUNodeStack *in,
GPUNodeStack *out)
{
if (socket_not_zero(SOCK_DENSITY_ID) && socket_not_white(SOCK_COLOR_ID)) {
GPU_material_flag_set(mat, GPU_MATFLAG_VOLUME_ABSORPTION);
}
return GPU_stack_link(mat, node, "node_volume_absorption", in, out);
}
#undef SOCK_COLOR_ID
#undef SOCK_DENSITY_ID
} // namespace blender::nodes::node_shader_volume_absorption_cc
/* node type definition */

View File

@ -11,23 +11,33 @@ namespace blender::nodes::node_shader_volume_principled_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Color").default_value({0.5f, 0.5f, 0.5f, 1.0f});
#define SOCK_COLOR_ID 0
b.add_input<decl::String>("Color Attribute");
#define SOCK_COLOR_ATTR_ID 1
b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f).max(1000.0f);
#define SOCK_DENSITY_ID 2
b.add_input<decl::String>("Density Attribute").default_value("density");
#define SOCK_DENSITY_ATTR_ID 3
b.add_input<decl::Float>("Anisotropy")
.default_value(0.0f)
.min(-1.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_ANISOTROPY_ID 4
b.add_input<decl::Color>("Absorption Color").default_value({0.0f, 0.0f, 0.0f, 1.0f});
#define SOCK_ABSORPTION_COLOR_ID 5
b.add_input<decl::Float>("Emission Strength").default_value(0.0f).min(0.0f).max(1000.0f);
#define SOCK_EMISSION_ID 6
b.add_input<decl::Color>("Emission Color").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_EMISSION_COLOR_ID 7
b.add_input<decl::Float>("Blackbody Intensity")
.default_value(0.0f)
.min(0.0f)
.max(1.0f)
.subtype(PROP_FACTOR);
#define SOCK_BLACKBODY_INTENSITY_ID 8
b.add_input<decl::Color>("Blackbody Tint").default_value({1.0f, 1.0f, 1.0f, 1.0f});
#define SOCK_BLACKBODY_TINT_ID 8
b.add_input<decl::Float>("Temperature").default_value(1000.0f).min(0.0f).max(6500.0f);
b.add_input<decl::String>("Temperature Attribute").default_value("temperature");
b.add_input<decl::Float>("Weight").unavailable();
@ -46,6 +56,16 @@ static void attribute_post_process(GPUMaterial *mat,
}
}
#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
#define socket_not_black(sock) \
(in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f && \
clamp_f(in[sock].vec[1], 0.0f, 1.0f) > 1e-5f && \
clamp_f(in[sock].vec[2], 0.0f, 1.0f) > 1e-5f))
#define socket_not_white(sock) \
(in[sock].link || \
(clamp_f(in[sock].vec[0], 0.0f, 1.0f) < 1.0f && clamp_f(in[sock].vec[1], 0.0f, 1.0f) < 1.0f && \
clamp_f(in[sock].vec[2], 0.0f, 1.0f) < 1.0f))
static int node_shader_gpu_volume_principled(GPUMaterial *mat,
bNode *node,
bNodeExecData * /*execdata*/,
@ -53,7 +73,16 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
GPUNodeStack *out)
{
/* Test if blackbody intensity is enabled. */
bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f);
bool use_blackbody = socket_not_zero(SOCK_BLACKBODY_INTENSITY_ID);
if (socket_not_zero(SOCK_DENSITY_ID) && socket_not_black(SOCK_COLOR_ID)) {
/* Consider there is absorption phenomenon when there is scattering since
* `extinction = scattering + absorption`. */
GPU_material_flag_set(mat, GPU_MATFLAG_VOLUME_SCATTER | GPU_MATFLAG_VOLUME_ABSORPTION);
}
if (socket_not_zero(SOCK_DENSITY_ID) && socket_not_white(SOCK_ABSORPTION_COLOR_ID)) {
GPU_material_flag_set(mat, GPU_MATFLAG_VOLUME_ABSORPTION);
}
/* Get volume attributes. */
GPUNodeLink *density = nullptr, *color = nullptr, *temperature = nullptr;
@ -119,6 +148,17 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat,
GPU_constant(&layer));
}
#undef SOCK_COLOR_ID
#undef SOCK_COLOR_ATTR_ID
#undef SOCK_DENSITY_ID
#undef SOCK_DENSITY_ATTR_ID
#undef SOCK_ANISOTROPY_ID
#undef SOCK_ABSORPTION_COLOR_ID
#undef SOCK_EMISSION_ID
#undef SOCK_EMISSION_COLOR_ID
#undef SOCK_BLACKBODY_INTENSITY_ID
#undef SOCK_BLACKBODY_TINT_ID
} // namespace blender::nodes::node_shader_volume_principled_cc
/* node type definition */

View File

@ -9,7 +9,9 @@ namespace blender::nodes::node_shader_volume_scatter_cc {
static void node_declare(NodeDeclarationBuilder &b)
{
b.add_input<decl::Color>("Color").default_value({0.8f, 0.8f, 0.8f, 1.0f});
#define SOCK_COLOR_ID 0
b.add_input<decl::Float>("Density").default_value(1.0f).min(0.0f).max(1000.0f);
#define SOCK_DENSITY_ID 1
b.add_input<decl::Float>("Anisotropy")
.default_value(0.0f)
.min(-1.0f)
@ -19,15 +21,29 @@ static void node_declare(NodeDeclarationBuilder &b)
b.add_output<decl::Shader>("Volume").translation_context(BLT_I18NCONTEXT_ID_ID);
}
#define socket_not_zero(sock) (in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f))
#define socket_not_black(sock) \
(in[sock].link || (clamp_f(in[sock].vec[0], 0.0f, 1.0f) > 1e-5f && \
clamp_f(in[sock].vec[1], 0.0f, 1.0f) > 1e-5f && \
clamp_f(in[sock].vec[2], 0.0f, 1.0f) > 1e-5f))
static int node_shader_gpu_volume_scatter(GPUMaterial *mat,
bNode *node,
bNodeExecData * /*execdata*/,
GPUNodeStack *in,
GPUNodeStack *out)
{
if (socket_not_zero(SOCK_DENSITY_ID) && socket_not_black(SOCK_COLOR_ID)) {
/* Consider there is absorption phenomenon when there is scattering since
* `extinction = scattering + absorption`. */
GPU_material_flag_set(mat, GPU_MATFLAG_VOLUME_SCATTER | GPU_MATFLAG_VOLUME_ABSORPTION);
}
return GPU_stack_link(mat, node, "node_volume_scatter", in, out);
}
#undef SOCK_COLOR_ID
#undef SOCK_DENSITY_ID
} // namespace blender::nodes::node_shader_volume_scatter_cc
/* node type definition */

View File

@ -34,6 +34,7 @@ set(SRC
gpu_py_uniformbuffer.cc
gpu_py_vertex_buffer.cc
gpu_py_vertex_format.cc
gpu_py_compute.cc
gpu_py.h
gpu_py_api.h
@ -53,6 +54,7 @@ set(SRC
gpu_py_uniformbuffer.h
gpu_py_vertex_buffer.h
gpu_py_vertex_format.h
gpu_py_compute.h
)
set(LIB

View File

@ -22,6 +22,7 @@
#include "gpu_py_select.h"
#include "gpu_py_state.h"
#include "gpu_py_types.h"
#include "gpu_py_compute.h"
#include "gpu_py.h"
#include "gpu_py_api.h" /* Own include. */
@ -77,6 +78,9 @@ PyObject *BPyInit_gpu()
PyModule_AddObject(mod, "texture", (submodule = bpygpu_texture_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
PyModule_AddObject(mod, "compute", (submodule = bpygpu_compute_init()));
PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule);
return mod;
}

View File

@ -230,6 +230,48 @@ static PyObject *pygpu_hdr_support_get(PyObject * /*self*/)
return PyBool_FromLong(GPU_hdr_support());
}
PyDoc_STRVAR(pygpu_max_work_group_count_get_doc,
".. function:: max_work_group_count_get(index)\n"
"\n"
" Get maximum number of work groups that may be dispatched to a compute shader.\n"
"\n"
" :arg index: Index of the dimension.\n"
" :type index: int\n"
" :return: Maximum number of work groups for the queried dimension.\n"
" :rtype: int\n");
static PyObject *pygpu_max_work_group_count_get(PyObject * /*self*/, PyObject *args)
{
int index;
if (!PyArg_ParseTuple(args, "i", &index)) {
return nullptr;
}
const int max_work_group_count = GPU_max_work_group_count(index);
return PyLong_FromLong(max_work_group_count);
}
PyDoc_STRVAR(pygpu_max_work_group_size_get_doc,
".. function:: max_work_group_size_get(index)\n"
"\n"
" Get maximum size of a work group that may be dispatched to a compute shader.\n"
"\n"
" :arg index: Index of the dimension.\n"
" :type index: int\n"
" :return: Maximum size of a work group for the queried dimension.\n"
" :rtype: int\n");
static PyObject *pygpu_max_work_group_size_get(PyObject * /*self*/, PyObject *args)
{
int index;
if (!PyArg_ParseTuple(args, "i", &index)) {
return nullptr;
}
const int max_work_group_size = GPU_max_work_group_size(index);
return PyLong_FromLong(max_work_group_size);
}
/** \} */
/* -------------------------------------------------------------------- */
@ -304,7 +346,16 @@ static PyMethodDef pygpu_capabilities__tp_methods[] = {
(PyCFunction)pygpu_hdr_support_get,
METH_NOARGS,
pygpu_hdr_support_get_doc},
{"max_work_group_count_get",
(PyCFunction)pygpu_max_work_group_count_get,
METH_VARARGS,
pygpu_max_work_group_count_get_doc,
},
{"max_work_group_size_get",
(PyCFunction)pygpu_max_work_group_size_get,
METH_VARARGS,
pygpu_max_work_group_size_get_doc,
},
{nullptr, nullptr, 0, nullptr},
};

View File

@ -0,0 +1,145 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bpygpu
*
* - Use `bpygpu_` for local API.
* - Use `BPyGPU` for public API.
*/
#include <Python.h>
#include "BLI_utildefines.h"
#include "GPU_shader.h"
#include "GPU_texture.h"
#include "GPU_uniform_buffer.h"
#include "GPU_compute.h"
#include "GPU_state.h"
#include "GPU_capabilities.h"
#include "../generic/py_capi_utils.h"
#include "../generic/python_compat.h"
#include "../generic/python_utildefines.h"
#include "../mathutils/mathutils.h"
#include "gpu_py.h"
#include "gpu_py_texture.h"
#include "gpu_py_uniformbuffer.h"
#include "gpu_py_vertex_format.h"
#include "gpu_py_shader.h"
#include "gpu_py_compute.h" /* own include */
PyDoc_STRVAR(
pygpu_compute_dispatch_doc,
".. function:: dispatch(shader, groups_x_len, groups_y_len, groups_z_len)\n"
"\n"
" Dispatches GPU compute.\n"
"\n"
" :arg shader: The shader that you want to dispatch.\n"
" :type shader: :class:`gpu.types.GPUShader`\n"
" :arg groups_x_len: Int for group x length:\n"
" :type groups_x_len: int\n"
" :arg groups_y_len: Int for group y length:\n"
" :type groups_y_len: int\n"
" :arg groups_z_len: Int for group z length:\n"
" :type groups_z_len: int\n"
" :return: Shader object.\n"
" :rtype: :class:`bpy.types.GPUShader`\n");
static PyObject *pygpu_compute_dispatch(PyObject * /*self*/, PyObject *args, PyObject *kwds)
{
BPyGPUShader *py_shader;
int groups_x_len;
int groups_y_len;
int groups_z_len;
static const char *_keywords[] = {"shader", "groups_x_len", "groups_y_len", "groups_z_len", nullptr};
static _PyArg_Parser _parser = {
PY_ARG_PARSER_HEAD_COMPAT()
"O" /* `shader` */
"i" /* `groups_x_len` */
"i" /* `groups_y_len` */
"i" /* `groups_z_len` */
":dispatch",
_keywords,
nullptr,
};
if (_PyArg_ParseTupleAndKeywordsFast(args,
kwds,
&_parser,
&py_shader,
&groups_x_len,
&groups_y_len,
&groups_z_len))
{
if (!BPyGPUShader_Check(py_shader)) {
PyErr_Format(PyExc_TypeError, "Expected a GPUShader, got %s", Py_TYPE(py_shader)->tp_name);
return nullptr;
}
// Check that groups do not exceed GPU_max_work_group_count()
const int max_work_group_count_x = GPU_max_work_group_count(0);
const int max_work_group_count_y = GPU_max_work_group_count(1);
const int max_work_group_count_z = GPU_max_work_group_count(2);
// Report back to the user both the requested and the maximum supported value
if (groups_x_len > GPU_max_work_group_count(0)) {
PyErr_Format(PyExc_ValueError, "groups_x_len (%d) exceeds maximum supported value (max work group count: %d)", groups_x_len, max_work_group_count_x);
return nullptr;
}
if (groups_y_len > GPU_max_work_group_count(1)) {
PyErr_Format(PyExc_ValueError, "groups_y_len (%d) exceeds maximum supported value (max work group count: %d)", groups_y_len, max_work_group_count_y);
return nullptr;
}
if (groups_z_len > GPU_max_work_group_count(2)) {
PyErr_Format(PyExc_ValueError, "groups_z_len (%d) exceeds maximum supported value (max work group count: %d)", groups_z_len, max_work_group_count_z);
return nullptr;
}
GPUShader *shader = py_shader->shader;
GPU_compute_dispatch(shader, groups_x_len, groups_y_len, groups_z_len);
GPU_memory_barrier(GPU_BARRIER_TEXTURE_FETCH | GPU_BARRIER_SHADER_IMAGE_ACCESS);
}
Py_RETURN_NONE;
}
/* -------------------------------------------------------------------- */
/** \name Module
* \{ */
static PyMethodDef pygpu_compute__tp_methods[] = {
{"dispatch", (PyCFunction)pygpu_compute_dispatch, METH_VARARGS | METH_KEYWORDS, pygpu_compute_dispatch_doc},
{nullptr, nullptr, 0, nullptr},
};
#if (defined(__GNUC__) && !defined(__clang__))
# pragma GCC diagnostic pop
#endif
PyDoc_STRVAR(pygpu_compute__tp_doc, "This module provides access to the global GPU compute functions");
static PyModuleDef pygpu_compute_module_def = {
/*m_base*/ PyModuleDef_HEAD_INIT,
/*m_name*/ "gpu.compute",
/*m_doc*/ pygpu_compute__tp_doc,
/*m_size*/ 0,
/*m_methods*/ pygpu_compute__tp_methods,
/*m_slots*/ nullptr,
/*m_traverse*/ nullptr,
/*m_clear*/ nullptr,
/*m_free*/ nullptr,
};
PyObject *bpygpu_compute_init()
{
PyObject *submodule;
submodule = bpygpu_create_module(&pygpu_compute_module_def);
return submodule;
}
/** \} */

View File

@ -0,0 +1,19 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bpygpu
*/
#pragma once
#ifdef __cplusplus
extern "C" {
#endif
PyObject *bpygpu_compute_init(void);
#ifdef __cplusplus
}
#endif

View File

@ -550,6 +550,38 @@ static PyObject *pygpu_shader_uniform_sampler(BPyGPUShader *self, PyObject *args
Py_RETURN_NONE;
}
PyDoc_STRVAR(pygpu_shader_image_doc,
".. method:: image(name, texture)\n"
"\n"
" Specify the value of an image variable for the current GPUShader.\n"
"\n"
" :arg name: Name of the image variable to which the texture is to be bound.\n"
" :type name: str\n"
" :arg texture: Texture to attach.\n"
" :type texture: :class:`gpu.types.GPUTexture`\n");
static PyObject *pygpu_shader_image(BPyGPUShader *self, PyObject *args)
{
const char *name;
BPyGPUTexture *py_texture;
if (!PyArg_ParseTuple(
args, "sO!:GPUShader.image", &name, &BPyGPUTexture_Type, &py_texture))
{
return nullptr;
}
GPU_shader_bind(self->shader);
int image_unit = GPU_shader_get_sampler_binding(self->shader, name);
if (image_unit == -1) {
PyErr_Format(PyExc_ValueError, "Image '%s' not found in shader", name);
return nullptr;
}
GPU_texture_image_bind(py_texture->tex, image_unit);
Py_RETURN_NONE;
}
PyDoc_STRVAR(
pygpu_shader_uniform_block_doc,
".. method:: uniform_block(name, ubo)\n"
@ -700,6 +732,10 @@ static PyMethodDef pygpu_shader__tp_methods[] = {
(PyCFunction)pygpu_shader_uniform_sampler,
METH_VARARGS,
pygpu_shader_uniform_sampler_doc},
{"image",
(PyCFunction)pygpu_shader_image,
METH_VARARGS,
pygpu_shader_image_doc},
{"uniform_block",
(PyCFunction)pygpu_shader_uniform_block,
METH_VARARGS,

View File

@ -60,6 +60,7 @@ typedef struct BPyGPUShaderCreateInfo {
/* Just to keep a user to prevent freeing buf's we're using. */
PyObject *vertex_source;
PyObject *fragment_source;
PyObject *compute_source;
PyObject *typedef_source;
PyObject *references;
#endif

View File

@ -20,8 +20,9 @@
#include "../generic/python_compat.h"
#include "gpu_py_shader.h" /* own include */
#include "gpu_py_texture.h"
//#define USE_PYGPU_SHADER_INFO_IMAGE_METHOD
#define USE_PYGPU_SHADER_INFO_IMAGE_METHOD
using blender::gpu::shader::DualBlend;
using blender::gpu::shader::Frequency;
@ -156,6 +157,53 @@ static const PyC_StringEnumItems pygpu_dualblend_items[] = {
{0, nullptr},
};
#define PYDOC_TEX_FORMAT_ITEMS \
" - ``RGBA8UI``\n" \
" - ``RGBA8I``\n" \
" - ``RGBA8``\n" \
" - ``RGBA32UI``\n" \
" - ``RGBA32I``\n" \
" - ``RGBA32F``\n" \
" - ``RGBA16UI``\n" \
" - ``RGBA16I``\n" \
" - ``RGBA16F``\n" \
" - ``RGBA16``\n" \
" - ``RG8UI``\n" \
" - ``RG8I``\n" \
" - ``RG8``\n" \
" - ``RG32UI``\n" \
" - ``RG32I``\n" \
" - ``RG32F``\n" \
" - ``RG16UI``\n" \
" - ``RG16I``\n" \
" - ``RG16F``\n" \
" - ``RG16``\n" \
" - ``R8UI``\n" \
" - ``R8I``\n" \
" - ``R8``\n" \
" - ``R32UI``\n" \
" - ``R32I``\n" \
" - ``R32F``\n" \
" - ``R16UI``\n" \
" - ``R16I``\n" \
" - ``R16F``\n" \
" - ``R16``\n" \
" - ``R11F_G11F_B10F``\n" \
" - ``DEPTH32F_STENCIL8``\n" \
" - ``DEPTH24_STENCIL8``\n" \
" - ``SRGB8_A8``\n" \
" - ``RGB16F``\n" \
" - ``SRGB8_A8_DXT1``\n" \
" - ``SRGB8_A8_DXT3``\n" \
" - ``SRGB8_A8_DXT5``\n" \
" - ``RGBA8_DXT1``\n" \
" - ``RGBA8_DXT3``\n" \
" - ``RGBA8_DXT5``\n" \
" - ``DEPTH_COMPONENT32F``\n" \
" - ``DEPTH_COMPONENT24``\n" \
" - ``DEPTH_COMPONENT16``\n"
extern const PyC_StringEnumItems pygpu_tex_format_items[];
/* -------------------------------------------------------------------- */
/** \name GPUStageInterfaceInfo Methods
* \{ */
@ -607,7 +655,7 @@ PyDoc_STRVAR(
" :arg slot: The image resource index.\n"
" :type slot: int\n"
" :arg format: The GPUTexture format that is passed to the shader. Possible values are:\n"
"" PYDOC_TEX_FORMAT_ITEMS
"\n" PYDOC_TEX_FORMAT_ITEMS
" :type format: str\n"
" :arg type: The data type describing how the image is to be read in the shader. "
"Possible values are:\n"
@ -902,6 +950,51 @@ static PyObject *pygpu_shader_info_vertex_source(BPyGPUShaderCreateInfo *self, P
Py_RETURN_NONE;
}
PyDoc_STRVAR(
pygpu_shader_info_compute_source_doc,
".. method:: compute_source(source)\n"
"\n"
" compute shader source code written in GLSL.\n"
"\n"
" Example:\n"
"\n"
" .. code-block:: python\n"
"\n"
" \"\"\"void main() {\n"
" int2 index = int2(gl_GlobalInvocationID.xy);\n"
" vec4 color = vec4(0.0, 0.0, 0.0, 1.0);\n"
" imageStore(img_output, index, color);\n"
" }\"\"\"\n"
"\n"
" :arg source: The compute shader source code.\n"
" :type source: str\n"
"\n"
" .. seealso:: `GLSL Cross Compilation "
"<https://wiki.blender.org/wiki/EEVEE_%26_Viewport/GPU_Module/GLSL_Cross_Compilation>`__\n");
static PyObject *pygpu_shader_info_compute_source(BPyGPUShaderCreateInfo *self, PyObject *o)
{
const char *compute_source = PyUnicode_AsUTF8(o);
if (compute_source == nullptr) {
PyErr_Format(PyExc_ValueError, "expected a string, got %s", Py_TYPE(o)->tp_name);
return nullptr;
}
#ifdef USE_GPU_PY_REFERENCES
if (self->compute_source) {
Py_DECREF(self->compute_source);
}
self->compute_source = o;
Py_INCREF(o);
#endif
ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
info->compute_source("common_colormanagement_lib.glsl");
info->compute_source_generated = compute_source;
Py_RETURN_NONE;
}
PyDoc_STRVAR(
pygpu_shader_info_fragment_source_doc,
".. method:: fragment_source(source)\n"
@ -1025,6 +1118,31 @@ static PyObject *pygpu_shader_info_define(BPyGPUShaderCreateInfo *self, PyObject
Py_RETURN_NONE;
}
PyDoc_STRVAR(pygpu_shader_info_local_group_size_doc,
".. method:: local_group_size(x, y=-1, z=-1)\n"
"\n"
" Specify the local group size for compute shaders.\n"
"\n"
" :arg x: The local group size in the x dimension.\n"
" :type x: int\n"
" :arg y: The local group size in the y dimension. Optional. Defaults to -1.\n"
" :type y: int\n"
" :arg z: The local group size in the z dimension. Optional. Defaults to -1.\n"
" :type z: int\n");
static PyObject *pygpu_shader_info_local_group_size(BPyGPUShaderCreateInfo *self, PyObject *args)
{
int x = -1, y = -1, z = -1;
if (!PyArg_ParseTuple(args, "i|ii:local_group_size", &x, &y, &z)) {
return nullptr;
}
ShaderCreateInfo *info = reinterpret_cast<ShaderCreateInfo *>(self->info);
info->local_group_size(x, y, z);
Py_RETURN_NONE;
}
static PyMethodDef pygpu_shader_info__tp_methods[] = {
{"vertex_in",
(PyCFunction)pygpu_shader_info_vertex_in,
@ -1064,11 +1182,19 @@ static PyMethodDef pygpu_shader_info__tp_methods[] = {
(PyCFunction)pygpu_shader_info_fragment_source,
METH_O,
pygpu_shader_info_fragment_source_doc},
{"compute_source",
(PyCFunction)pygpu_shader_info_compute_source,
METH_O,
pygpu_shader_info_compute_source_doc},
{"typedef_source",
(PyCFunction)pygpu_shader_info_typedef_source,
METH_O,
pygpu_shader_info_typedef_source_doc},
{"define", (PyCFunction)pygpu_shader_info_define, METH_VARARGS, pygpu_shader_info_define_doc},
{"local_group_size",
(PyCFunction)pygpu_shader_info_local_group_size,
METH_VARARGS,
pygpu_shader_info_local_group_size_doc},
{nullptr, nullptr, 0, nullptr},
};
@ -1098,6 +1224,7 @@ static int pygpu_shader_info__tp_traverse(PyObject *self, visitproc visit, void
BPyGPUShaderCreateInfo *py_info = reinterpret_cast<BPyGPUShaderCreateInfo *>(self);
Py_VISIT(py_info->vertex_source);
Py_VISIT(py_info->fragment_source);
Py_VISIT(py_info->compute_source);
Py_VISIT(py_info->references);
return 0;
}
@ -1107,6 +1234,7 @@ static int pygpu_shader_info__tp_clear(PyObject *self)
BPyGPUShaderCreateInfo *py_info = reinterpret_cast<BPyGPUShaderCreateInfo *>(self);
Py_CLEAR(py_info->vertex_source);
Py_CLEAR(py_info->fragment_source);
Py_CLEAR(py_info->compute_source);
Py_CLEAR(py_info->references);
return 0;
}
@ -1125,8 +1253,10 @@ static void pygpu_shader_info__tp_dealloc(PyObject *self)
pygpu_shader_info__tp_clear(self);
Py_XDECREF(py_info->vertex_source);
Py_XDECREF(py_info->fragment_source);
Py_XDECREF(py_info->compute_source);
Py_XDECREF(py_info->references);
}
#endif
Py_TYPE(self)->tp_free((PyObject *)self);
@ -1231,6 +1361,7 @@ PyObject *BPyGPUShaderCreateInfo_CreatePyObject(GPUShaderCreateInfo *info)
self = (BPyGPUShaderCreateInfo *)_PyObject_GC_New(&BPyGPUShaderCreateInfo_Type);
self->vertex_source = nullptr;
self->fragment_source = nullptr;
self->compute_source = nullptr;
self->typedef_source = nullptr;
self->references = PyList_New(0);
#else

View File

@ -34,7 +34,7 @@
/** \name GPUTexture Common Utilities
* \{ */
static const PyC_StringEnumItems pygpu_textureformat_items[] = {
const PyC_StringEnumItems pygpu_textureformat_items[] = {
{GPU_RGBA8UI, "RGBA8UI"},
{GPU_RGBA8I, "RGBA8I"},
{GPU_RGBA8, "RGBA8"},

View File

@ -15,6 +15,7 @@ extern "C" {
#endif
extern PyTypeObject BPyGPUTexture_Type;
extern const struct PyC_StringEnumItems pygpu_textureformat_items[];
#define BPyGPUTexture_Check(v) (Py_TYPE(v) == &BPyGPUTexture_Type)

View File

@ -19,6 +19,7 @@
#include "gpu_py_uniformbuffer.h"
#include "gpu_py_vertex_buffer.h"
#include "gpu_py_vertex_format.h"
#include "gpu_py_compute.h"
#ifdef __cplusplus
extern "C" {

View File

@ -1430,14 +1430,14 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
*/
const bool is_rendering = G.is_rendering;
const bool is_background = G.background;
const bool do_seq_gl = is_rendering ? false : (context->scene->r.seq_prev_type) != OB_RENDER;
bool do_seq_gl = !context->for_render && (context->scene->r.seq_prev_type) != OB_RENDER &&
BLI_thread_is_main();
bool have_comp = false;
bool use_gpencil = true;
/* do we need to re-evaluate the frame after rendering? */
bool is_frame_update = false;
Scene *scene;
int is_thread_main = BLI_thread_is_main();
/* don't refer to seq->scene above this point!, it can be nullptr */
if (seq->scene == nullptr) {
@ -1498,7 +1498,7 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
is_frame_update = (orig_data.timeline_frame != scene->r.cfra) ||
(orig_data.subframe != scene->r.subframe);
if ((sequencer_view3d_fn && do_seq_gl && camera) && is_thread_main) {
if ((sequencer_view3d_fn && do_seq_gl && camera)) {
char err_out[256] = "unknown";
int width, height;
BKE_render_resolution(&scene->r, false, &width, &height);
@ -1544,37 +1544,40 @@ static ImBuf *seq_render_scene_strip(const SeqRenderData *context,
const int totviews = BKE_scene_multiview_num_views_get(&scene->r);
ImBuf **ibufs_arr;
ibufs_arr = static_cast<ImBuf **>(
MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"));
/* XXX: this if can be removed when sequence preview rendering uses the job system
/*
* XXX: this if can be removed when sequence preview rendering uses the job system
*
* disable rendered preview for sequencer while rendering -- it's very much possible
* that preview render will went into conflict with final render
* Disable rendered preview for sequencer while rendering - invoked render job will
* conflict with already running render
*
* When rendering from command line renderer is called from main thread, in this
* case it's always safe to render scene here
*/
if (!is_thread_main || is_rendering == false || is_background || context->for_render) {
if (re == nullptr) {
re = RE_NewSceneRender(scene);
}
const float subframe = frame - floorf(frame);
RE_RenderFrame(re,
context->bmain,
scene,
have_comp ? nullptr : view_layer,
camera,
floorf(frame),
subframe,
false);
/* restore previous state after it was toggled on & off by RE_RenderFrame */
G.is_rendering = is_rendering;
if (!context->for_render && (is_rendering && !G.background)) {
goto finally;
}
ibufs_arr = static_cast<ImBuf **>(
MEM_callocN(sizeof(ImBuf *) * totviews, "Sequence Image Views Imbufs"));
if (re == nullptr) {
re = RE_NewSceneRender(scene);
}
const float subframe = frame - floorf(frame);
RE_RenderFrame(re,
context->bmain,
scene,
have_comp ? nullptr : view_layer,
camera,
floorf(frame),
subframe,
false);
/* restore previous state after it was toggled on & off by RE_RenderFrame */
G.is_rendering = is_rendering;
for (int view_id = 0; view_id < totviews; view_id++) {
SeqRenderData localcontext = *context;
RenderResult rres;

View File

@ -531,8 +531,7 @@ SeqRetimingKey *SEQ_retiming_add_transition(const Scene *scene,
SeqRetimingKey *prev_key = key - 1;
if ((key->flag & SEQ_SPEED_TRANSITION_IN) != 0 ||
(prev_key->flag & SEQ_SPEED_TRANSITION_IN) != 0)
{
(prev_key->flag & SEQ_SPEED_TRANSITION_IN) != 0) {
return nullptr;
}