GPv3: Lock unselect materials operator #115278
|
@ -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"
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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')
|
|
@ -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> {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
});
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -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();
|
||||
};
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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). */
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
||||
/** \} */
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 = ®ion->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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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(®ion->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(®ion->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 = ®ion->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 = ®ion->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);
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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));
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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},
|
||||
};
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
/** \} */
|
|
@ -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
|
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"},
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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" {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue