diff options
author | Michael Kowalski <makowalski@nvidia.com> | 2022-01-07 02:02:02 +0300 |
---|---|---|
committer | Michael Kowalski <makowalski@nvidia.com> | 2022-01-07 02:02:02 +0300 |
commit | 442b8e3dcdbe200d9ac449a07a89726a3329ac14 (patch) | |
tree | 10af735a2d0c6aee1c321a372940387bc590f391 | |
parent | 18bf798dc6032f67c247f0b64e246e94a88f3f5f (diff) | |
parent | 3e92b4ed2408eacd126c0deb7790891025b2c075 (diff) |
Merge remote-tracking branch 'origin/master' into temp-usd-preview-surf-export
974 files changed, 29442 insertions, 15564 deletions
diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 24294df14ed..c38973b274f 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -2083,9 +2083,9 @@ compile_OIIO() { cmake_d="$cmake_d -D OPENEXR_VERSION=$OPENEXR_VERSION" if [ "$_with_built_openexr" = true ]; then - cmake_d="$cmake_d -D ILMBASE_HOME=$INST/openexr" - cmake_d="$cmake_d -D OPENEXR_HOME=$INST/openexr" - INFO "ILMBASE_HOME=$INST/openexr" + cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr" + cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr" + INFO "Ilmbase_ROOT=$INST/openexr" fi # ptex is only needed when nicholas bishop is ready @@ -2374,9 +2374,9 @@ compile_OSL() { #~ cmake_d="$cmake_d -D ILMBASE_VERSION=$ILMBASE_VERSION" if [ "$_with_built_openexr" = true ]; then - INFO "ILMBASE_HOME=$INST/openexr" - cmake_d="$cmake_d -D OPENEXR_ROOT_DIR=$INST/openexr" - cmake_d="$cmake_d -D ILMBASE_ROOT_DIR=$INST/openexr" + cmake_d="$cmake_d -D ILMBASE_ROOT=$INST/openexr" + cmake_d="$cmake_d -D OPENEXR_ROOT=$INST/openexr" + INFO "Ilmbase_ROOT=$INST/openexr" # XXX Temp workaround... sigh, ILMBase really messed the things up by defining their custom names ON by default :( fi @@ -5801,7 +5801,7 @@ print_info() { PRINT "If you're using CMake add this to your configuration flags:" _buildargs="-U *SNDFILE* -U PYTHON* -U *BOOST* -U *Boost* -U *TBB*" - _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CYCLES*" + _buildargs="$_buildargs -U *OPENCOLORIO* -U *OPENEXR* -U *OPENIMAGEIO* -U *LLVM* -U *CLANG* -U *CYCLES*" _buildargs="$_buildargs -U *OPENSUBDIV* -U *OPENVDB* -U *BLOSC* -U *COLLADA* -U *FFMPEG* -U *ALEMBIC* -U *USD*" _buildargs="$_buildargs -U *EMBREE* -U *OPENIMAGEDENOISE* -U *OPENXR*" diff --git a/build_files/build_environment/patches/usd.diff b/build_files/build_environment/patches/usd.diff index dc4982ad114..8ea1e2054c1 100644 --- a/build_files/build_environment/patches/usd.diff +++ b/build_files/build_environment/patches/usd.diff @@ -197,3 +197,38 @@ index 67ec0d15f..6dc3e85a0 100644 #else #error Unknown architecture. #endif + +diff --git a/pxr/base/arch/demangle.cpp b/pxr/base/arch/demangle.cpp +index 67ec0d15f..6dc3e85a0 100644 +--- a/pxr/base/arch/demangle.cpp ++++ b/pxr/base/arch/demangle.cpp +@@ -36,6 +36,7 @@ + #if (ARCH_COMPILER_GCC_MAJOR == 3 && ARCH_COMPILER_GCC_MINOR >= 1) || \ + ARCH_COMPILER_GCC_MAJOR > 3 || defined(ARCH_COMPILER_CLANG) + #define _AT_LEAST_GCC_THREE_ONE_OR_CLANG ++#include <cxxabi.h> + #endif + + PXR_NAMESPACE_OPEN_SCOPE +@@ -138,7 +139,6 @@ + #endif + + #if defined(_AT_LEAST_GCC_THREE_ONE_OR_CLANG) +-#include <cxxabi.h> + + /* + * This routine doesn't work when you get to gcc3.4. + +diff --git a/pxr/base/work/singularTask.h b/pxr/base/work/singularTask.h +index 67ec0d15f..6dc3e85a0 100644 +--- a/pxr/base/work/singularTask.h ++++ b/pxr/base/work/singularTask.h +@@ -120,7 +120,7 @@ + // case we go again to ensure the task can do whatever it + // was awakened to do. Once we successfully take the count + // to zero, we stop. +- size_t old = count; ++ std::size_t old = count; + do { _fn(); } while ( + !count.compare_exchange_strong(old, 0)); + }); diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index bb17cfdcb45..5e2b700427a 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -1086,40 +1086,6 @@ static void create_subd_mesh(Scene *scene, /* Sync */ -/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes - * things like velocity from cache modifier, fluid simulation). - * - * NOTE: This code is run prior to object motion blur initialization. so can not access properties - * set by `sync_object_motion_init()`. */ -static bool mesh_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene) -{ - const Scene::MotionType need_motion = scene->need_motion(); - if (need_motion == Scene::MOTION_NONE) { - /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related - * attributes. */ - return false; - } - - if (need_motion == Scene::MOTION_BLUR) { - /* A bit tricky and implicit case: - * - Motion blur is enabled in the scene, which implies specific number of time steps for - * objects. - * - If the object has motion blur disabled on it, it will have 0 time steps. - * - Motion attribute expects non-zero time steps. - * - * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */ - PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles"); - const bool use_motion = get_boolean(cobject, "use_motion_blur"); - if (!use_motion) { - return false; - } - } - - /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object - * level. */ - return true; -} - void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, Mesh *mesh) { /* make a copy of the shaders as the caller in the main thread still need them for syncing the @@ -1144,7 +1110,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M if (b_mesh) { /* Motion blur attribute is relative to seconds, we need it relative to frames. */ - const bool need_motion = mesh_need_motion_attribute(b_ob_info, scene); + const bool need_motion = object_need_motion_attribute(b_ob_info, scene); const float motion_scale = (need_motion) ? scene->motion_shutter_time() / (b_scene.render().fps() / b_scene.render().fps_base()) : diff --git a/intern/cycles/blender/pointcloud.cpp b/intern/cycles/blender/pointcloud.cpp index a9e616a468f..a69c4f6eca3 100644 --- a/intern/cycles/blender/pointcloud.cpp +++ b/intern/cycles/blender/pointcloud.cpp @@ -37,12 +37,52 @@ static void fill_generic_attribute(BL::PointCloud &b_pointcloud, } } -static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud) +static void attr_create_motion(PointCloud *pointcloud, + BL::Attribute &b_attribute, + const float motion_scale) +{ + if (!(b_attribute.domain() == BL::Attribute::domain_POINT) && + (b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR)) { + return; + } + + BL::FloatVectorAttribute b_vector_attribute(b_attribute); + const int num_points = pointcloud->get_points().size(); + + /* Find or add attribute */ + float3 *P = &pointcloud->get_points()[0]; + Attribute *attr_mP = pointcloud->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (!attr_mP) { + attr_mP = pointcloud->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + const float relative_time = motion_times[step] * 0.5f * motion_scale; + float3 *mP = attr_mP->data_float3() + step * num_points; + + for (int i = 0; i < num_points; i++) { + mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; + } + } +} + +static void copy_attributes(PointCloud *pointcloud, + BL::PointCloud b_pointcloud, + const bool need_motion, + const float motion_scale) { AttributeSet &attributes = pointcloud->attributes; + static const ustring u_velocity("velocity"); for (BL::Attribute &b_attribute : b_pointcloud.attributes) { const ustring name{b_attribute.name().c_str()}; + if (need_motion && name == u_velocity) { + attr_create_motion(pointcloud, b_attribute, motion_scale); + } + if (attributes.find(name)) { continue; } @@ -111,7 +151,11 @@ static void copy_attributes(PointCloud *pointcloud, BL::PointCloud b_pointcloud) } } -static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointCloud b_pointcloud) +static void export_pointcloud(Scene *scene, + PointCloud *pointcloud, + BL::PointCloud b_pointcloud, + const bool need_motion, + const float motion_scale) { /* TODO: optimize so we can straight memcpy arrays from Blender? */ @@ -141,7 +185,7 @@ static void export_pointcloud(Scene *scene, PointCloud *pointcloud, BL::PointClo } /* Export attributes */ - copy_attributes(pointcloud, b_pointcloud); + copy_attributes(pointcloud, b_pointcloud, need_motion, motion_scale); } static void export_pointcloud_motion(PointCloud *pointcloud, @@ -193,7 +237,7 @@ static void export_pointcloud_motion(PointCloud *pointcloud, } /* Export attributes */ - copy_attributes(pointcloud, b_pointcloud); + copy_attributes(pointcloud, b_pointcloud, false, 0.0f); } void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info) @@ -207,7 +251,13 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info /* TODO: add option to filter out points in the view layer. */ BL::PointCloud b_pointcloud(b_ob_info.object_data); - export_pointcloud(scene, &new_pointcloud, b_pointcloud); + /* Motion blur attribute is relative to seconds, we need it relative to frames. */ + const bool need_motion = object_need_motion_attribute(b_ob_info, scene); + const float motion_scale = (need_motion) ? + scene->motion_shutter_time() / + (b_scene.render().fps() / b_scene.render().fps_base()) : + 0.0f; + export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale); /* update original sockets */ for (const SocketType &socket : new_pointcloud.type->inputs) { diff --git a/intern/cycles/blender/python.cpp b/intern/cycles/blender/python.cpp index 024dae306b0..f509d5c2eeb 100644 --- a/intern/cycles/blender/python.cpp +++ b/intern/cycles/blender/python.cpp @@ -735,27 +735,20 @@ static bool image_parse_filepaths(PyObject *pyfilepaths, vector<string> &filepat static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *keywords) { -#if 1 - (void)args; - (void)keywords; -#else static const char *keyword_list[] = { - "preferences", "scene", "view_layer", "input", "output", "tile_size", "samples", NULL}; + "preferences", "scene", "view_layer", "input", "output", NULL}; PyObject *pypreferences, *pyscene, *pyviewlayer; PyObject *pyinput, *pyoutput = NULL; - int tile_size = 0, samples = 0; if (!PyArg_ParseTupleAndKeywords(args, keywords, - "OOOO|Oii", + "OOOO|O", (char **)keyword_list, &pypreferences, &pyscene, &pyviewlayer, &pyinput, - &pyoutput, - &tile_size, - &samples)) { + &pyoutput)) { return NULL; } @@ -777,14 +770,10 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key &RNA_ViewLayer, PyLong_AsVoidPtr(pyviewlayer), &viewlayerptr); - PointerRNA cviewlayer = RNA_pointer_get(&viewlayerptr, "cycles"); + BL::ViewLayer b_view_layer(viewlayerptr); - DenoiseParams params; - params.radius = get_int(cviewlayer, "denoising_radius"); - params.strength = get_float(cviewlayer, "denoising_strength"); - params.feature_strength = get_float(cviewlayer, "denoising_feature_strength"); - params.relative_pca = get_boolean(cviewlayer, "denoising_relative_pca"); - params.neighbor_frames = get_int(cviewlayer, "denoising_neighbor_frames"); + DenoiseParams params = BlenderSync::get_denoise_params(b_scene, b_view_layer, true); + params.use = true; /* Parse file paths list. */ vector<string> input, output; @@ -812,24 +801,15 @@ static PyObject *denoise_func(PyObject * /*self*/, PyObject *args, PyObject *key } /* Create denoiser. */ - DenoiserPipeline denoiser(device); - denoiser.params = params; + DenoiserPipeline denoiser(device, params); denoiser.input = input; denoiser.output = output; - if (tile_size > 0) { - denoiser.tile_size = make_int2(tile_size, tile_size); - } - if (samples > 0) { - denoiser.samples_override = samples; - } - /* Run denoiser. */ if (!denoiser.run()) { PyErr_SetString(PyExc_ValueError, denoiser.error.c_str()); return NULL; } -#endif Py_RETURN_NONE; } diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index 70acfce6891..5604c2989fd 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -776,7 +776,7 @@ static ShaderNode *add_node(Scene *scene, } else { ustring filename = ustring( - image_user_file_path(b_image_user, b_image, b_scene.frame_current(), true)); + image_user_file_path(b_image_user, b_image, b_scene.frame_current())); image->set_filename(filename); } } @@ -813,7 +813,7 @@ static ShaderNode *add_node(Scene *scene, } else { env->set_filename( - ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current(), false))); + ustring(image_user_file_path(b_image_user, b_image, b_scene.frame_current()))); } } node = env; diff --git a/intern/cycles/blender/sync.h b/intern/cycles/blender/sync.h index d074f90bb1b..3722b938863 100644 --- a/intern/cycles/blender/sync.h +++ b/intern/cycles/blender/sync.h @@ -105,11 +105,11 @@ class BlenderSync { static BufferParams get_buffer_params( BL::SpaceView3D &b_v3d, BL::RegionView3D &b_rv3d, Camera *cam, int width, int height); - private: static DenoiseParams get_denoise_params(BL::Scene &b_scene, BL::ViewLayer &b_view_layer, bool background); + private: /* sync */ void sync_lights(BL::Depsgraph &b_depsgraph, bool update_all); void sync_materials(BL::Depsgraph &b_depsgraph, bool update_all); diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h index be36bcdaaa8..59520b94d6f 100644 --- a/intern/cycles/blender/util.h +++ b/intern/cycles/blender/util.h @@ -18,6 +18,7 @@ #define __BLENDER_UTIL_H__ #include "scene/mesh.h" +#include "scene/scene.h" #include "util/algorithm.h" #include "util/array.h" @@ -33,7 +34,7 @@ extern "C" { void BKE_image_user_frame_calc(void *ima, void *iuser, int cfra); -void BKE_image_user_file_path(void *iuser, void *ima, char *path); +void BKE_image_user_file_path_ex(void *iuser, void *ima, char *path, bool resolve_udim); unsigned char *BKE_image_get_pixels_for_frame(void *image, int frame, int tile); float *BKE_image_get_float_pixels_for_frame(void *image, int frame, int tile); } @@ -290,25 +291,14 @@ static inline int render_resolution_y(BL::RenderSettings &b_render) return b_render.resolution_y() * b_render.resolution_percentage() / 100; } -static inline string image_user_file_path(BL::ImageUser &iuser, - BL::Image &ima, - int cfra, - bool load_tiled) +static inline string image_user_file_path(BL::ImageUser &iuser, BL::Image &ima, int cfra) { char filepath[1024]; iuser.tile(0); BKE_image_user_frame_calc(ima.ptr.data, iuser.ptr.data, cfra); - BKE_image_user_file_path(iuser.ptr.data, ima.ptr.data, filepath); + BKE_image_user_file_path_ex(iuser.ptr.data, ima.ptr.data, filepath, false); - string filepath_str = string(filepath); - if (load_tiled && ima.source() == BL::Image::source_TILED) { - string udim; - if (!ima.tiles.empty()) { - udim = to_string(ima.tiles[0].number()); - } - string_replace(filepath_str, udim, "<UDIM>"); - } - return filepath_str; + return string(filepath); } static inline int image_user_frame_number(BL::ImageUser &iuser, BL::Image &ima, int cfra) @@ -681,6 +671,40 @@ static inline uint object_ray_visibility(BL::Object &b_ob) return flag; } +/* Check whether some of "built-in" motion-related attributes are needed to be exported (includes + * things like velocity from cache modifier, fluid simulation). + * + * NOTE: This code is run prior to object motion blur initialization. so can not access properties + * set by `sync_object_motion_init()`. */ +static inline bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene) +{ + const Scene::MotionType need_motion = scene->need_motion(); + if (need_motion == Scene::MOTION_NONE) { + /* Simple case: neither motion pass nor motion blur is needed, no need in the motion related + * attributes. */ + return false; + } + + if (need_motion == Scene::MOTION_BLUR) { + /* A bit tricky and implicit case: + * - Motion blur is enabled in the scene, which implies specific number of time steps for + * objects. + * - If the object has motion blur disabled on it, it will have 0 time steps. + * - Motion attribute expects non-zero time steps. + * + * Avoid adding motion attributes if the motion blur will enforce 0 motion steps. */ + PointerRNA cobject = RNA_pointer_get(&b_ob_info.real_object.ptr, "cycles"); + const bool use_motion = get_boolean(cobject, "use_motion_blur"); + if (!use_motion) { + return false; + } + } + + /* Motion pass which implies 3 motion steps, or motion blur which is not disabled on object + * level. */ + return true; +} + class EdgeMap { public: EdgeMap() diff --git a/intern/cycles/bvh/build.cpp b/intern/cycles/bvh/build.cpp index 91198e4e2a2..242595bee4c 100644 --- a/intern/cycles/bvh/build.cpp +++ b/intern/cycles/bvh/build.cpp @@ -656,24 +656,24 @@ bool BVHBuild::range_within_max_leaf_size(const BVHRange &range, for (int i = 0; i < size; i++) { const BVHReference &ref = references[range.start() + i]; - if (ref.prim_type() & PRIMITIVE_ALL_CURVE) { - if (ref.prim_type() & PRIMITIVE_ALL_MOTION) { + if (ref.prim_type() & PRIMITIVE_CURVE) { + if (ref.prim_type() & PRIMITIVE_MOTION) { num_motion_curves++; } else { num_curves++; } } - else if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) { - if (ref.prim_type() & PRIMITIVE_ALL_MOTION) { + else if (ref.prim_type() & PRIMITIVE_TRIANGLE) { + if (ref.prim_type() & PRIMITIVE_MOTION) { num_motion_triangles++; } else { num_triangles++; } } - else if (ref.prim_type() & PRIMITIVE_ALL_POINT) { - if (ref.prim_type() & PRIMITIVE_ALL_MOTION) { + else if (ref.prim_type() & PRIMITIVE_POINT) { + if (ref.prim_type() & PRIMITIVE_MOTION) { num_motion_points++; } else { @@ -973,7 +973,7 @@ BVHNode *BVHBuild::create_leaf_node(const BVHRange &range, const vector<BVHRefer for (int i = 0; i < range.size(); i++) { const BVHReference &ref = references[range.start() + i]; if (ref.prim_index() != -1) { - uint32_t type_index = bitscan((uint32_t)(ref.prim_type() & PRIMITIVE_ALL)); + uint32_t type_index = PRIMITIVE_INDEX(ref.prim_type() & PRIMITIVE_ALL); p_ref[type_index].push_back(ref); p_type[type_index].push_back(ref.prim_type()); p_index[type_index].push_back(ref.prim_index()); diff --git a/intern/cycles/bvh/bvh2.cpp b/intern/cycles/bvh/bvh2.cpp index 744e7fa9898..f1ea43da1d9 100644 --- a/intern/cycles/bvh/bvh2.cpp +++ b/intern/cycles/bvh/bvh2.cpp @@ -387,7 +387,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility } else { /* Primitives. */ - if (pack.prim_type[prim] & PRIMITIVE_ALL_CURVE) { + if (pack.prim_type[prim] & PRIMITIVE_CURVE) { /* Curves. */ const Hair *hair = static_cast<const Hair *>(ob->get_geometry()); int prim_offset = (params.top_level) ? hair->prim_offset : 0; @@ -410,7 +410,7 @@ void BVH2::refit_primitives(int start, int end, BoundBox &bbox, uint &visibility } } } - else if (pack.prim_type[prim] & PRIMITIVE_ALL_POINT) { + else if (pack.prim_type[prim] & PRIMITIVE_POINT) { /* Points. */ const PointCloud *pointcloud = static_cast<const PointCloud *>(ob->get_geometry()); int prim_offset = (params.top_level) ? pointcloud->prim_offset : 0; @@ -590,13 +590,7 @@ void BVH2::pack_instances(size_t nodes_size, size_t leaf_nodes_size) float2 *bvh_prim_time = bvh->pack.prim_time.size() ? &bvh->pack.prim_time[0] : NULL; for (size_t i = 0; i < bvh_prim_index_size; i++) { - if (bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; - } - else { - pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; - } - + pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + geom_prim_offset; pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; pack_prim_object[pack_prim_index_offset] = 0; // unused for instances diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp index eab193f45cb..618dd9438d5 100644 --- a/intern/cycles/bvh/embree.cpp +++ b/intern/cycles/bvh/embree.cpp @@ -91,7 +91,7 @@ static void rtc_filter_occluded_func(const RTCFilterFunctionNArguments *args) ++ctx->num_hits; /* Always use baked shadow transparency for curves. */ - if (current_isect.type & PRIMITIVE_ALL_CURVE) { + if (current_isect.type & PRIMITIVE_CURVE) { ctx->throughput *= intersection_curve_shadow_transparency( kg, current_isect.object, current_isect.prim, current_isect.u); diff --git a/intern/cycles/bvh/split.cpp b/intern/cycles/bvh/split.cpp index 34d12de97c0..e126b6f18bc 100644 --- a/intern/cycles/bvh/split.cpp +++ b/intern/cycles/bvh/split.cpp @@ -535,15 +535,15 @@ void BVHSpatialSplit::split_reference(const BVHBuild &builder, /* loop over vertices/edges. */ const Object *ob = builder.objects[ref.prim_object()]; - if (ref.prim_type() & PRIMITIVE_ALL_TRIANGLE) { + if (ref.prim_type() & PRIMITIVE_TRIANGLE) { Mesh *mesh = static_cast<Mesh *>(ob->get_geometry()); split_triangle_reference(ref, mesh, dim, pos, left_bounds, right_bounds); } - else if (ref.prim_type() & PRIMITIVE_ALL_CURVE) { + else if (ref.prim_type() & PRIMITIVE_CURVE) { Hair *hair = static_cast<Hair *>(ob->get_geometry()); split_curve_reference(ref, hair, dim, pos, left_bounds, right_bounds); } - else if (ref.prim_type() & PRIMITIVE_ALL_POINT) { + else if (ref.prim_type() & PRIMITIVE_POINT) { PointCloud *pointcloud = static_cast<PointCloud *>(ob->get_geometry()); split_point_reference(ref, pointcloud, dim, pos, left_bounds, right_bounds); } diff --git a/intern/cycles/bvh/unaligned.cpp b/intern/cycles/bvh/unaligned.cpp index 3c4a600fe58..a8db6efb597 100644 --- a/intern/cycles/bvh/unaligned.cpp +++ b/intern/cycles/bvh/unaligned.cpp @@ -69,7 +69,7 @@ bool BVHUnaligned::compute_aligned_space(const BVHReference &ref, Transform *ali const int packed_type = ref.prim_type(); const int type = (packed_type & PRIMITIVE_ALL); /* No motion blur curves here, we can't fit them to aligned boxes well. */ - if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) { + if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) { const int curve_index = ref.prim_index(); const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); const Hair *hair = static_cast<const Hair *>(object->get_geometry()); @@ -95,7 +95,7 @@ BoundBox BVHUnaligned::compute_aligned_prim_boundbox(const BVHReference &prim, const int packed_type = prim.prim_type(); const int type = (packed_type & PRIMITIVE_ALL); /* No motion blur curves here, we can't fit them to aligned boxes well. */ - if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_CURVE_THICK)) { + if ((type & PRIMITIVE_CURVE) && !(type & PRIMITIVE_MOTION)) { const int curve_index = prim.prim_index(); const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); const Hair *hair = static_cast<const Hair *>(object->get_geometry()); diff --git a/intern/cycles/device/denoise.cpp b/intern/cycles/device/denoise.cpp index c291a7a0adb..8ae2bb213e4 100644 --- a/intern/cycles/device/denoise.cpp +++ b/intern/cycles/device/denoise.cpp @@ -76,6 +76,8 @@ NODE_DEFINE(DenoiseParams) SOCKET_BOOLEAN(use_pass_albedo, "Use Pass Albedo", true); SOCKET_BOOLEAN(use_pass_normal, "Use Pass Normal", false); + SOCKET_BOOLEAN(temporally_stable, "Temporally Stable", false); + SOCKET_ENUM(prefilter, "Prefilter", *prefilter_enum, DENOISER_PREFILTER_FAST); return type; diff --git a/intern/cycles/device/denoise.h b/intern/cycles/device/denoise.h index 3f30506ae06..07868527fc5 100644 --- a/intern/cycles/device/denoise.h +++ b/intern/cycles/device/denoise.h @@ -72,6 +72,9 @@ class DenoiseParams : public Node { bool use_pass_albedo = true; bool use_pass_normal = true; + /* Configure the denoiser to use motion vectors, previous image and a temporally stable model. */ + bool temporally_stable = false; + DenoiserPrefilter prefilter = DENOISER_PREFILTER_FAST; static const NodeEnum *get_type_enum(); @@ -83,7 +86,8 @@ class DenoiseParams : public Node { { return !(use == other.use && type == other.type && start_sample == other.start_sample && use_pass_albedo == other.use_pass_albedo && - use_pass_normal == other.use_pass_normal && prefilter == other.prefilter); + use_pass_normal == other.use_pass_normal && + temporally_stable == other.temporally_stable && prefilter == other.prefilter); } }; diff --git a/intern/cycles/device/optix/device_impl.cpp b/intern/cycles/device/optix/device_impl.cpp index 38cc3330ebd..009661b2dec 100644 --- a/intern/cycles/device/optix/device_impl.cpp +++ b/intern/cycles/device/optix/device_impl.cpp @@ -566,6 +566,19 @@ class OptiXDevice::DenoiseContext { } } + if (denoise_params.temporally_stable) { + prev_output.device_pointer = render_buffers->buffer.device_pointer; + + prev_output.offset = buffer_params.get_pass_offset(PASS_DENOISING_PREVIOUS); + + prev_output.stride = buffer_params.stride; + prev_output.pass_stride = buffer_params.pass_stride; + + num_input_passes += 1; + use_pass_flow = true; + pass_motion = buffer_params.get_pass_offset(PASS_MOTION); + } + use_guiding_passes = (num_input_passes - 1) > 0; if (use_guiding_passes) { @@ -574,6 +587,7 @@ class OptiXDevice::DenoiseContext { guiding_params.pass_albedo = pass_denoising_albedo; guiding_params.pass_normal = pass_denoising_normal; + guiding_params.pass_flow = pass_motion; guiding_params.stride = buffer_params.stride; guiding_params.pass_stride = buffer_params.pass_stride; @@ -588,6 +602,10 @@ class OptiXDevice::DenoiseContext { guiding_params.pass_normal = guiding_params.pass_stride; guiding_params.pass_stride += 3; } + if (use_pass_flow) { + guiding_params.pass_flow = guiding_params.pass_stride; + guiding_params.pass_stride += 2; + } guiding_params.stride = buffer_params.width; @@ -605,6 +623,16 @@ class OptiXDevice::DenoiseContext { RenderBuffers *render_buffers = nullptr; const BufferParams &buffer_params; + /* Previous output. */ + struct { + device_ptr device_pointer = 0; + + int offset = PASS_UNUSED; + + int stride = -1; + int pass_stride = -1; + } prev_output; + /* Device-side storage of the guiding passes. */ device_only_memory<float> guiding_buffer; @@ -614,6 +642,7 @@ class OptiXDevice::DenoiseContext { /* NOTE: Are only initialized when the corresponding guiding pass is enabled. */ int pass_albedo = PASS_UNUSED; int pass_normal = PASS_UNUSED; + int pass_flow = PASS_UNUSED; int stride = -1; int pass_stride = -1; @@ -624,6 +653,7 @@ class OptiXDevice::DenoiseContext { bool use_guiding_passes = false; bool use_pass_albedo = false; bool use_pass_normal = false; + bool use_pass_flow = false; int num_samples = 0; @@ -632,6 +662,7 @@ class OptiXDevice::DenoiseContext { /* NOTE: Are only initialized when the corresponding guiding pass is enabled. */ int pass_denoising_albedo = PASS_UNUSED; int pass_denoising_normal = PASS_UNUSED; + int pass_motion = PASS_UNUSED; /* For passes which don't need albedo channel for denoising we replace the actual albedo with * the (0.5, 0.5, 0.5). This flag indicates that the real albedo pass has been replaced with @@ -702,6 +733,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context) &context.guiding_params.pass_stride, &context.guiding_params.pass_albedo, &context.guiding_params.pass_normal, + &context.guiding_params.pass_flow, &context.render_buffers->buffer.device_pointer, &buffer_params.offset, &buffer_params.stride, @@ -709,6 +741,7 @@ bool OptiXDevice::denoise_filter_guiding_preprocess(DenoiseContext &context) &context.pass_sample_count, &context.pass_denoising_albedo, &context.pass_denoising_normal, + &context.pass_motion, &buffer_params.full_x, &buffer_params.full_y, &buffer_params.width, @@ -881,7 +914,8 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context) { const bool recreate_denoiser = (denoiser_.optix_denoiser == nullptr) || (denoiser_.use_pass_albedo != context.use_pass_albedo) || - (denoiser_.use_pass_normal != context.use_pass_normal); + (denoiser_.use_pass_normal != context.use_pass_normal) || + (denoiser_.use_pass_flow != context.use_pass_flow); if (!recreate_denoiser) { return true; } @@ -895,8 +929,14 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context) OptixDenoiserOptions denoiser_options = {}; denoiser_options.guideAlbedo = context.use_pass_albedo; denoiser_options.guideNormal = context.use_pass_normal; + + OptixDenoiserModelKind model = OPTIX_DENOISER_MODEL_KIND_HDR; + if (context.use_pass_flow) { + model = OPTIX_DENOISER_MODEL_KIND_TEMPORAL; + } + const OptixResult result = optixDenoiserCreate( - this->context, OPTIX_DENOISER_MODEL_KIND_HDR, &denoiser_options, &denoiser_.optix_denoiser); + this->context, model, &denoiser_options, &denoiser_.optix_denoiser); if (result != OPTIX_SUCCESS) { set_error("Failed to create OptiX denoiser"); @@ -906,6 +946,7 @@ bool OptiXDevice::denoise_create_if_needed(DenoiseContext &context) /* OptiX denoiser handle was created with the requested number of input passes. */ denoiser_.use_pass_albedo = context.use_pass_albedo; denoiser_.use_pass_normal = context.use_pass_normal; + denoiser_.use_pass_flow = context.use_pass_flow; /* OptiX denoiser has been created, but it needs configuration. */ denoiser_.is_configured = false; @@ -965,8 +1006,10 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass) OptixImage2D color_layer = {0}; OptixImage2D albedo_layer = {0}; OptixImage2D normal_layer = {0}; + OptixImage2D flow_layer = {0}; OptixImage2D output_layer = {0}; + OptixImage2D prev_output_layer = {0}; /* Color pass. */ { @@ -982,6 +1025,19 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass) color_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3; } + /* Previous output. */ + if (context.prev_output.offset != PASS_UNUSED) { + const int64_t pass_stride_in_bytes = context.prev_output.pass_stride * sizeof(float); + + prev_output_layer.data = context.prev_output.device_pointer + + context.prev_output.offset * sizeof(float); + prev_output_layer.width = width; + prev_output_layer.height = height; + prev_output_layer.rowStrideInBytes = pass_stride_in_bytes * context.prev_output.stride; + prev_output_layer.pixelStrideInBytes = pass_stride_in_bytes; + prev_output_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3; + } + /* Optional albedo and color passes. */ if (context.num_input_passes > 1) { const device_ptr d_guiding_buffer = context.guiding_params.device_pointer; @@ -1005,21 +1061,32 @@ bool OptiXDevice::denoise_run(DenoiseContext &context, const DenoisePass &pass) normal_layer.pixelStrideInBytes = pixel_stride_in_bytes; normal_layer.format = OPTIX_PIXEL_FORMAT_FLOAT3; } + + if (context.use_pass_flow) { + flow_layer.data = d_guiding_buffer + context.guiding_params.pass_flow * sizeof(float); + flow_layer.width = width; + flow_layer.height = height; + flow_layer.rowStrideInBytes = row_stride_in_bytes; + flow_layer.pixelStrideInBytes = pixel_stride_in_bytes; + flow_layer.format = OPTIX_PIXEL_FORMAT_FLOAT2; + } } /* Denoise in-place of the noisy input in the render buffers. */ output_layer = color_layer; - /* Finally run denoising. */ - OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */ + OptixDenoiserGuideLayer guide_layers = {}; + guide_layers.albedo = albedo_layer; + guide_layers.normal = normal_layer; + guide_layers.flow = flow_layer; OptixDenoiserLayer image_layers = {}; image_layers.input = color_layer; + image_layers.previousOutput = prev_output_layer; image_layers.output = output_layer; - OptixDenoiserGuideLayer guide_layers = {}; - guide_layers.albedo = albedo_layer; - guide_layers.normal = normal_layer; + /* Finally run denoising. */ + OptixDenoiserParams params = {}; /* All parameters are disabled/zero. */ optix_assert(optixUtilDenoiserInvokeTiled(denoiser_.optix_denoiser, denoiser_.queue.stream(), diff --git a/intern/cycles/device/optix/device_impl.h b/intern/cycles/device/optix/device_impl.h index 25073c60e69..a1865527c2d 100644 --- a/intern/cycles/device/optix/device_impl.h +++ b/intern/cycles/device/optix/device_impl.h @@ -104,6 +104,7 @@ class OptiXDevice : public CUDADevice { bool use_pass_albedo = false; bool use_pass_normal = false; + bool use_pass_flow = false; }; Denoiser denoiser_; diff --git a/intern/cycles/device/queue.h b/intern/cycles/device/queue.h index 4e9f41f7875..926b7cba78a 100644 --- a/intern/cycles/device/queue.h +++ b/intern/cycles/device/queue.h @@ -19,6 +19,7 @@ #include "device/kernel.h" #include "device/graphics_interop.h" +#include "util/debug.h" #include "util/log.h" #include "util/map.h" #include "util/string.h" @@ -42,7 +43,7 @@ struct DeviceKernelArguments { KERNEL_FILM_CONVERT, }; - static const int MAX_ARGS = 16; + static const int MAX_ARGS = 18; Type types[MAX_ARGS]; void *values[MAX_ARGS]; size_t sizes[MAX_ARGS]; @@ -85,6 +86,8 @@ struct DeviceKernelArguments { } void add(const Type type, const void *value, size_t size) { + assert(count < MAX_ARGS); + types[count] = type; values[count] = (void *)value; sizes[count] = size; diff --git a/intern/cycles/kernel/bvh/shadow_all.h b/intern/cycles/kernel/bvh/shadow_all.h index caca85aac1a..b0e799675e0 100644 --- a/intern/cycles/kernel/bvh/shadow_all.h +++ b/intern/cycles/kernel/bvh/shadow_all.h @@ -174,7 +174,7 @@ ccl_device_inline case PRIMITIVE_MOTION_CURVE_THICK: case PRIMITIVE_CURVE_RIBBON: case PRIMITIVE_MOTION_CURVE_RIBBON: { - if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) { + if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { hit = false; @@ -203,7 +203,7 @@ ccl_device_inline #if BVH_FEATURE(BVH_POINTCLOUD) case PRIMITIVE_POINT: case PRIMITIVE_MOTION_POINT: { - if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) { + if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { hit = false; @@ -255,7 +255,7 @@ ccl_device_inline bool record_intersection = true; /* Always use baked shadow transparency for curves. */ - if (isect.type & PRIMITIVE_ALL_CURVE) { + if (isect.type & PRIMITIVE_CURVE) { *throughput *= intersection_curve_shadow_transparency( kg, isect.object, isect.prim, isect.u); diff --git a/intern/cycles/kernel/bvh/traversal.h b/intern/cycles/kernel/bvh/traversal.h index 180f19d11c5..e4bff1a8a80 100644 --- a/intern/cycles/kernel/bvh/traversal.h +++ b/intern/cycles/kernel/bvh/traversal.h @@ -166,7 +166,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, case PRIMITIVE_CURVE_RIBBON: case PRIMITIVE_MOTION_CURVE_RIBBON: { for (; prim_addr < prim_addr2; prim_addr++) { - if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) { + if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { continue; @@ -193,7 +193,7 @@ ccl_device_noinline bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals kg, case PRIMITIVE_POINT: case PRIMITIVE_MOTION_POINT: { for (; prim_addr < prim_addr2; prim_addr++) { - if ((type & PRIMITIVE_ALL_MOTION) && kernel_data.bvh.use_bvh_steps) { + if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) { const float2 prim_time = kernel_tex_fetch(__prim_time, prim_addr); if (ray->time < prim_time.x || ray->time > prim_time.y) { continue; diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index 57593e42a88..bd79c6e19c6 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -118,16 +118,16 @@ ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, { int shader = 0; - if (type & PRIMITIVE_ALL_TRIANGLE) { + if (type & PRIMITIVE_TRIANGLE) { shader = kernel_tex_fetch(__tri_shader, prim); } #ifdef __POINTCLOUD__ - else if (type & PRIMITIVE_ALL_POINT) { + else if (type & PRIMITIVE_POINT) { shader = kernel_tex_fetch(__points_shader, prim); } #endif #ifdef __HAIR__ - else if (type & PRIMITIVE_ALL_CURVE) { + else if (type & PRIMITIVE_CURVE) { shader = kernel_tex_fetch(__curves, prim).shader_id; } #endif @@ -141,16 +141,16 @@ ccl_device_forceinline int intersection_get_shader_from_isect_prim(KernelGlobals { int shader = 0; - if (isect_type & PRIMITIVE_ALL_TRIANGLE) { + if (isect_type & PRIMITIVE_TRIANGLE) { shader = kernel_tex_fetch(__tri_shader, prim); } #ifdef __POINTCLOUD__ - else if (isect_type & PRIMITIVE_ALL_POINT) { + else if (isect_type & PRIMITIVE_POINT) { shader = kernel_tex_fetch(__points_shader, prim); } #endif #ifdef __HAIR__ - else if (isect_type & PRIMITIVE_ALL_CURVE) { + else if (isect_type & PRIMITIVE_CURVE) { shader = kernel_tex_fetch(__curves, prim).shader_id; } #endif diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index f0ce45d1c2c..2c8ef858270 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -124,7 +124,7 @@ ccl_device_inline int bsdf_sample(KernelGlobals kg, /* For curves use the smooth normal, particularly for ribbons the geometric * normal gives too much darkening otherwise. */ int label; - const float3 Ng = (sd->type & PRIMITIVE_ALL_CURVE) ? sc->N : sd->Ng; + const float3 Ng = (sd->type & PRIMITIVE_CURVE) ? sc->N : sd->Ng; switch (sc->type) { case CLOSURE_BSDF_DIFFUSE_ID: diff --git a/intern/cycles/kernel/closure/bsdf_hair_principled.h b/intern/cycles/kernel/closure/bsdf_hair_principled.h index f55ea0f6a2e..c68314889f1 100644 --- a/intern/cycles/kernel/closure/bsdf_hair_principled.h +++ b/intern/cycles/kernel/closure/bsdf_hair_principled.h @@ -213,9 +213,7 @@ ccl_device int bsdf_principled_hair_setup(ccl_private ShaderData *sd, /* TODO: we convert this value to a cosine later and discard the sign, so * we could probably save some operations. */ - float h = (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) ? - -sd->v : - dot(cross(sd->Ng, X), Z); + float h = (sd->type & PRIMITIVE_CURVE_RIBBON) ? -sd->v : dot(cross(sd->Ng, X), Z); kernel_assert(fabsf(h) < 1.0f + 1e-4f); kernel_assert(isfinite3_safe(Y)); diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h index b50f492e8c7..027b2a7a8c7 100644 --- a/intern/cycles/kernel/device/gpu/kernel.h +++ b/intern/cycles/kernel/device/gpu/kernel.h @@ -756,6 +756,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) int guiding_pass_stride, int guiding_pass_albedo, int guiding_pass_normal, + int guiding_pass_flow, ccl_global const float *render_buffer, int render_offset, int render_stride, @@ -763,6 +764,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) int render_pass_sample_count, int render_pass_denoising_albedo, int render_pass_denoising_normal, + int render_pass_motion, int full_x, int full_y, int width, @@ -814,6 +816,17 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) normal_out[1] = normal_in[1] * pixel_scale; normal_out[2] = normal_in[2] * pixel_scale; } + + /* Flow pass. */ + if (guiding_pass_flow != PASS_UNUSED) { + kernel_assert(render_pass_motion != PASS_UNUSED); + + const float *motion_in = buffer + render_pass_motion; + float *flow_out = guiding_pixel + guiding_pass_flow; + + flow_out[0] = -motion_in[0] * pixel_scale; + flow_out[1] = -motion_in[1] * pixel_scale; + } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) @@ -899,7 +912,6 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) else { /* Assigning to zero since this is a default alpha value for 3-component passes, and it * is an opaque pixel for 4 component passes. */ - denoised_pixel[3] = 0; } } diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal index 27dc1f44c6f..deb7dafe55e 100644 --- a/intern/cycles/kernel/device/metal/kernel.metal +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -211,7 +211,7 @@ bool metalrt_shadow_all_hit(constant KernelParamsMetal &launch_params_metal, } /* Always use baked shadow transparency for curves. */ - if (type & PRIMITIVE_ALL_CURVE) { + if (type & PRIMITIVE_CURVE) { float throughput = payload.throughput; throughput *= context.intersection_curve_shadow_transparency(nullptr, object, prim, u); payload.throughput = throughput; @@ -476,7 +476,7 @@ __intersection__curve_ribbon(constant KernelParamsMetal &launch_params_metal [[b result.continue_search = true; result.distance = ray_tmax; - if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) { + if (segment.type & PRIMITIVE_CURVE_RIBBON) { metalrt_intersection_curve(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction, # if defined(__METALRT_MOTION__) payload.time, @@ -507,7 +507,7 @@ __intersection__curve_ribbon_shadow(constant KernelParamsMetal &launch_params_me result.continue_search = true; result.distance = ray_tmax; - if (segment.type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) { + if (segment.type & PRIMITIVE_CURVE_RIBBON) { metalrt_intersection_curve_shadow(launch_params_metal, payload, object, segment.prim, segment.type, ray_origin, ray_direction, # if defined(__METALRT_MOTION__) payload.time, diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu index c639dc87f35..aa210b31a95 100644 --- a/intern/cycles/kernel/device/optix/kernel.cu +++ b/intern/cycles/kernel/device/optix/kernel.cu @@ -194,7 +194,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() type = kernel_tex_fetch(__objects, object).primitive_type; } # ifdef __HAIR__ - else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) { + else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) { u = __uint_as_float(optixGetAttribute_0()); v = __uint_as_float(optixGetAttribute_1()); @@ -234,7 +234,7 @@ extern "C" __global__ void __anyhit__kernel_optix_shadow_all_hit() } /* Always use baked shadow transparency for curves. */ - if (type & PRIMITIVE_ALL_CURVE) { + if (type & PRIMITIVE_CURVE) { float throughput = __uint_as_float(optixGetPayload_1()); throughput *= intersection_curve_shadow_transparency(nullptr, object, prim, u); optixSetPayload_1(__float_as_uint(throughput)); @@ -320,7 +320,7 @@ extern "C" __global__ void __anyhit__kernel_optix_visibility_test() { #ifdef __HAIR__ # if OPTIX_ABI_VERSION < 55 - if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) { + if (optixGetPrimitiveType() == OPTIX_PRIMITIVE_TYPE_ROUND_CUBIC_BSPLINE) { /* Filter out curve endcaps. */ const float u = __uint_as_float(optixGetAttribute_0()); if (u == 0.0f || u == 1.0f) { @@ -359,7 +359,7 @@ extern "C" __global__ void __closesthit__kernel_optix_hit() optixSetPayload_3(prim); optixSetPayload_5(kernel_tex_fetch(__objects, object).primitive_type); } - else if (optixGetHitKind() & PRIMITIVE_ALL_CURVE) { + else if ((optixGetHitKind() & (~PRIMITIVE_MOTION)) != PRIMITIVE_POINT) { const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, prim); optixSetPayload_1(optixGetAttribute_0()); /* Same as 'optixGetCurveParameter()' */ optixSetPayload_2(optixGetAttribute_1()); @@ -406,6 +406,7 @@ ccl_device_inline void optix_intersection_curve(const int prim, const int type) isect.t *= len; if (curve_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) { + static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use"); optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL, __float_as_int(isect.u), /* Attribute_0 */ @@ -418,7 +419,7 @@ extern "C" __global__ void __intersection__curve_ribbon() const KernelCurveSegment segment = kernel_tex_fetch(__curve_segments, optixGetPrimitiveIndex()); const int prim = segment.prim; const int type = segment.type; - if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) { + if (type & PRIMITIVE_CURVE_RIBBON) { optix_intersection_curve(prim, type); } } @@ -460,6 +461,7 @@ extern "C" __global__ void __intersection__point() } if (point_intersect(NULL, &isect, P, dir, isect.t, object, prim, time, type)) { + static_assert(PRIMITIVE_ALL < 128, "Values >= 128 are reserved for OptiX internal use"); optixReportIntersection(isect.t / len, type & PRIMITIVE_ALL); } } diff --git a/intern/cycles/kernel/geom/attribute.h b/intern/cycles/kernel/geom/attribute.h index a7ac2bd926f..8b3524beb5d 100644 --- a/intern/cycles/kernel/geom/attribute.h +++ b/intern/cycles/kernel/geom/attribute.h @@ -36,7 +36,7 @@ ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const S ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd) { - if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) { + if ((sd->type & PRIMITIVE_TRIANGLE) && subd_triangle_patch(kg, sd) != ~0) { return ATTR_PRIM_SUBD; } else { diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h index 4b6eecf9640..8a63f01643b 100644 --- a/intern/cycles/kernel/geom/curve.h +++ b/intern/cycles/kernel/geom/curve.h @@ -205,14 +205,14 @@ ccl_device float curve_thickness(KernelGlobals kg, ccl_private const ShaderData { float r = 0.0f; - if (sd->type & PRIMITIVE_ALL_CURVE) { + if (sd->type & PRIMITIVE_CURVE) { KernelCurve curve = kernel_tex_fetch(__curves, sd->prim); int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type); int k1 = k0 + 1; float4 P_curve[2]; - if (!(sd->type & PRIMITIVE_ALL_MOTION)) { + if (!(sd->type & PRIMITIVE_MOTION)) { P_curve[0] = kernel_tex_fetch(__curve_keys, k0); P_curve[1] = kernel_tex_fetch(__curve_keys, k1); } @@ -249,7 +249,7 @@ ccl_device float3 curve_tangent_normal(KernelGlobals kg, ccl_private const Shade { float3 tgN = make_float3(0.0f, 0.0f, 0.0f); - if (sd->type & PRIMITIVE_ALL_CURVE) { + if (sd->type & PRIMITIVE_CURVE) { tgN = -(-sd->I - sd->dPdu * (dot(sd->dPdu, -sd->I) / len_squared(sd->dPdu))); tgN = normalize(tgN); diff --git a/intern/cycles/kernel/geom/curve_intersect.h b/intern/cycles/kernel/geom/curve_intersect.h index fb0b80b281f..2081eeb3eac 100644 --- a/intern/cycles/kernel/geom/curve_intersect.h +++ b/intern/cycles/kernel/geom/curve_intersect.h @@ -635,7 +635,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg, float time, int type) { - const bool is_motion = (type & PRIMITIVE_ALL_MOTION); + const bool is_motion = (type & PRIMITIVE_MOTION); KernelCurve kcurve = kernel_tex_fetch(__curves, prim); @@ -655,7 +655,7 @@ ccl_device_forceinline bool curve_intersect(KernelGlobals kg, motion_curve_keys(kg, object, prim, time, ka, k0, k1, kb, curve); } - if (type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) { + if (type & PRIMITIVE_CURVE_RIBBON) { /* todo: adaptive number of subdivisions could help performance here. */ const int subdivisions = kernel_data.bvh.curve_subdivisions; if (ribbon_intersect(P, dir, tmax, subdivisions, curve, isect)) { @@ -704,7 +704,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg, float4 P_curve[4]; - if (!(sd->type & PRIMITIVE_ALL_MOTION)) { + if (!(sd->type & PRIMITIVE_MOTION)) { P_curve[0] = kernel_tex_fetch(__curve_keys, ka); P_curve[1] = kernel_tex_fetch(__curve_keys, k0); P_curve[2] = kernel_tex_fetch(__curve_keys, k1); @@ -719,7 +719,7 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg, const float4 dPdu4 = catmull_rom_basis_derivative(P_curve, sd->u); const float3 dPdu = float4_to_float3(dPdu4); - if (sd->type & (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON)) { + if (sd->type & PRIMITIVE_CURVE_RIBBON) { /* Rounded smooth normals for ribbons, to approximate thick curve shape. */ const float3 tangent = normalize(dPdu); const float3 bitangent = normalize(cross(tangent, -D)); @@ -727,8 +727,6 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg, const float cosine = safe_sqrtf(1.0f - sine * sine); sd->N = normalize(sine * bitangent - cosine * normalize(cross(tangent, bitangent))); - sd->Ng = -D; - # if 0 /* This approximates the position and geometric normal of a thick curve too, * but gives too many issues with wrong self intersections. */ @@ -744,25 +742,27 @@ ccl_device_inline void curve_shader_setup(KernelGlobals kg, /* NOTE: It is possible that P will be the same as P_inside (precision issues, or very small * radius). In this case use the view direction to approximate the normal. */ const float3 P_inside = float4_to_float3(catmull_rom_basis_eval(P_curve, sd->u)); - const float3 Ng = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I; + const float3 N = (!isequal_float3(P, P_inside)) ? normalize(P - P_inside) : -sd->I; - sd->N = Ng; - sd->Ng = Ng; + sd->N = N; sd->v = 0.0f; } # ifdef __DPDU__ /* dPdu/dPdv */ sd->dPdu = dPdu; - sd->dPdv = cross(dPdu, sd->Ng); # endif + /* Convert to world space. */ if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_transform(kg, sd); - P = transform_point(&tfm, P); + object_position_transform_auto(kg, sd, &P); + object_normal_transform_auto(kg, sd, &sd->N); + object_dir_transform_auto(kg, sd, &sd->dPdu); } sd->P = P; + sd->Ng = (sd->type & PRIMITIVE_CURVE_RIBBON) ? sd->I : sd->N; + sd->dPdv = cross(sd->dPdu, sd->Ng); sd->shader = kernel_tex_fetch(__curves, sd->prim).shader_id; } diff --git a/intern/cycles/kernel/geom/point.h b/intern/cycles/kernel/geom/point.h index 021135b76fb..52a1e77d71a 100644 --- a/intern/cycles/kernel/geom/point.h +++ b/intern/cycles/kernel/geom/point.h @@ -46,8 +46,11 @@ ccl_device float point_attribute_float(KernelGlobals kg, } } -ccl_device float2 point_attribute_float2( - KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float2 *dx, float2 *dy) +ccl_device float2 point_attribute_float2(KernelGlobals kg, + ccl_private const ShaderData *sd, + const AttributeDescriptor desc, + ccl_private float2 *dx, + ccl_private float2 *dy) { # ifdef __RAY_DIFFERENTIALS__ if (dx) @@ -64,8 +67,11 @@ ccl_device float2 point_attribute_float2( } } -ccl_device float3 point_attribute_float3( - KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float3 *dx, float3 *dy) +ccl_device float3 point_attribute_float3(KernelGlobals kg, + ccl_private const ShaderData *sd, + const AttributeDescriptor desc, + ccl_private float3 *dx, + ccl_private float3 *dy) { # ifdef __RAY_DIFFERENTIALS__ if (dx) @@ -82,8 +88,11 @@ ccl_device float3 point_attribute_float3( } } -ccl_device float4 point_attribute_float4( - KernelGlobals kg, const ShaderData *sd, const AttributeDescriptor desc, float4 *dx, float4 *dy) +ccl_device float4 point_attribute_float4(KernelGlobals kg, + ccl_private const ShaderData *sd, + const AttributeDescriptor desc, + ccl_private float4 *dx, + ccl_private float4 *dy) { # ifdef __RAY_DIFFERENTIALS__ if (dx) @@ -104,7 +113,7 @@ ccl_device float4 point_attribute_float4( ccl_device float point_radius(KernelGlobals kg, ccl_private const ShaderData *sd) { - if (sd->type & PRIMITIVE_ALL_POINT) { + if (sd->type & PRIMITIVE_POINT) { return kernel_tex_fetch(__points, sd->prim).w; } diff --git a/intern/cycles/kernel/geom/point_intersect.h b/intern/cycles/kernel/geom/point_intersect.h index da0b31f9a8c..757c8b81efa 100644 --- a/intern/cycles/kernel/geom/point_intersect.h +++ b/intern/cycles/kernel/geom/point_intersect.h @@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN #ifdef __POINTCLOUD__ ccl_device_forceinline bool point_intersect_test( - const float4 point, const float3 P, const float3 dir, const float tmax, float *t) + const float4 point, const float3 P, const float3 dir, const float tmax, ccl_private float *t) { const float3 center = float4_to_float3(point); const float radius = point.w; @@ -43,7 +43,7 @@ ccl_device_forceinline bool point_intersect_test( const float t_front = projC0 - td; const bool valid_front = (0.0f <= t_front) & (t_front <= tmax); - /* Always backface culling for now. */ + /* Always back-face culling for now. */ # if 0 const float t_back = projC0 + td; const bool valid_back = (0.0f <= t_back) & (t_back <= tmax); @@ -75,8 +75,8 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg, const float time, const int type) { - const float4 point = (type & PRIMITIVE_ALL_MOTION) ? motion_point(kg, object, prim, time) : - kernel_tex_fetch(__points, prim); + const float4 point = (type & PRIMITIVE_MOTION) ? motion_point(kg, object, prim, time) : + kernel_tex_fetch(__points, prim); if (!point_intersect_test(point, P, dir, tmax, &isect->t)) { return false; @@ -93,7 +93,7 @@ ccl_device_forceinline bool point_intersect(KernelGlobals kg, ccl_device_inline void point_shader_setup(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private const Intersection *isect, - const Ray *ray) + ccl_private const Ray *ray) { sd->shader = kernel_tex_fetch(__points_shader, isect->prim); sd->P = ray->P + ray->D * isect->t; @@ -104,17 +104,12 @@ ccl_device_inline void point_shader_setup(KernelGlobals kg, sd->v = isect->v; # endif - /* Computer point center for normal. */ - float3 center = float4_to_float3((isect->type & PRIMITIVE_ALL_MOTION) ? + /* Compute point center for normal. */ + float3 center = float4_to_float3((isect->type & PRIMITIVE_MOTION) ? motion_point(kg, sd->object, sd->prim, sd->time) : kernel_tex_fetch(__points, sd->prim)); - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - const Transform tfm = object_get_transform(kg, sd); - -# ifndef __KERNEL_OPTIX__ - center = transform_point(&tfm, center); -# endif + object_position_transform_auto(kg, sd, ¢er); } /* Normal */ diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h index 9416385638c..2e8e0cda6f1 100644 --- a/intern/cycles/kernel/geom/primitive.h +++ b/intern/cycles/kernel/geom/primitive.h @@ -37,19 +37,19 @@ ccl_device_inline float primitive_surface_attribute_float(KernelGlobals kg, ccl_private float *dx, ccl_private float *dy) { - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { if (subd_triangle_patch(kg, sd) == ~0) return triangle_attribute_float(kg, sd, desc, dx, dy); else return subd_triangle_attribute_float(kg, sd, desc, dx, dy); } #ifdef __HAIR__ - else if (sd->type & PRIMITIVE_ALL_CURVE) { + else if (sd->type & PRIMITIVE_CURVE) { return curve_attribute_float(kg, sd, desc, dx, dy); } #endif #ifdef __POINTCLOUD__ - else if (sd->type & PRIMITIVE_ALL_POINT) { + else if (sd->type & PRIMITIVE_POINT) { return point_attribute_float(kg, sd, desc, dx, dy); } #endif @@ -68,19 +68,19 @@ ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals kg, ccl_private float2 *dx, ccl_private float2 *dy) { - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { if (subd_triangle_patch(kg, sd) == ~0) return triangle_attribute_float2(kg, sd, desc, dx, dy); else return subd_triangle_attribute_float2(kg, sd, desc, dx, dy); } #ifdef __HAIR__ - else if (sd->type & PRIMITIVE_ALL_CURVE) { + else if (sd->type & PRIMITIVE_CURVE) { return curve_attribute_float2(kg, sd, desc, dx, dy); } #endif #ifdef __POINTCLOUD__ - else if (sd->type & PRIMITIVE_ALL_POINT) { + else if (sd->type & PRIMITIVE_POINT) { return point_attribute_float2(kg, sd, desc, dx, dy); } #endif @@ -99,19 +99,19 @@ ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals kg, ccl_private float3 *dx, ccl_private float3 *dy) { - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { if (subd_triangle_patch(kg, sd) == ~0) return triangle_attribute_float3(kg, sd, desc, dx, dy); else return subd_triangle_attribute_float3(kg, sd, desc, dx, dy); } #ifdef __HAIR__ - else if (sd->type & PRIMITIVE_ALL_CURVE) { + else if (sd->type & PRIMITIVE_CURVE) { return curve_attribute_float3(kg, sd, desc, dx, dy); } #endif #ifdef __POINTCLOUD__ - else if (sd->type & PRIMITIVE_ALL_POINT) { + else if (sd->type & PRIMITIVE_POINT) { return point_attribute_float3(kg, sd, desc, dx, dy); } #endif @@ -130,19 +130,19 @@ ccl_device_forceinline float4 primitive_surface_attribute_float4(KernelGlobals k ccl_private float4 *dx, ccl_private float4 *dy) { - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { if (subd_triangle_patch(kg, sd) == ~0) return triangle_attribute_float4(kg, sd, desc, dx, dy); else return subd_triangle_attribute_float4(kg, sd, desc, dx, dy); } #ifdef __HAIR__ - else if (sd->type & PRIMITIVE_ALL_CURVE) { + else if (sd->type & PRIMITIVE_CURVE) { return curve_attribute_float4(kg, sd, desc, dx, dy); } #endif #ifdef __POINTCLOUD__ - else if (sd->type & PRIMITIVE_ALL_POINT) { + else if (sd->type & PRIMITIVE_POINT) { return point_attribute_float4(kg, sd, desc, dx, dy); } #endif @@ -246,7 +246,7 @@ ccl_device bool primitive_ptex(KernelGlobals kg, ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd) { #if defined(__HAIR__) || defined(__POINTCLOUD__) - if (sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT)) + if (sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT)) # ifdef __DPDU__ return normalize(sd->dPdu); # else @@ -282,16 +282,16 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, float3 center; #if defined(__HAIR__) || defined(__POINTCLOUD__) - bool is_curve_or_point = sd->type & (PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_POINT); + bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT); if (is_curve_or_point) { center = make_float3(0.0f, 0.0f, 0.0f); - if (sd->type & PRIMITIVE_ALL_CURVE) { + if (sd->type & PRIMITIVE_CURVE) { # if defined(__HAIR__) center = curve_motion_center_location(kg, sd); # endif } - else if (sd->type & PRIMITIVE_ALL_POINT) { + else if (sd->type & PRIMITIVE_POINT) { # if defined(__POINTCLOUD__) center = point_motion_center_location(kg, sd); # endif @@ -331,7 +331,7 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, } else #endif - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { /* Triangle */ if (subd_triangle_patch(kg, sd) == ~0) { motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL); diff --git a/intern/cycles/kernel/geom/shader_data.h b/intern/cycles/kernel/geom/shader_data.h index d3932545ef6..f5055d8b285 100644 --- a/intern/cycles/kernel/geom/shader_data.h +++ b/intern/cycles/kernel/geom/shader_data.h @@ -69,56 +69,58 @@ ccl_device_inline void shader_setup_from_ray(KernelGlobals kg, sd->I = -ray->D; #ifdef __HAIR__ - if (sd->type & PRIMITIVE_ALL_CURVE) { + if (sd->type & PRIMITIVE_CURVE) { /* curve */ curve_shader_setup(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim); } else #endif #ifdef __POINTCLOUD__ - if (sd->type & PRIMITIVE_ALL_POINT) { + if (sd->type & PRIMITIVE_POINT) { /* point */ point_shader_setup(kg, sd, isect, ray); } else #endif - if (sd->type & PRIMITIVE_TRIANGLE) { - /* static triangle */ - float3 Ng = triangle_normal(kg, sd); - sd->shader = kernel_tex_fetch(__tri_shader, sd->prim); + { + if (sd->type == PRIMITIVE_TRIANGLE) { + /* static triangle */ + float3 Ng = triangle_normal(kg, sd); + sd->shader = kernel_tex_fetch(__tri_shader, sd->prim); - /* vectors */ - sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim); - sd->Ng = Ng; - sd->N = Ng; + /* vectors */ + sd->P = triangle_refine(kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim); + sd->Ng = Ng; + sd->N = Ng; - /* smooth normal */ - if (sd->shader & SHADER_SMOOTH_NORMAL) - sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v); + /* smooth normal */ + if (sd->shader & SHADER_SMOOTH_NORMAL) + sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v); #ifdef __DPDU__ - /* dPdu/dPdv */ - triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv); + /* dPdu/dPdv */ + triangle_dPdudv(kg, sd->prim, &sd->dPdu, &sd->dPdv); #endif - } - else { - /* motion triangle */ - motion_triangle_shader_setup( - kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false); - } - - sd->flag |= kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags; + } + else { + /* motion triangle */ + motion_triangle_shader_setup( + kg, sd, ray->P, ray->D, isect->t, isect->object, isect->prim, false); + } - if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { - /* instance transform */ - object_normal_transform_auto(kg, sd, &sd->N); - object_normal_transform_auto(kg, sd, &sd->Ng); + if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { + /* instance transform */ + object_normal_transform_auto(kg, sd, &sd->N); + object_normal_transform_auto(kg, sd, &sd->Ng); #ifdef __DPDU__ - object_dir_transform_auto(kg, sd, &sd->dPdu); - object_dir_transform_auto(kg, sd, &sd->dPdv); + object_dir_transform_auto(kg, sd, &sd->dPdu); + object_dir_transform_auto(kg, sd, &sd->dPdv); #endif + } } + sd->flag = kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).flags; + /* backfacing test */ bool backfacing = (dot(sd->Ng, sd->I) < 0.0f); @@ -201,7 +203,7 @@ ccl_device_inline void shader_setup_from_sample(KernelGlobals kg, object_dir_transform_auto(kg, sd, &sd->I); } - if (sd->type & PRIMITIVE_TRIANGLE) { + if (sd->type == PRIMITIVE_TRIANGLE) { /* smooth normal */ if (sd->shader & SHADER_SMOOTH_NORMAL) { sd->N = triangle_smooth_normal(kg, Ng, sd->prim, sd->u, sd->v); diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index c9c586f5ae4..3d5b65458c7 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -82,7 +82,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg, # ifdef __HAIR__ if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS) && - (sd->type & PRIMITIVE_ALL_TRIANGLE)) + (sd->type & PRIMITIVE_TRIANGLE)) # else if (!(path_flag & PATH_RAY_MIS_SKIP) && (sd->flag & SD_USE_MIS)) # endif diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 83f6d733d3a..b6662c7f6b3 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -191,7 +191,7 @@ ccl_device_inline float3 shadow_ray_offset(KernelGlobals kg, float3 Ng = (transmit ? -sd->Ng : sd->Ng); float3 P = ray_offset(sd->P, Ng); - if ((sd->type & PRIMITIVE_ALL_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) { + if ((sd->type & PRIMITIVE_TRIANGLE) && (sd->shader & SHADER_SMOOTH_NORMAL)) { const float offset_cutoff = kernel_tex_fetch(__objects, sd->object).shadow_terminator_geometry_offset; /* Do ray offset (heavy stuff) only for close to be terminated triangles: diff --git a/intern/cycles/kernel/osl/services.cpp b/intern/cycles/kernel/osl/services.cpp index 4007005dee7..a79fc323a13 100644 --- a/intern/cycles/kernel/osl/services.cpp +++ b/intern/cycles/kernel/osl/services.cpp @@ -960,13 +960,15 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg return set_attribute_int(3, type, derivatives, val); } else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices) && - sd->type & PRIMITIVE_ALL_TRIANGLE) { + sd->type & PRIMITIVE_TRIANGLE) { float3 P[3]; - if (sd->type & PRIMITIVE_TRIANGLE) - triangle_vertices(kg, sd->prim, P); - else + if (sd->type & PRIMITIVE_MOTION) { motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P); + } + else { + triangle_vertices(kg, sd->prim, P); + } if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &P[0]); @@ -986,7 +988,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg } /* Hair Attributes */ else if (name == u_is_curve) { - float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0; + float f = (sd->type & PRIMITIVE_CURVE) != 0; return set_attribute_float(f, type, derivatives, val); } else if (name == u_curve_thickness) { @@ -999,7 +1001,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg } /* point attributes */ else if (name == u_is_point) { - float f = (sd->type & PRIMITIVE_ALL_POINT) != 0; + float f = (sd->type & PRIMITIVE_POINT) != 0; return set_attribute_float(f, type, derivatives, val); } else if (name == u_point_radius) { @@ -1007,7 +1009,7 @@ bool OSLRenderServices::get_object_standard_attribute(const KernelGlobalsCPU *kg return set_attribute_float(f, type, derivatives, val); } else if (name == u_normal_map_normal) { - if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + if (sd->type & PRIMITIVE_TRIANGLE) { float3 f = triangle_smooth_normal_unnormalized(kg, sd, sd->Ng, sd->prim, sd->u, sd->v); return set_attribute_float3(f, type, derivatives, val); } diff --git a/intern/cycles/kernel/svm/bevel.h b/intern/cycles/kernel/svm/bevel.h index 6799489514f..46dfb6631da 100644 --- a/intern/cycles/kernel/svm/bevel.h +++ b/intern/cycles/kernel/svm/bevel.h @@ -206,12 +206,12 @@ ccl_device float3 svm_bevel( for (int hit = 0; hit < num_eval_hits; hit++) { /* Quickly retrieve P and Ng without setting up ShaderData. */ float3 hit_P; - if (sd->type & PRIMITIVE_TRIANGLE) { + if (sd->type == PRIMITIVE_TRIANGLE) { hit_P = triangle_refine_local( kg, sd, ray.P, ray.D, ray.t, isect.hits[hit].object, isect.hits[hit].prim); } # ifdef __OBJECT_MOTION__ - else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) { + else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) { float3 verts[3]; motion_triangle_vertices(kg, sd->object, isect.hits[hit].prim, sd->time, verts); hit_P = motion_triangle_refine_local( @@ -236,11 +236,11 @@ ccl_device float3 svm_bevel( float u = isect.hits[hit].u; float v = isect.hits[hit].v; - if (sd->type & PRIMITIVE_TRIANGLE) { + if (sd->type == PRIMITIVE_TRIANGLE) { N = triangle_smooth_normal(kg, N, prim, u, v); } # ifdef __OBJECT_MOTION__ - else if (sd->type & PRIMITIVE_MOTION_TRIANGLE) { + else if (sd->type == PRIMITIVE_MOTION_TRIANGLE) { N = motion_triangle_smooth_normal(kg, N, sd->object, prim, u, v, sd->time); } # endif /* __OBJECT_MOTION__ */ diff --git a/intern/cycles/kernel/svm/closure.h b/intern/cycles/kernel/svm/closure.h index 71952e9e0f8..2ca22d58191 100644 --- a/intern/cycles/kernel/svm/closure.h +++ b/intern/cycles/kernel/svm/closure.h @@ -107,7 +107,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, } float3 N = stack_valid(data_node.x) ? stack_load_float3(stack, data_node.x) : sd->N; - if (!(sd->type & PRIMITIVE_ALL_CURVE)) { + if (!(sd->type & PRIMITIVE_CURVE)) { N = ensure_valid_reflection(sd->Ng, sd->I, N); } @@ -191,7 +191,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, float3 clearcoat_normal = stack_valid(data_cn_ssr.x) ? stack_load_float3(stack, data_cn_ssr.x) : sd->N; - if (!(sd->type & PRIMITIVE_ALL_CURVE)) { + if (!(sd->type & PRIMITIVE_CURVE)) { clearcoat_normal = ensure_valid_reflection(sd->Ng, sd->I, clearcoat_normal); } float3 subsurface_radius = stack_valid(data_cn_ssr.y) ? @@ -902,7 +902,7 @@ ccl_device_noinline int svm_node_closure_bsdf(KernelGlobals kg, if (stack_valid(data_node.y)) { bsdf->T = normalize(stack_load_float3(stack, data_node.y)); } - else if (!(sd->type & PRIMITIVE_ALL_CURVE)) { + else if (!(sd->type & PRIMITIVE_CURVE)) { bsdf->T = normalize(sd->dPdv); bsdf->offset = 0.0f; } diff --git a/intern/cycles/kernel/svm/geometry.h b/intern/cycles/kernel/svm/geometry.h index 772942e0c08..2bac58b0aa2 100644 --- a/intern/cycles/kernel/svm/geometry.h +++ b/intern/cycles/kernel/svm/geometry.h @@ -227,7 +227,7 @@ ccl_device_noinline void svm_node_hair_info(KernelGlobals kg, switch (type) { case NODE_INFO_CURVE_IS_STRAND: { - data = (sd->type & PRIMITIVE_ALL_CURVE) != 0; + data = (sd->type & PRIMITIVE_CURVE) != 0; stack_store_float(stack, out_offset, data); break; } diff --git a/intern/cycles/kernel/svm/tex_coord.h b/intern/cycles/kernel/svm/tex_coord.h index 5e0debc968a..4b12a0065a6 100644 --- a/intern/cycles/kernel/svm/tex_coord.h +++ b/intern/cycles/kernel/svm/tex_coord.h @@ -291,7 +291,7 @@ ccl_device_noinline void svm_node_normal_map(KernelGlobals kg, if (space == NODE_NORMAL_MAP_TANGENT) { /* tangent space */ - if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_ALL_TRIANGLE) == 0) { + if (sd->object == OBJECT_NONE || (sd->type & PRIMITIVE_TRIANGLE) == 0) { /* Fallback to unperturbed normal. */ stack_store_float3(stack, normal_offset, sd->N); return; diff --git a/intern/cycles/kernel/svm/wireframe.h b/intern/cycles/kernel/svm/wireframe.h index 645dc59f22e..2c91ab3dedf 100644 --- a/intern/cycles/kernel/svm/wireframe.h +++ b/intern/cycles/kernel/svm/wireframe.h @@ -43,7 +43,7 @@ ccl_device_inline float wireframe(KernelGlobals kg, ccl_private float3 *P) { #if defined(__HAIR__) || defined(__POINTCLOUD__) - if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_ALL_TRIANGLE) + if (sd->prim != PRIM_NONE && sd->type & PRIMITIVE_TRIANGLE) #else if (sd->prim != PRIM_NONE) #endif @@ -54,10 +54,12 @@ ccl_device_inline float wireframe(KernelGlobals kg, /* Triangles */ int np = 3; - if (sd->type & PRIMITIVE_TRIANGLE) - triangle_vertices(kg, sd->prim, Co); - else + if (sd->type & PRIMITIVE_MOTION) { motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, Co); + } + else { + triangle_vertices(kg, sd->prim, Co); + } if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) { object_position_transform(kg, sd, &Co[0]); diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 855cc97edbf..5d41abb53c4 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -202,7 +202,7 @@ enum SamplingPattern { /* These flags values correspond to `raytypes` in `osl.cpp`, so keep them in sync! */ -enum PathRayFlag { +enum PathRayFlag : uint32_t { /* -------------------------------------------------------------------- * Ray visibility. * @@ -388,6 +388,7 @@ typedef enum PassType { PASS_DENOISING_NORMAL, PASS_DENOISING_ALBEDO, PASS_DENOISING_DEPTH, + PASS_DENOISING_PREVIOUS, /* PASS_SHADOW_CATCHER accumulates contribution of shadow catcher object which is not affected by * any other object. The pass accessor will divide the combined pass by the shadow catcher. The @@ -537,31 +538,34 @@ typedef struct Intersection { typedef enum PrimitiveType { PRIMITIVE_NONE = 0, PRIMITIVE_TRIANGLE = (1 << 0), - PRIMITIVE_MOTION_TRIANGLE = (1 << 1), - PRIMITIVE_CURVE_THICK = (1 << 2), - PRIMITIVE_MOTION_CURVE_THICK = (1 << 3), - PRIMITIVE_CURVE_RIBBON = (1 << 4), - PRIMITIVE_MOTION_CURVE_RIBBON = (1 << 5), - PRIMITIVE_POINT = (1 << 6), - PRIMITIVE_MOTION_POINT = (1 << 7), - PRIMITIVE_VOLUME = (1 << 8), - PRIMITIVE_LAMP = (1 << 9), - - PRIMITIVE_ALL_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION_TRIANGLE), - PRIMITIVE_ALL_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION_CURVE_THICK | - PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION_CURVE_RIBBON), - PRIMITIVE_ALL_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION_POINT), - PRIMITIVE_ALL_VOLUME = (PRIMITIVE_VOLUME), - PRIMITIVE_ALL_MOTION = (PRIMITIVE_MOTION_TRIANGLE | PRIMITIVE_MOTION_CURVE_THICK | - PRIMITIVE_MOTION_CURVE_RIBBON | PRIMITIVE_MOTION_POINT), - PRIMITIVE_ALL = (PRIMITIVE_ALL_TRIANGLE | PRIMITIVE_ALL_CURVE | PRIMITIVE_ALL_VOLUME | - PRIMITIVE_LAMP | PRIMITIVE_ALL_POINT), - - PRIMITIVE_NUM = 10, + PRIMITIVE_CURVE_THICK = (1 << 1), + PRIMITIVE_CURVE_RIBBON = (1 << 2), + PRIMITIVE_POINT = (1 << 3), + PRIMITIVE_VOLUME = (1 << 4), + PRIMITIVE_LAMP = (1 << 5), + + PRIMITIVE_MOTION = (1 << 6), + PRIMITIVE_MOTION_TRIANGLE = (PRIMITIVE_TRIANGLE | PRIMITIVE_MOTION), + PRIMITIVE_MOTION_CURVE_THICK = (PRIMITIVE_CURVE_THICK | PRIMITIVE_MOTION), + PRIMITIVE_MOTION_CURVE_RIBBON = (PRIMITIVE_CURVE_RIBBON | PRIMITIVE_MOTION), + PRIMITIVE_MOTION_POINT = (PRIMITIVE_POINT | PRIMITIVE_MOTION), + + PRIMITIVE_CURVE = (PRIMITIVE_CURVE_THICK | PRIMITIVE_CURVE_RIBBON), + + PRIMITIVE_ALL = (PRIMITIVE_TRIANGLE | PRIMITIVE_CURVE | PRIMITIVE_POINT | PRIMITIVE_VOLUME | + PRIMITIVE_LAMP | PRIMITIVE_MOTION), + + PRIMITIVE_NUM_SHAPES = 6, + PRIMITIVE_NUM_BITS = PRIMITIVE_NUM_SHAPES + 1, /* All shapes + motion bit. */ + PRIMITIVE_NUM = PRIMITIVE_NUM_SHAPES * 2, /* With and without motion. */ } PrimitiveType; -#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM) | (type)) -#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM) +/* Convert type to index in range 0..PRIMITIVE_NUM-1. */ +#define PRIMITIVE_INDEX(type) (bitscan((uint32_t)(type)) * 2 + (((type)&PRIMITIVE_MOTION) ? 1 : 0)) + +/* Pack segment into type value to save space. */ +#define PRIMITIVE_PACK_SEGMENT(type, segment) ((segment << PRIMITIVE_NUM_BITS) | (type)) +#define PRIMITIVE_UNPACK_SEGMENT(type) (type >> PRIMITIVE_NUM_BITS) typedef enum CurveShapeType { CURVE_RIBBON = 0, @@ -1556,7 +1560,7 @@ enum { /* Kernel Features */ -enum KernelFeatureFlag : unsigned int { +enum KernelFeatureFlag : uint32_t { /* Shader nodes. */ KERNEL_FEATURE_NODE_BSDF = (1U << 0U), KERNEL_FEATURE_NODE_EMISSION = (1U << 1U), diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 558b0e13b0f..49d18d00dd7 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -1002,10 +1002,10 @@ void GeometryManager::device_update_attributes(Device *device, /* After mesh attributes and patch tables have been copied to device memory, * we need to update offsets in the objects. */ - scene->object_manager->device_update_mesh_offsets(device, dscene, scene); + scene->object_manager->device_update_geom_offsets(device, dscene, scene); } -void GeometryManager::mesh_calc_offset(Scene *scene, BVHLayout bvh_layout) +void GeometryManager::geom_calc_offset(Scene *scene, BVHLayout bvh_layout) { size_t vert_size = 0; size_t tri_size = 0; @@ -1370,22 +1370,22 @@ enum { DEVICE_MESH_DATA_MODIFIED = (1 << 1), DEVICE_POINT_DATA_MODIFIED = (1 << 2), - ATTR_FLOAT_MODIFIED = (1 << 2), - ATTR_FLOAT2_MODIFIED = (1 << 3), - ATTR_FLOAT3_MODIFIED = (1 << 4), - ATTR_FLOAT4_MODIFIED = (1 << 5), - ATTR_UCHAR4_MODIFIED = (1 << 6), + ATTR_FLOAT_MODIFIED = (1 << 3), + ATTR_FLOAT2_MODIFIED = (1 << 4), + ATTR_FLOAT3_MODIFIED = (1 << 5), + ATTR_FLOAT4_MODIFIED = (1 << 6), + ATTR_UCHAR4_MODIFIED = (1 << 7), - CURVE_DATA_NEED_REALLOC = (1 << 7), - MESH_DATA_NEED_REALLOC = (1 << 8), - POINT_DATA_NEED_REALLOC = (1 << 9), + CURVE_DATA_NEED_REALLOC = (1 << 8), + MESH_DATA_NEED_REALLOC = (1 << 9), + POINT_DATA_NEED_REALLOC = (1 << 10), - ATTR_FLOAT_NEEDS_REALLOC = (1 << 10), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 11), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 12), - ATTR_FLOAT4_NEEDS_REALLOC = (1 << 13), + ATTR_FLOAT_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 12), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 13), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 14), - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 14), + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 15), ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | @@ -1922,7 +1922,7 @@ void GeometryManager::device_update(Device *device, const BVHLayout bvh_layout = BVHParams::best_bvh_layout(scene->params.bvh_layout, device->get_bvh_layout_mask()); - mesh_calc_offset(scene, bvh_layout); + geom_calc_offset(scene, bvh_layout); if (true_displacement_used || curve_shadow_transparency_used) { scoped_callback_timer timer([scene](double time) { if (scene->update_stats) { diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index b02387c3020..63ab2c2f4e0 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -242,7 +242,7 @@ class GeometryManager { vector<AttributeRequestSet> &object_attributes); /* Compute verts/triangles/curves offsets in global arrays. */ - void mesh_calc_offset(Scene *scene, BVHLayout bvh_layout); + void geom_calc_offset(Scene *scene, BVHLayout bvh_layout); void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress &progress); diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp index 8bb2d87fd1e..3595ca55a46 100644 --- a/intern/cycles/scene/image.cpp +++ b/intern/cycles/scene/image.cpp @@ -381,8 +381,15 @@ ImageHandle ImageManager::add_image(const string &filename, foreach (int tile, tiles) { string tile_filename = filename; + + /* Since we don't have information about the exact tile format used in this code location, + * just attempt all replacement patterns that Blender supports. */ if (tile != 0) { string_replace(tile_filename, "<UDIM>", string_printf("%04d", tile)); + + int u = ((tile - 1001) % 10); + int v = ((tile - 1001) / 10); + string_replace(tile_filename, "<UVTILE>", string_printf("u%d_v%d", u + 1, v + 1)); } const int slot = add_image_slot(new OIIOImageLoader(tile_filename), params, false); handle.tile_slots.push_back(slot); diff --git a/intern/cycles/scene/object.cpp b/intern/cycles/scene/object.cpp index f8110b20d6e..aa0a64f49ec 100644 --- a/intern/cycles/scene/object.cpp +++ b/intern/cycles/scene/object.cpp @@ -821,7 +821,7 @@ void ObjectManager::device_update_flags( dscene->object_volume_step.clear_modified(); } -void ObjectManager::device_update_mesh_offsets(Device *, DeviceScene *dscene, Scene *scene) +void ObjectManager::device_update_geom_offsets(Device *, DeviceScene *dscene, Scene *scene) { if (dscene->objects.size() == 0) { return; diff --git a/intern/cycles/scene/object.h b/intern/cycles/scene/object.h index f983b58b59c..3a97fabbdaa 100644 --- a/intern/cycles/scene/object.h +++ b/intern/cycles/scene/object.h @@ -162,7 +162,7 @@ class ObjectManager { Scene *scene, Progress &progress, bool bounds_valid = true); - void device_update_mesh_offsets(Device *device, DeviceScene *dscene, Scene *scene); + void device_update_geom_offsets(Device *device, DeviceScene *dscene, Scene *scene); void device_free(Device *device, DeviceScene *dscene, bool force_free); diff --git a/intern/cycles/scene/pass.cpp b/intern/cycles/scene/pass.cpp index a885ede50a4..ca5687e6b4d 100644 --- a/intern/cycles/scene/pass.cpp +++ b/intern/cycles/scene/pass.cpp @@ -101,6 +101,7 @@ const NodeEnum *Pass::get_type_enum() pass_type_enum.insert("denoising_normal", PASS_DENOISING_NORMAL); pass_type_enum.insert("denoising_albedo", PASS_DENOISING_ALBEDO); pass_type_enum.insert("denoising_depth", PASS_DENOISING_DEPTH); + pass_type_enum.insert("denoising_previous", PASS_DENOISING_PREVIOUS); pass_type_enum.insert("shadow_catcher", PASS_SHADOW_CATCHER); pass_type_enum.insert("shadow_catcher_sample_count", PASS_SHADOW_CATCHER_SAMPLE_COUNT); @@ -299,6 +300,10 @@ PassInfo Pass::get_info(const PassType type, const bool include_albedo) case PASS_DENOISING_DEPTH: pass_info.num_components = 1; break; + case PASS_DENOISING_PREVIOUS: + pass_info.num_components = 3; + pass_info.use_exposure = true; + break; case PASS_SHADOW_CATCHER: pass_info.num_components = 3; diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index c345d5bbc9a..e8316ad41b4 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -5901,7 +5901,7 @@ VectorMapRangeNode::VectorMapRangeNode() : ShaderNode(get_node_type()) { } -void VectorMapRangeNode::expand(ShaderGraph *graph) +void VectorMapRangeNode::expand(ShaderGraph * /*graph*/) { } diff --git a/intern/cycles/session/denoising.cpp b/intern/cycles/session/denoising.cpp index 21df068092a..b9021b9cbe2 100644 --- a/intern/cycles/session/denoising.cpp +++ b/intern/cycles/session/denoising.cpp @@ -16,62 +16,17 @@ #include "session/denoising.h" -#if 0 +#include "util/map.h" +#include "util/system.h" +#include "util/task.h" +#include "util/time.h" -# include "kernel/filter/filter_defines.h" - -# include "util/util_foreach.h" -# include "util/util_map.h" -# include "util/util_system.h" -# include "util/util_task.h" -# include "util/util_time.h" - -# include <OpenImageIO/filesystem.h> +#include <OpenImageIO/filesystem.h> CCL_NAMESPACE_BEGIN /* Utility Functions */ -static void print_progress(int num, int total, int frame, int num_frames) -{ - const char *label = "Denoise Frame "; - int cols = system_console_width(); - - cols -= strlen(label); - - int len = 1; - for (int x = total; x > 9; x /= 10) { - len++; - } - - int bars = cols - 2 * len - 6; - - printf("\r%s", label); - - if (num_frames > 1) { - int frame_len = 1; - for (int x = num_frames - 1; x > 9; x /= 10) { - frame_len++; - } - bars -= frame_len + 2; - printf("%*d ", frame_len, frame); - } - - int v = int(float(num) * bars / total); - printf("["); - for (int i = 0; i < v; i++) { - printf("="); - } - if (v < bars) { - printf(">"); - } - for (int i = v + 1; i < bars; i++) { - printf(" "); - } - printf(string_printf("] %%%dd / %d", len, total).c_str(), num); - fflush(stdout); -} - /* Splits in at its last dot, setting suffix to the part after the dot and in to the part before * it. Returns whether a dot was found. */ static bool split_last_dot(string &in, string &suffix) @@ -125,24 +80,18 @@ static void fill_mapping(vector<ChannelMapping> &map, int pos, string name, stri } } -static const int INPUT_NUM_CHANNELS = 15; -static const int INPUT_DENOISING_DEPTH = 0; -static const int INPUT_DENOISING_NORMAL = 1; -static const int INPUT_DENOISING_SHADOWING = 4; -static const int INPUT_DENOISING_ALBEDO = 5; -static const int INPUT_NOISY_IMAGE = 8; -static const int INPUT_DENOISING_VARIANCE = 11; -static const int INPUT_DENOISING_INTENSITY = 14; +static const int INPUT_NUM_CHANNELS = 13; +static const int INPUT_NOISY_IMAGE = 0; +static const int INPUT_DENOISING_NORMAL = 3; +static const int INPUT_DENOISING_ALBEDO = 6; +static const int INPUT_MOTION = 9; static vector<ChannelMapping> input_channels() { vector<ChannelMapping> map; - fill_mapping(map, INPUT_DENOISING_DEPTH, "Denoising Depth", "Z"); + fill_mapping(map, INPUT_NOISY_IMAGE, "Combined", "RGB"); fill_mapping(map, INPUT_DENOISING_NORMAL, "Denoising Normal", "XYZ"); - fill_mapping(map, INPUT_DENOISING_SHADOWING, "Denoising Shadowing", "X"); fill_mapping(map, INPUT_DENOISING_ALBEDO, "Denoising Albedo", "RGB"); - fill_mapping(map, INPUT_NOISY_IMAGE, "Noisy Image", "RGB"); - fill_mapping(map, INPUT_DENOISING_VARIANCE, "Denoising Variance", "RGB"); - fill_mapping(map, INPUT_DENOISING_INTENSITY, "Denoising Intensity", "X"); + fill_mapping(map, INPUT_MOTION, "Vector", "XYZW"); return map; } @@ -162,7 +111,7 @@ bool DenoiseImageLayer::detect_denoising_channels() input_to_image_channel.clear(); input_to_image_channel.resize(INPUT_NUM_CHANNELS, -1); - foreach (const ChannelMapping &mapping, input_channels()) { + for (const ChannelMapping &mapping : input_channels()) { vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); if (i == channels.end()) { return false; @@ -177,7 +126,7 @@ bool DenoiseImageLayer::detect_denoising_channels() output_to_image_channel.clear(); output_to_image_channel.resize(OUTPUT_NUM_CHANNELS, -1); - foreach (const ChannelMapping &mapping, output_channels()) { + for (const ChannelMapping &mapping : output_channels()) { vector<string>::iterator i = find(channels.begin(), channels.end(), mapping.name); if (i == channels.end()) { return false; @@ -199,18 +148,16 @@ bool DenoiseImageLayer::detect_denoising_channels() return true; } -bool DenoiseImageLayer::match_channels(int neighbor, - const std::vector<string> &channelnames, +bool DenoiseImageLayer::match_channels(const std::vector<string> &channelnames, const std::vector<string> &neighbor_channelnames) { - neighbor_input_to_image_channel.resize(neighbor + 1); - vector<int> &mapping = neighbor_input_to_image_channel[neighbor]; + vector<int> &mapping = previous_output_to_image_channel; assert(mapping.size() == 0); - mapping.resize(input_to_image_channel.size(), -1); + mapping.resize(output_to_image_channel.size(), -1); - for (int i = 0; i < input_to_image_channel.size(); i++) { - const string &channel = channelnames[input_to_image_channel[i]]; + for (int i = 0; i < output_to_image_channel.size(); i++) { + const string &channel = channelnames[output_to_image_channel[i]]; std::vector<string>::const_iterator frame_channel = find( neighbor_channelnames.begin(), neighbor_channelnames.end(), channel); @@ -226,19 +173,9 @@ bool DenoiseImageLayer::match_channels(int neighbor, /* Denoise Task */ -DenoiseTask::DenoiseTask(Device *device, - DenoiserPipeline *denoiser, - int frame, - const vector<int> &neighbor_frames) - : denoiser(denoiser), - device(device), - frame(frame), - neighbor_frames(neighbor_frames), - current_layer(0), - input_pixels(device, "filter input buffer", MEM_READ_ONLY), - num_tiles(0) +DenoiseTask::DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame) + : denoiser(denoiser), device(device), frame(frame), current_layer(0), buffers(device) { - image.samples = denoiser->samples_override; } DenoiseTask::~DenoiseTask() @@ -246,284 +183,39 @@ DenoiseTask::~DenoiseTask() free(); } -/* Device callbacks */ - -bool DenoiseTask::acquire_tile(Device *device, Device *tile_device, RenderTile &tile) -{ - thread_scoped_lock tile_lock(tiles_mutex); - - if (tiles.empty()) { - return false; - } - - tile = tiles.front(); - tiles.pop_front(); - - device->map_tile(tile_device, tile); - - print_progress(num_tiles - tiles.size(), num_tiles, frame, denoiser->num_frames); - - return true; -} - -/* Mapping tiles is required for regular rendering since each tile has its separate memory - * which may be allocated on a different device. - * For standalone denoising, there is a single memory that is present on all devices, so the only - * thing that needs to be done here is to specify the surrounding tile geometry. - * - * However, since there is only one large memory, the denoised result has to be written to - * a different buffer to avoid having to copy an entire horizontal slice of the image. */ -void DenoiseTask::map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device) -{ - RenderTile ¢er_tile = neighbors.tiles[RenderTileNeighbors::CENTER]; - RenderTile &target_tile = neighbors.target; - - /* Fill tile information. */ - for (int i = 0; i < RenderTileNeighbors::SIZE; i++) { - if (i == RenderTileNeighbors::CENTER) { - continue; - } - - RenderTile &tile = neighbors.tiles[i]; - int dx = (i % 3) - 1; - int dy = (i / 3) - 1; - tile.x = clamp(center_tile.x + dx * denoiser->tile_size.x, 0, image.width); - tile.w = clamp(center_tile.x + (dx + 1) * denoiser->tile_size.x, 0, image.width) - tile.x; - tile.y = clamp(center_tile.y + dy * denoiser->tile_size.y, 0, image.height); - tile.h = clamp(center_tile.y + (dy + 1) * denoiser->tile_size.y, 0, image.height) - tile.y; - - tile.buffer = center_tile.buffer; - tile.offset = center_tile.offset; - tile.stride = image.width; - } - - /* Allocate output buffer. */ - device_vector<float> *output_mem = new device_vector<float>( - tile_device, "denoising_output", MEM_READ_WRITE); - output_mem->alloc(OUTPUT_NUM_CHANNELS * center_tile.w * center_tile.h); - - /* Fill output buffer with noisy image, assumed by kernel_filter_finalize - * when skipping denoising of some pixels. */ - float *result = output_mem->data(); - float *in = &image.pixels[image.num_channels * (center_tile.y * image.width + center_tile.x)]; - - const DenoiseImageLayer &layer = image.layers[current_layer]; - const int *input_to_image_channel = layer.input_to_image_channel.data(); - - for (int y = 0; y < center_tile.h; y++) { - for (int x = 0; x < center_tile.w; x++, result += OUTPUT_NUM_CHANNELS) { - for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { - result[i] = in[image.num_channels * x + input_to_image_channel[INPUT_NOISY_IMAGE + i]]; - } - } - in += image.num_channels * image.width; - } - - output_mem->copy_to_device(); - - /* Fill output tile info. */ - target_tile = center_tile; - target_tile.buffer = output_mem->device_pointer; - target_tile.stride = target_tile.w; - target_tile.offset -= target_tile.x + target_tile.y * target_tile.stride; - - thread_scoped_lock output_lock(output_mutex); - assert(output_pixels.count(center_tile.tile_index) == 0); - output_pixels[target_tile.tile_index] = output_mem; -} - -void DenoiseTask::unmap_neighboring_tiles(RenderTileNeighbors &neighbors) -{ - RenderTile ¢er_tile = neighbors.tiles[RenderTileNeighbors::CENTER]; - RenderTile &target_tile = neighbors.target; - - thread_scoped_lock output_lock(output_mutex); - assert(output_pixels.count(center_tile.tile_index) == 1); - device_vector<float> *output_mem = output_pixels[target_tile.tile_index]; - output_pixels.erase(center_tile.tile_index); - output_lock.unlock(); - - /* Copy denoised pixels from device. */ - output_mem->copy_from_device(0, OUTPUT_NUM_CHANNELS * target_tile.w, target_tile.h); - - float *result = output_mem->data(); - float *out = &image.pixels[image.num_channels * (target_tile.y * image.width + target_tile.x)]; - - const DenoiseImageLayer &layer = image.layers[current_layer]; - const int *output_to_image_channel = layer.output_to_image_channel.data(); - - for (int y = 0; y < target_tile.h; y++) { - for (int x = 0; x < target_tile.w; x++, result += OUTPUT_NUM_CHANNELS) { - for (int i = 0; i < OUTPUT_NUM_CHANNELS; i++) { - out[image.num_channels * x + output_to_image_channel[i]] = result[i]; - } - } - out += image.num_channels * image.width; - } - - /* Free device buffer. */ - output_mem->free(); - delete output_mem; -} - -void DenoiseTask::release_tile() -{ -} - -bool DenoiseTask::get_cancel() -{ - return false; -} - -void DenoiseTask::create_task(DeviceTask &task) -{ - /* Callback functions. */ - task.acquire_tile = function_bind(&DenoiseTask::acquire_tile, this, device, _1, _2); - task.map_neighbor_tiles = function_bind(&DenoiseTask::map_neighboring_tiles, this, _1, _2); - task.unmap_neighbor_tiles = function_bind(&DenoiseTask::unmap_neighboring_tiles, this, _1); - task.release_tile = function_bind(&DenoiseTask::release_tile, this); - task.get_cancel = function_bind(&DenoiseTask::get_cancel, this); - - /* Denoising parameters. */ - task.denoising = denoiser->params; - task.denoising.type = DENOISER_NLM; - task.denoising.use = true; - task.denoising_from_render = false; - - task.denoising_frames.resize(neighbor_frames.size()); - for (int i = 0; i < neighbor_frames.size(); i++) { - task.denoising_frames[i] = neighbor_frames[i] - frame; - } - - /* Buffer parameters. */ - task.pass_stride = INPUT_NUM_CHANNELS; - task.target_pass_stride = OUTPUT_NUM_CHANNELS; - task.pass_denoising_data = 0; - task.pass_denoising_clean = -1; - task.frame_stride = image.width * image.height * INPUT_NUM_CHANNELS; - - /* Create tiles. */ - thread_scoped_lock tile_lock(tiles_mutex); - thread_scoped_lock output_lock(output_mutex); - - tiles.clear(); - assert(output_pixels.empty()); - output_pixels.clear(); - - int tiles_x = divide_up(image.width, denoiser->tile_size.x); - int tiles_y = divide_up(image.height, denoiser->tile_size.y); - - for (int ty = 0; ty < tiles_y; ty++) { - for (int tx = 0; tx < tiles_x; tx++) { - RenderTile tile; - tile.x = tx * denoiser->tile_size.x; - tile.y = ty * denoiser->tile_size.y; - tile.w = min(image.width - tile.x, denoiser->tile_size.x); - tile.h = min(image.height - tile.y, denoiser->tile_size.y); - tile.start_sample = 0; - tile.num_samples = image.layers[current_layer].samples; - tile.sample = 0; - tile.offset = 0; - tile.stride = image.width; - tile.tile_index = ty * tiles_x + tx; - tile.task = RenderTile::DENOISE; - tile.buffers = NULL; - tile.buffer = input_pixels.device_pointer; - tiles.push_back(tile); - } - } - - num_tiles = tiles.size(); -} - /* Denoiser Operations */ bool DenoiseTask::load_input_pixels(int layer) { - int w = image.width; - int h = image.height; - int num_pixels = image.width * image.height; - int frame_stride = num_pixels * INPUT_NUM_CHANNELS; - /* Load center image */ DenoiseImageLayer &image_layer = image.layers[layer]; - float *buffer_data = input_pixels.data(); - image.read_pixels(image_layer, buffer_data); - buffer_data += frame_stride; - - /* Load neighbor images */ - for (int i = 0; i < image.in_neighbors.size(); i++) { - if (!image.read_neighbor_pixels(i, image_layer, buffer_data)) { - error = "Failed to read neighbor frame pixels"; - return false; - } - buffer_data += frame_stride; - } - - /* Preprocess */ - buffer_data = input_pixels.data(); - for (int neighbor = 0; neighbor < image.in_neighbors.size() + 1; neighbor++) { - /* Clamp */ - if (denoiser->params.clamp_input) { - for (int i = 0; i < num_pixels * INPUT_NUM_CHANNELS; i++) { - buffer_data[i] = clamp(buffer_data[i], -1e8f, 1e8f); - } - } - - /* Box blur */ - int r = 5 * denoiser->params.radius; - float *data = buffer_data + 14; - array<float> temp(num_pixels); - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int n = 0; - float sum = 0.0f; - for (int dx = max(x - r, 0); dx < min(x + r + 1, w); dx++, n++) { - sum += data[INPUT_NUM_CHANNELS * (y * w + dx)]; - } - temp[y * w + x] = sum / n; - } - } - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int n = 0; - float sum = 0.0f; - - for (int dy = max(y - r, 0); dy < min(y + r + 1, h); dy++, n++) { - sum += temp[dy * w + x]; - } + float *buffer_data = buffers.buffer.data(); + image.read_pixels(image_layer, buffers.params, buffer_data); - data[INPUT_NUM_CHANNELS * (y * w + x)] = sum / n; - } - } - - /* Highlight compression */ - data = buffer_data + 8; - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - int idx = INPUT_NUM_CHANNELS * (y * w + x); - float3 color = make_float3(data[idx], data[idx + 1], data[idx + 2]); - color = color_highlight_compress(color, NULL); - data[idx] = color.x; - data[idx + 1] = color.y; - data[idx + 2] = color.z; - } - } - - buffer_data += frame_stride; + /* Load previous image */ + if (frame > 0 && !image.read_previous_pixels(image_layer, buffers.params, buffer_data)) { + error = "Failed to read neighbor frame pixels"; + return false; } /* Copy to device */ - input_pixels.copy_to_device(); + buffers.buffer.copy_to_device(); return true; } /* Task stages */ +static void add_pass(vector<Pass *> &passes, PassType type, PassMode mode = PassMode::NOISY) +{ + Pass *pass = new Pass(); + pass->set_type(type); + pass->set_mode(mode); + + passes.push_back(pass); +} + bool DenoiseTask::load() { string center_filepath = denoiser->input[frame]; @@ -531,7 +223,8 @@ bool DenoiseTask::load() return false; } - if (!image.load_neighbors(denoiser->input, neighbor_frames, error)) { + /* Use previous frame output as input for subsequent frames. */ + if (frame > 0 && !image.load_previous(denoiser->output[frame - 1], error)) { return false; } @@ -540,10 +233,35 @@ bool DenoiseTask::load() return false; } + /* Enable temporal denoising for frames after the first (which will use the output from the + * previous frames). */ + DenoiseParams params = denoiser->denoiser->get_params(); + params.temporally_stable = frame > 0; + denoiser->denoiser->set_params(params); + /* Allocate device buffer. */ - int num_frames = image.in_neighbors.size() + 1; - input_pixels.alloc(image.width * INPUT_NUM_CHANNELS, image.height * num_frames); - input_pixels.zero_to_device(); + vector<Pass *> passes; + add_pass(passes, PassType::PASS_COMBINED); + add_pass(passes, PassType::PASS_DENOISING_ALBEDO); + add_pass(passes, PassType::PASS_DENOISING_NORMAL); + add_pass(passes, PassType::PASS_MOTION); + add_pass(passes, PassType::PASS_DENOISING_PREVIOUS); + add_pass(passes, PassType::PASS_COMBINED, PassMode::DENOISED); + + BufferParams buffer_params; + buffer_params.width = image.width; + buffer_params.height = image.height; + buffer_params.full_x = 0; + buffer_params.full_y = 0; + buffer_params.full_width = image.width; + buffer_params.full_height = image.height; + buffer_params.update_passes(passes); + + for (Pass *pass : passes) { + delete pass; + } + + buffers.reset(buffer_params); /* Read pixels for first layer. */ current_layer = 0; @@ -565,10 +283,26 @@ bool DenoiseTask::exec() } /* Run task on device. */ - DeviceTask task(DeviceTask::RENDER); - create_task(task); - device->task_add(task); - device->task_wait(); + denoiser->denoiser->denoise_buffer(buffers.params, &buffers, 1, true); + + /* Copy denoised pixels from device. */ + buffers.buffer.copy_from_device(); + + float *result = buffers.buffer.data(), *out = image.pixels.data(); + + const DenoiseImageLayer &layer = image.layers[current_layer]; + const int *output_to_image_channel = layer.output_to_image_channel.data(); + + for (int y = 0; y < image.height; y++) { + for (int x = 0; x < image.width; x++, result += buffers.params.pass_stride) { + for (int j = 0; j < OUTPUT_NUM_CHANNELS; j++) { + int offset = buffers.params.get_pass_offset(PASS_COMBINED, PassMode::DENOISED); + int image_channel = output_to_image_channel[j]; + out[image.num_channels * x + image_channel] = result[offset + j]; + } + } + out += image.num_channels * image.width; + } printf("\n"); } @@ -586,8 +320,7 @@ bool DenoiseTask::save() void DenoiseTask::free() { image.free(); - input_pixels.free(); - assert(output_pixels.empty()); + buffers.buffer.free(); } /* Denoise Image Storage */ @@ -607,7 +340,7 @@ DenoiseImage::~DenoiseImage() void DenoiseImage::close_input() { - in_neighbors.clear(); + in_previous.reset(); } void DenoiseImage::free() @@ -677,39 +410,61 @@ bool DenoiseImage::parse_channels(const ImageSpec &in_spec, string &error) return true; } -void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, float *input_pixels) +void DenoiseImage::read_pixels(const DenoiseImageLayer &layer, + const BufferParams ¶ms, + float *input_pixels) { /* Pixels from center file have already been loaded into pixels. * We copy a subset into the device input buffer with channels reshuffled. */ const int *input_to_image_channel = layer.input_to_image_channel.data(); for (int i = 0; i < width * height; i++) { - for (int j = 0; j < INPUT_NUM_CHANNELS; j++) { - int image_channel = input_to_image_channel[j]; - input_pixels[i * INPUT_NUM_CHANNELS + j] = + for (int j = 0; j < 3; ++j) { + int offset = params.get_pass_offset(PASS_COMBINED); + int image_channel = input_to_image_channel[INPUT_NOISY_IMAGE + j]; + input_pixels[i * params.pass_stride + offset + j] = + pixels[((size_t)i) * num_channels + image_channel]; + } + for (int j = 0; j < 3; ++j) { + int offset = params.get_pass_offset(PASS_DENOISING_NORMAL); + int image_channel = input_to_image_channel[INPUT_DENOISING_NORMAL + j]; + input_pixels[i * params.pass_stride + offset + j] = + pixels[((size_t)i) * num_channels + image_channel]; + } + for (int j = 0; j < 3; ++j) { + int offset = params.get_pass_offset(PASS_DENOISING_ALBEDO); + int image_channel = input_to_image_channel[INPUT_DENOISING_ALBEDO + j]; + input_pixels[i * params.pass_stride + offset + j] = + pixels[((size_t)i) * num_channels + image_channel]; + } + for (int j = 0; j < 4; ++j) { + int offset = params.get_pass_offset(PASS_MOTION); + int image_channel = input_to_image_channel[INPUT_MOTION + j]; + input_pixels[i * params.pass_stride + offset + j] = pixels[((size_t)i) * num_channels + image_channel]; } } } -bool DenoiseImage::read_neighbor_pixels(int neighbor, - const DenoiseImageLayer &layer, +bool DenoiseImage::read_previous_pixels(const DenoiseImageLayer &layer, + const BufferParams ¶ms, float *input_pixels) { /* Load pixels from neighboring frames, and copy them into device buffer * with channels reshuffled. */ size_t num_pixels = (size_t)width * (size_t)height; array<float> neighbor_pixels(num_pixels * num_channels); - if (!in_neighbors[neighbor]->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) { + if (!in_previous->read_image(TypeDesc::FLOAT, neighbor_pixels.data())) { return false; } - const int *input_to_image_channel = layer.neighbor_input_to_image_channel[neighbor].data(); + const int *output_to_image_channel = layer.previous_output_to_image_channel.data(); for (int i = 0; i < width * height; i++) { - for (int j = 0; j < INPUT_NUM_CHANNELS; j++) { - int image_channel = input_to_image_channel[j]; - input_pixels[i * INPUT_NUM_CHANNELS + j] = + for (int j = 0; j < 3; ++j) { + int offset = params.get_pass_offset(PASS_DENOISING_PREVIOUS); + int image_channel = output_to_image_channel[j]; + input_pixels[i * params.pass_stride + offset + j] = neighbor_pixels[((size_t)i) * num_channels + image_channel]; } } @@ -739,8 +494,8 @@ bool DenoiseImage::load(const string &in_filepath, string &error) return false; } - if (layers.size() == 0) { - error = "Could not find a render layer containing denoising info"; + if (layers.empty()) { + error = "Could not find a render layer containing denoising data and motion vector passes"; return false; } @@ -757,46 +512,34 @@ bool DenoiseImage::load(const string &in_filepath, string &error) return true; } -bool DenoiseImage::load_neighbors(const vector<string> &filepaths, - const vector<int> &frames, - string &error) +bool DenoiseImage::load_previous(const string &filepath, string &error) { - if (frames.size() > DENOISE_MAX_FRAMES - 1) { - error = string_printf("Maximum number of neighbors (%d) exceeded\n", DENOISE_MAX_FRAMES - 1); + if (!Filesystem::is_regular(filepath)) { + error = "Couldn't find neighbor frame: " + filepath; return false; } - for (int neighbor = 0; neighbor < frames.size(); neighbor++) { - int frame = frames[neighbor]; - const string &filepath = filepaths[frame]; - - if (!Filesystem::is_regular(filepath)) { - error = "Couldn't find neighbor frame: " + filepath; - return false; - } + unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath)); + if (!in_neighbor) { + error = "Couldn't open neighbor frame: " + filepath; + return false; + } - unique_ptr<ImageInput> in_neighbor(ImageInput::open(filepath)); - if (!in_neighbor) { - error = "Couldn't open neighbor frame: " + filepath; - return false; - } + const ImageSpec &neighbor_spec = in_neighbor->spec(); + if (neighbor_spec.width != width || neighbor_spec.height != height) { + error = "Neighbor frame has different dimensions: " + filepath; + return false; + } - const ImageSpec &neighbor_spec = in_neighbor->spec(); - if (neighbor_spec.width != width || neighbor_spec.height != height) { - error = "Neighbor frame has different dimensions: " + filepath; + for (DenoiseImageLayer &layer : layers) { + if (!layer.match_channels(in_spec.channelnames, neighbor_spec.channelnames)) { + error = "Neighbor frame misses denoising data passes: " + filepath; return false; } - - foreach (DenoiseImageLayer &layer, layers) { - if (!layer.match_channels(neighbor, in_spec.channelnames, neighbor_spec.channelnames)) { - error = "Neighbor frame misses denoising data passes: " + filepath; - return false; - } - } - - in_neighbors.push_back(std::move(in_neighbor)); } + in_previous = std::move(in_neighbor); + return true; } @@ -864,24 +607,22 @@ bool DenoiseImage::save_output(const string &out_filepath, string &error) /* File pattern handling and outer loop over frames */ -DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info) +DenoiserPipeline::DenoiserPipeline(DeviceInfo &device_info, const DenoiseParams ¶ms) { - samples_override = 0; - tile_size = make_int2(64, 64); - - num_frames = 0; - /* Initialize task scheduler. */ TaskScheduler::init(); /* Initialize device. */ - device = Device::create(device_info, stats, profiler, true); - + device = Device::create(device_info, stats, profiler); device->load_kernels(KERNEL_FEATURE_DENOISING); + + denoiser = Denoiser::create(device, params); + denoiser->load_kernels(nullptr); } DenoiserPipeline::~DenoiserPipeline() { + denoiser.reset(); delete device; TaskScheduler::exit(); } @@ -890,7 +631,7 @@ bool DenoiserPipeline::run() { assert(input.size() == output.size()); - num_frames = output.size(); + int num_frames = output.size(); for (int frame = 0; frame < num_frames; frame++) { /* Skip empty output paths. */ @@ -898,16 +639,8 @@ bool DenoiserPipeline::run() continue; } - /* Determine neighbor frame numbers that should be used for filtering. */ - vector<int> neighbor_frames; - for (int f = frame - params.neighbor_frames; f <= frame + params.neighbor_frames; f++) { - if (f >= 0 && f < num_frames && f != frame) { - neighbor_frames.push_back(f); - } - } - /* Execute task. */ - DenoiseTask task(device, this, frame, neighbor_frames); + DenoiseTask task(device, this, frame); if (!task.load()) { error = task.error; return false; @@ -930,5 +663,3 @@ bool DenoiserPipeline::run() } CCL_NAMESPACE_END - -#endif diff --git a/intern/cycles/session/denoising.h b/intern/cycles/session/denoising.h index 097cc570d06..15e691f73fd 100644 --- a/intern/cycles/session/denoising.h +++ b/intern/cycles/session/denoising.h @@ -17,20 +17,17 @@ #ifndef __DENOISING_H__ #define __DENOISING_H__ -#if 0 - /* TODO(sergey): Make it explicit and clear when something is a denoiser, its pipeline or * parameters. Currently it is an annoying mixture of terms used interchangeably. */ -# include "device/device.h" - -# include "render/buffers.h" +#include "device/device.h" +#include "integrator/denoiser.h" -# include "util/util_string.h" -# include "util/util_unique_ptr.h" -# include "util/util_vector.h" +#include "util/string.h" +#include "util/unique_ptr.h" +#include "util/vector.h" -# include <OpenImageIO/imageio.h> +#include <OpenImageIO/imageio.h> OIIO_NAMESPACE_USING @@ -40,7 +37,7 @@ CCL_NAMESPACE_BEGIN class DenoiserPipeline { public: - DenoiserPipeline(DeviceInfo &device_info); + DenoiserPipeline(DeviceInfo &device_info, const DenoiseParams ¶ms); ~DenoiserPipeline(); bool run(); @@ -55,22 +52,13 @@ class DenoiserPipeline { * taking into account all input frames. */ vector<string> output; - /* Sample number override, takes precedence over values from input frames. */ - int samples_override; - /* Tile size for processing on device. */ - int2 tile_size; - - /* Equivalent to the settings in the regular denoiser. */ - DenoiseParams params; - protected: friend class DenoiseTask; Stats stats; Profiler profiler; Device *device; - - int num_frames; + std::unique_ptr<Denoiser> denoiser; }; /* Denoise Image Layer */ @@ -88,13 +76,13 @@ struct DenoiseImageLayer { /* Device input channel will be copied from image channel input_to_image_channel[i]. */ vector<int> input_to_image_channel; - /* input_to_image_channel of the secondary frames, if any are used. */ - vector<vector<int>> neighbor_input_to_image_channel; - /* Write i-th channel of the processing output to output_to_image_channel[i]-th channel of the * file. */ vector<int> output_to_image_channel; + /* output_to_image_channel of the previous frame, if used. */ + vector<int> previous_output_to_image_channel; + /* Detect whether this layer contains a full set of channels and set up the offsets accordingly. */ bool detect_denoising_channels(); @@ -102,8 +90,7 @@ struct DenoiseImageLayer { /* Map the channels of a secondary frame to the channels that are required for processing, * fill neighbor_input_to_image_channel if all are present or return false if a channel are * missing. */ - bool match_channels(int neighbor, - const std::vector<string> &channelnames, + bool match_channels(const std::vector<string> &channelnames, const std::vector<string> &neighbor_channelnames); }; @@ -125,7 +112,7 @@ class DenoiseImage { /* Image file handles */ ImageSpec in_spec; - vector<unique_ptr<ImageInput>> in_neighbors; + unique_ptr<ImageInput> in_previous; /* Render layers */ vector<DenoiseImageLayer> layers; @@ -137,12 +124,16 @@ class DenoiseImage { bool load(const string &in_filepath, string &error); /* Load neighboring frames. */ - bool load_neighbors(const vector<string> &filepaths, const vector<int> &frames, string &error); + bool load_previous(const string &in_filepath, string &error); /* Load subset of pixels from file buffer into input buffer, as needed for denoising * on the device. Channels are reshuffled following the provided mapping. */ - void read_pixels(const DenoiseImageLayer &layer, float *input_pixels); - bool read_neighbor_pixels(int neighbor, const DenoiseImageLayer &layer, float *input_pixels); + void read_pixels(const DenoiseImageLayer &layer, + const BufferParams ¶ms, + float *input_pixels); + bool read_previous_pixels(const DenoiseImageLayer &layer, + const BufferParams ¶ms, + float *input_pixels); bool save_output(const string &out_filepath, string &error); @@ -159,10 +150,7 @@ class DenoiseImage { class DenoiseTask { public: - DenoiseTask(Device *device, - DenoiserPipeline *denoiser, - int frame, - const vector<int> &neighbor_frames); + DenoiseTask(Device *device, DenoiserPipeline *denoiser, int frame); ~DenoiseTask(); /* Task stages */ @@ -180,37 +168,17 @@ class DenoiseTask { /* Frame number to be denoised */ int frame; - vector<int> neighbor_frames; /* Image file data */ DenoiseImage image; int current_layer; - /* Device input buffer */ - device_vector<float> input_pixels; - - /* Tiles */ - thread_mutex tiles_mutex; - list<RenderTile> tiles; - int num_tiles; - - thread_mutex output_mutex; - map<int, device_vector<float> *> output_pixels; + RenderBuffers buffers; /* Task handling */ bool load_input_pixels(int layer); - void create_task(DeviceTask &task); - - /* Device task callbacks */ - bool acquire_tile(Device *device, Device *tile_device, RenderTile &tile); - void map_neighboring_tiles(RenderTileNeighbors &neighbors, Device *tile_device); - void unmap_neighboring_tiles(RenderTileNeighbors &neighbors); - void release_tile(); - bool get_cancel(); }; CCL_NAMESPACE_END -#endif - #endif /* __DENOISING_H__ */ diff --git a/intern/ghost/intern/GHOST_Window.h b/intern/ghost/intern/GHOST_Window.h index 69d0eea838c..a3eb116780f 100644 --- a/intern/ghost/intern/GHOST_Window.h +++ b/intern/ghost/intern/GHOST_Window.h @@ -41,8 +41,8 @@ class GHOST_Window : public GHOST_IWindow { * Constructor. * Creates a new window and opens it. * To check if the window was created properly, use the getValid() method. - * \param width: The width the window. - * \param height: The height the window. + * \param width: The width of the window. + * \param height: The height of the window. * \param state: The state the window is initially opened with. * \param wantStereoVisual: Stereo visual for quad buffered stereo. * \param exclusive: Use to show the window ontop and ignore others (used full-screen). diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 3c006b9a70c..8a20323dcfc 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -259,6 +259,50 @@ void MEM_use_guarded_allocator(void); #endif /* __cplusplus */ #ifdef __cplusplus + +# include <new> +# include <type_traits> +# include <utility> + +/** + * Allocate new memory for and constructs an object of type #T. + * #MEM_delete should be used to delete the object. Just calling #MEM_freeN is not enough when #T + * is not a trivial type. + */ +template<typename T, typename... Args> +inline T *MEM_new(const char *allocation_name, Args &&...args) +{ + void *buffer = MEM_mallocN(sizeof(T), allocation_name); + return new (buffer) T(std::forward<Args>(args)...); +} + +/** + * Allocates zero-initialized memory for an object of type #T. The constructor of #T is not called, + * therefor this should only used with trivial types (like all C types). + * It's valid to call #MEM_freeN on a pointer returned by this, because a destructor call is not + * necessary, because the type is trivial. + */ +template<typename T> inline T *MEM_cnew(const char *allocation_name) +{ + static_assert(std::is_trivial_v<T>, "For non-trivial types, MEM_new should be used."); + return static_cast<T *>(MEM_callocN(sizeof(T), allocation_name)); +} + +/** + * Destructs and deallocates an object previously allocated with any `MEM_*` function. + * Passing in null does nothing. + */ +template<typename T> inline void MEM_delete(const T *ptr) +{ + if (ptr == nullptr) { + /* Support #ptr being null, because C++ `delete` supports that as well. */ + return; + } + /* C++ allows destruction of const objects, so the pointer is allowed to be const. */ + ptr->~T(); + MEM_freeN(const_cast<T *>(ptr)); +} + /* Allocation functions (for C++ only). */ # define MEM_CXX_CLASS_ALLOC_FUNCS(_id) \ public: \ @@ -292,36 +336,6 @@ void MEM_use_guarded_allocator(void); { \ } -/* Needed when type includes a namespace, then the namespace should not be - * specified after ~, so using a macro fails. */ -template<class T> inline void OBJECT_GUARDED_DESTRUCTOR(T *what) -{ - what->~T(); -} - -# if defined __GNUC__ -# define OBJECT_GUARDED_NEW(type, args...) new (MEM_mallocN(sizeof(type), __func__)) type(args) -# else -# define OBJECT_GUARDED_NEW(type, ...) \ - new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__) -# endif -# define OBJECT_GUARDED_DELETE(what, type) \ - { \ - if (what) { \ - OBJECT_GUARDED_DESTRUCTOR((type *)what); \ - MEM_freeN(what); \ - } \ - } \ - (void)0 -# define OBJECT_GUARDED_SAFE_DELETE(what, type) \ - { \ - if (what) { \ - OBJECT_GUARDED_DESTRUCTOR((type *)what); \ - MEM_freeN(what); \ - what = NULL; \ - } \ - } \ - (void)0 #endif /* __cplusplus */ #endif /* __MEM_GUARDEDALLOC_H__ */ diff --git a/intern/iksolver/intern/IK_QJacobian.cpp b/intern/iksolver/intern/IK_QJacobian.cpp index 19d711f3fe1..7e4d48e37c9 100644 --- a/intern/iksolver/intern/IK_QJacobian.cpp +++ b/intern/iksolver/intern/IK_QJacobian.cpp @@ -196,12 +196,12 @@ void IK_QJacobian::InvertSDLS() // Compute the dampeds least squeares pseudo inverse of J. // // Since J is usually not invertible (most of the times it's not even - // square), the psuedo inverse is used. This gives us a least squares + // square), the pseudo inverse is used. This gives us a least squares // solution. // // This is fine when the J*Jt is of full rank. When J*Jt is near to // singular the least squares inverse tries to minimize |J(dtheta) - dX)| - // and doesn't try to minimize dTheta. This results in eratic changes in + // and doesn't try to minimize dTheta. This results in erratic changes in // angle. The damped least squares minimizes |dtheta| to try and reduce this // erratic behavior. // @@ -323,7 +323,7 @@ void IK_QJacobian::InvertDLS() // least squares solution. This is fine when the m_jjt is // of full rank. When m_jjt is near to singular the least squares // inverse tries to minimize |J(dtheta) - dX)| and doesn't - // try to minimize dTheta. This results in eratic changes in angle. + // try to minimize dTheta. This results in erratic changes in angle. // Damped least squares minimizes |dtheta| to try and reduce this // erratic behavior. diff --git a/intern/libmv/intern/utildefines.h b/intern/libmv/intern/utildefines.h index 052052a1d76..8b37253698d 100644 --- a/intern/libmv/intern/utildefines.h +++ b/intern/libmv/intern/utildefines.h @@ -27,9 +27,21 @@ #ifdef WITH_LIBMV_GUARDED_ALLOC # include "MEM_guardedalloc.h" -# define LIBMV_OBJECT_NEW OBJECT_GUARDED_NEW -# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE -# define LIBMV_OBJECT_DELETE OBJECT_GUARDED_DELETE +# if defined __GNUC__ +# define LIBMV_OBJECT_NEW(type, args...) \ + new (MEM_mallocN(sizeof(type), __func__)) type(args) +# else +# define LIBMV_OBJECT_NEW(type, ...) \ + new (MEM_mallocN(sizeof(type), __FUNCTION__)) type(__VA_ARGS__) +# endif +# define LIBMV_OBJECT_DELETE(what, type) \ + { \ + if (what) { \ + ((type*)what)->~type(); \ + MEM_freeN(what); \ + } \ + } \ + (void)0 # define LIBMV_STRUCT_NEW(type, count) \ (type*)MEM_mallocN(sizeof(type) * count, __func__) # define LIBMV_STRUCT_DELETE(what) MEM_freeN(what) diff --git a/intern/libmv/libmv/autotrack/autotrack.cc b/intern/libmv/libmv/autotrack/autotrack.cc index afdf48912e5..a407639ecfa 100644 --- a/intern/libmv/libmv/autotrack/autotrack.cc +++ b/intern/libmv/libmv/autotrack/autotrack.cc @@ -178,7 +178,7 @@ bool AutoTrack::TrackMarker(Marker* tracked_marker, return false; } - // Store original position befoer tracking, so we can claculate offset later. + // Store original position before tracking, so we can claculate offset later. Vec2f original_center = tracked_marker->center; // Do the tracking! diff --git a/intern/libmv/libmv/build/build_config.h b/intern/libmv/libmv/build/build_config.h index 7029a36a7dd..1d87660f87c 100644 --- a/intern/libmv/libmv/build/build_config.h +++ b/intern/libmv/libmv/build/build_config.h @@ -239,7 +239,7 @@ // Check what is the latest C++ specification the compiler supports. // // NOTE: Use explicit definition here to avoid expansion-to-defined warning from -// being geenrated. While this will most likely a false-positive warning in this +// being generated. While this will most likely a false-positive warning in this // particular case, that warning might be helpful to catch errors elsewhere. // C++11 check. diff --git a/intern/libmv/libmv/image/tuple.h b/intern/libmv/libmv/image/tuple.h index 447bf0cc81c..3f4b58886e4 100644 --- a/intern/libmv/libmv/image/tuple.h +++ b/intern/libmv/libmv/image/tuple.h @@ -25,7 +25,7 @@ namespace libmv { -// A vector of elements with fixed lenght and deep copy semantics. +// A vector of elements with fixed length and deep copy semantics. template <typename T, int N> class Tuple { public: diff --git a/intern/libmv/libmv/multiview/panography.h b/intern/libmv/libmv/multiview/panography.h index 5860a34d1fd..6b87f25bdda 100644 --- a/intern/libmv/libmv/multiview/panography.h +++ b/intern/libmv/libmv/multiview/panography.h @@ -38,7 +38,7 @@ namespace libmv { // The 2-point algorithm solves for the rotation of the camera with a single // focal length (4 degrees of freedom). // -// Compute from 1 to 3 possible focal lenght for 2 point correspondences. +// Compute from 1 to 3 possible focal length for 2 point correspondences. // Suppose that the cameras share the same optical center and focal lengths: // // Image 1 => H*x = x' => Image 2 diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index e3ebdb5a4bb..52f3b8d6a78 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -261,7 +261,7 @@ Mat3 RotationRodrigues(const Vec3& axis); // positive z-axis, and y is oriented close to up. Mat3 LookAt(Vec3 center); -// Return a diagonal matrix from a vector containg the diagonal values. +// Return a diagonal matrix from a vector containing the diagonal values. template <typename TVec> inline Mat Diag(const TVec& x) { return x.asDiagonal(); diff --git a/intern/libmv/libmv/numeric/poly.h b/intern/libmv/libmv/numeric/poly.h index a3d3801a399..c1deee42bf9 100644 --- a/intern/libmv/libmv/numeric/poly.h +++ b/intern/libmv/libmv/numeric/poly.h @@ -50,7 +50,7 @@ int SolveCubicPolynomial(Real a, Real b, Real c, Real* x0, Real* x1, Real* x2) { Real CQ3 = 2916 * q * q * q; if (R == 0 && Q == 0) { - // Tripple root in one place. + // Triple root in one place. *x0 = *x1 = *x2 = -a / 3; return 3; diff --git a/intern/memutil/MEM_RefCounted.h b/intern/memutil/MEM_RefCounted.h index 319effdebaf..71be4b62f12 100644 --- a/intern/memutil/MEM_RefCounted.h +++ b/intern/memutil/MEM_RefCounted.h @@ -41,7 +41,7 @@ class MEM_RefCounted { public: /** - * Constructs a a shared object. + * Constructs a shared object. */ MEM_RefCounted() : m_refCount(1) { diff --git a/intern/numaapi/source/build_config.h b/intern/numaapi/source/build_config.h index e7c332483b5..58c07ac85ab 100644 --- a/intern/numaapi/source/build_config.h +++ b/intern/numaapi/source/build_config.h @@ -234,7 +234,7 @@ // Check what is the latest C++ specification the compiler supports. // // NOTE: Use explicit definition here to avoid expansion-to-defined warning from -// being geenrated. While this will most likely a false-positive warning in this +// being generated. While this will most likely a false-positive warning in this // particular case, that warning might be helpful to catch errors elsewhere. // C++11 check. diff --git a/intern/opencolorio/fallback_impl.cc b/intern/opencolorio/fallback_impl.cc index 42a2b5bf3b6..9402a12a71a 100644 --- a/intern/opencolorio/fallback_impl.cc +++ b/intern/opencolorio/fallback_impl.cc @@ -485,8 +485,8 @@ OCIO_PackedImageDesc *FallbackImpl::createOCIO_PackedImageDesc(float *data, long xStrideBytes, long yStrideBytes) { - OCIO_PackedImageDescription *desc = (OCIO_PackedImageDescription *)MEM_callocN( - sizeof(OCIO_PackedImageDescription), "OCIO_PackedImageDescription"); + OCIO_PackedImageDescription *desc = MEM_cnew<OCIO_PackedImageDescription>( + "OCIO_PackedImageDescription"); desc->data = data; desc->width = width; desc->height = height; diff --git a/intern/opencolorio/gpu_shader_display_transform.glsl b/intern/opencolorio/gpu_shader_display_transform.glsl index d94ff9230e8..f5a7a7bf45d 100644 --- a/intern/opencolorio/gpu_shader_display_transform.glsl +++ b/intern/opencolorio/gpu_shader_display_transform.glsl @@ -119,7 +119,7 @@ vec4 curvemapping_evaluate_premulRGBF(vec4 col) /* Using a triangle distribution which gives a more final uniform noise. * See Banding in Games:A Noisy Rant(revision 5) Mikkel Gjøl, Playdead (slide 27) */ -/* GPUs are rounding before writting to framebuffer so we center the distribution around 0.0. */ +/* GPUs are rounding before writing to framebuffer so we center the distribution around 0.0. */ /* Return triangle noise in [-1..1[ range */ float dither_random_value(vec2 co) { diff --git a/intern/opencolorio/ocio_impl.cc b/intern/opencolorio/ocio_impl.cc index 058b8f51dd6..b4e48c013c0 100644 --- a/intern/opencolorio/ocio_impl.cc +++ b/intern/opencolorio/ocio_impl.cc @@ -67,7 +67,7 @@ static void OCIO_reportException(Exception &exception) OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) { - ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr); + ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__); try { *config = GetCurrentConfig(); @@ -79,7 +79,7 @@ OCIO_ConstConfigRcPtr *OCIOImpl::getCurrentConfig(void) OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr); + MEM_delete(config); return NULL; } @@ -96,7 +96,7 @@ void OCIOImpl::setCurrentConfig(const OCIO_ConstConfigRcPtr *config) OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) { - ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr); + ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__); try { *config = Config::CreateFromEnv(); @@ -108,14 +108,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromEnv(void) OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr); + MEM_delete(config); return NULL; } OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) { - ConstConfigRcPtr *config = OBJECT_GUARDED_NEW(ConstConfigRcPtr); + ConstConfigRcPtr *config = MEM_new<ConstConfigRcPtr>(__func__); try { *config = Config::CreateFromFile(filename); @@ -127,14 +127,14 @@ OCIO_ConstConfigRcPtr *OCIOImpl::configCreateFromFile(const char *filename) OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(config, ConstConfigRcPtr); + MEM_delete(config); return NULL; } void OCIOImpl::configRelease(OCIO_ConstConfigRcPtr *config) { - OBJECT_GUARDED_DELETE((ConstConfigRcPtr *)config, ConstConfigRcPtr); + MEM_delete((ConstConfigRcPtr *)config); } int OCIOImpl::configGetNumColorSpaces(OCIO_ConstConfigRcPtr *config) @@ -164,7 +164,7 @@ const char *OCIOImpl::configGetColorSpaceNameByIndex(OCIO_ConstConfigRcPtr *conf OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr *config, const char *name) { - ConstColorSpaceRcPtr *cs = OBJECT_GUARDED_NEW(ConstColorSpaceRcPtr); + ConstColorSpaceRcPtr *cs = MEM_new<ConstColorSpaceRcPtr>(__func__); try { *cs = (*(ConstConfigRcPtr *)config)->getColorSpace(name); @@ -176,7 +176,7 @@ OCIO_ConstColorSpaceRcPtr *OCIOImpl::configGetColorSpace(OCIO_ConstConfigRcPtr * OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(cs, ConstColorSpaceRcPtr); + MEM_delete(cs); return NULL; } @@ -380,7 +380,7 @@ const char *OCIOImpl::configGetLookNameByIndex(OCIO_ConstConfigRcPtr *config, in OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, const char *name) { - ConstLookRcPtr *look = OBJECT_GUARDED_NEW(ConstLookRcPtr); + ConstLookRcPtr *look = MEM_new<ConstLookRcPtr>(__func__); try { *look = (*(ConstConfigRcPtr *)config)->getLook(name); @@ -392,7 +392,7 @@ OCIO_ConstLookRcPtr *OCIOImpl::configGetLook(OCIO_ConstConfigRcPtr *config, cons OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(look, ConstLookRcPtr); + MEM_delete(look); return NULL; } @@ -404,7 +404,7 @@ const char *OCIOImpl::lookGetProcessSpace(OCIO_ConstLookRcPtr *look) void OCIOImpl::lookRelease(OCIO_ConstLookRcPtr *look) { - OBJECT_GUARDED_DELETE((ConstLookRcPtr *)look, ConstLookRcPtr); + MEM_delete((ConstLookRcPtr *)look); } int OCIOImpl::colorSpaceIsInvertible(OCIO_ConstColorSpaceRcPtr *cs_) @@ -521,14 +521,14 @@ void OCIOImpl::colorSpaceIsBuiltin(OCIO_ConstConfigRcPtr *config_, void OCIOImpl::colorSpaceRelease(OCIO_ConstColorSpaceRcPtr *cs) { - OBJECT_GUARDED_DELETE((ConstColorSpaceRcPtr *)cs, ConstColorSpaceRcPtr); + MEM_delete((ConstColorSpaceRcPtr *)cs); } OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfigRcPtr *config, const char *srcName, const char *dstName) { - ConstProcessorRcPtr *processor = OBJECT_GUARDED_NEW(ConstProcessorRcPtr); + ConstProcessorRcPtr *processor = MEM_new<ConstProcessorRcPtr>(__func__); try { *processor = (*(ConstConfigRcPtr *)config)->getProcessor(srcName, dstName); @@ -540,20 +540,20 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::configGetProcessorWithNames(OCIO_ConstConfig OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr); + MEM_delete(processor); return 0; } void OCIOImpl::processorRelease(OCIO_ConstProcessorRcPtr *processor) { - OBJECT_GUARDED_DELETE(processor, ConstProcessorRcPtr); + MEM_delete(processor); } OCIO_ConstCPUProcessorRcPtr *OCIOImpl::processorGetCPUProcessor( OCIO_ConstProcessorRcPtr *processor) { - ConstCPUProcessorRcPtr *cpu_processor = OBJECT_GUARDED_NEW(ConstCPUProcessorRcPtr); + ConstCPUProcessorRcPtr *cpu_processor = MEM_new<ConstCPUProcessorRcPtr>(__func__); *cpu_processor = (*(ConstProcessorRcPtr *)processor)->getDefaultCPUProcessor(); return (OCIO_ConstCPUProcessorRcPtr *)cpu_processor; } @@ -636,7 +636,7 @@ void OCIOImpl::cpuProcessorApplyRGBA_predivide(OCIO_ConstCPUProcessorRcPtr *cpu_ void OCIOImpl::cpuProcessorRelease(OCIO_ConstCPUProcessorRcPtr *cpu_processor) { - OBJECT_GUARDED_DELETE(cpu_processor, ConstCPUProcessorRcPtr); + MEM_delete(cpu_processor); } const char *OCIOImpl::colorSpaceGetName(OCIO_ConstColorSpaceRcPtr *cs) @@ -725,7 +725,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr /* Create processor from transform. This is the moment were OCIO validates * the entire transform, no need to check for the validity of inputs above. */ - ConstProcessorRcPtr *p = OBJECT_GUARDED_NEW(ConstProcessorRcPtr); + ConstProcessorRcPtr *p = MEM_new<ConstProcessorRcPtr>(__func__); try { *p = config->getProcessor(group); @@ -737,7 +737,7 @@ OCIO_ConstProcessorRcPtr *OCIOImpl::createDisplayProcessor(OCIO_ConstConfigRcPtr OCIO_reportException(exception); } - OBJECT_GUARDED_DELETE(p, ConstProcessorRcPtr); + MEM_delete(p); return NULL; } @@ -771,7 +771,7 @@ OCIO_PackedImageDesc *OCIOImpl::createOCIO_PackedImageDesc(float *data, void OCIOImpl::OCIO_PackedImageDescRelease(OCIO_PackedImageDesc *id) { - OBJECT_GUARDED_DELETE((PackedImageDesc *)id, PackedImageDesc); + MEM_delete((PackedImageDesc *)id); } const char *OCIOImpl::getVersionString(void) diff --git a/intern/opensubdiv/CMakeLists.txt b/intern/opensubdiv/CMakeLists.txt index bce8a8baa84..f141689791f 100644 --- a/intern/opensubdiv/CMakeLists.txt +++ b/intern/opensubdiv/CMakeLists.txt @@ -72,9 +72,20 @@ if(WITH_OPENSUBDIV) internal/device/device_context_openmp.h # Evaluator. + internal/evaluator/eval_output.cc + internal/evaluator/eval_output.h + internal/evaluator/eval_output_cpu.cc + internal/evaluator/eval_output_cpu.h + internal/evaluator/eval_output_gpu.cc + internal/evaluator/eval_output_gpu.h + internal/evaluator/evaluator_cache_impl.cc + internal/evaluator/evaluator_cache_impl.h internal/evaluator/evaluator_capi.cc internal/evaluator/evaluator_impl.cc internal/evaluator/evaluator_impl.h + internal/evaluator/patch_map.cc + internal/evaluator/patch_map.h + # Topology. internal/topology/mesh_topology.cc diff --git a/intern/opensubdiv/internal/evaluator/eval_output.cc b/intern/opensubdiv/internal/evaluator/eval_output.cc new file mode 100644 index 00000000000..58f835ab2e0 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output.cc @@ -0,0 +1,35 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/evaluator/eval_output.h" + +namespace blender { +namespace opensubdiv { + +bool is_adaptive(CpuPatchTable *patch_table) +{ + return patch_table->GetPatchArrayBuffer()[0].GetDescriptor().IsAdaptive(); +} + +bool is_adaptive(GLPatchTable *patch_table) +{ + return patch_table->GetPatchArrays()[0].GetDescriptor().IsAdaptive(); +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/evaluator/eval_output.h b/intern/opensubdiv/internal/evaluator/eval_output.h new file mode 100644 index 00000000000..a55b89001a4 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output.h @@ -0,0 +1,582 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVAL_OUTPUT_H_ +#define OPENSUBDIV_EVAL_OUTPUT_H_ + +#include <opensubdiv/osd/cpuPatchTable.h> +#include <opensubdiv/osd/glPatchTable.h> +#include <opensubdiv/osd/mesh.h> +#include <opensubdiv/osd/types.h> + +#include "internal/base/type.h" +#include "internal/evaluator/evaluator_impl.h" + +using OpenSubdiv::Far::PatchTable; +using OpenSubdiv::Far::StencilTable; +using OpenSubdiv::Osd::BufferDescriptor; +using OpenSubdiv::Osd::CpuPatchTable; +using OpenSubdiv::Osd::GLPatchTable; +using OpenSubdiv::Osd::PatchCoord; + +namespace blender { +namespace opensubdiv { + +// Base class for the implementation of the evaluators. +class EvalOutputAPI::EvalOutput { + public: + virtual ~EvalOutput() = default; + + virtual void updateData(const float *src, int start_vertex, int num_vertices) = 0; + + virtual void updateVaryingData(const float *src, int start_vertex, int num_vertices) = 0; + + virtual void updateFaceVaryingData(const int face_varying_channel, + const float *src, + int start_vertex, + int num_vertices) = 0; + + virtual void refine() = 0; + + // NOTE: P must point to a memory of at least float[3]*num_patch_coords. + virtual void evalPatches(const PatchCoord *patch_coord, + const int num_patch_coords, + float *P) = 0; + + // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords. + virtual void evalPatchesWithDerivatives(const PatchCoord *patch_coord, + const int num_patch_coords, + float *P, + float *dPdu, + float *dPdv) = 0; + + // NOTE: varying must point to a memory of at least float[3]*num_patch_coords. + virtual void evalPatchesVarying(const PatchCoord *patch_coord, + const int num_patch_coords, + float *varying) = 0; + + virtual void evalPatchesFaceVarying(const int face_varying_channel, + const PatchCoord *patch_coord, + const int num_patch_coords, + float face_varying[2]) = 0; + + // The following interfaces are dependant on the actual evaluator type (CPU, OpenGL, etc.) which + // have slightly different APIs to access patch arrays, as well as different types for their + // data structure. They need to be overridden in the specific instances of the EvalOutput derived + // classes if needed, while the interfaces above are overriden through VolatileEvalOutput. + + virtual void fillPatchArraysBuffer(OpenSubdiv_Buffer * /*patch_arrays_buffer*/) + { + } + + virtual void wrapPatchIndexBuffer(OpenSubdiv_Buffer * /*patch_index_buffer*/) + { + } + + virtual void wrapPatchParamBuffer(OpenSubdiv_Buffer * /*patch_param_buffer*/) + { + } + + virtual void wrapSrcBuffer(OpenSubdiv_Buffer * /*src_buffer*/) + { + } + + virtual void fillFVarPatchArraysBuffer(const int /*face_varying_channel*/, + OpenSubdiv_Buffer * /*patch_arrays_buffer*/) + { + } + + virtual void wrapFVarPatchIndexBuffer(const int /*face_varying_channel*/, + OpenSubdiv_Buffer * /*patch_index_buffer*/) + { + } + + virtual void wrapFVarPatchParamBuffer(const int /*face_varying_channel*/, + OpenSubdiv_Buffer * /*patch_param_buffer*/) + { + } + + virtual void wrapFVarSrcBuffer(const int /*face_varying_channel*/, + OpenSubdiv_Buffer * /*src_buffer*/) + { + } +}; + +namespace { + +// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying +// storage. +template<typename T> class RawDataWrapperBuffer { + public: + RawDataWrapperBuffer(T *data) : data_(data) + { + } + + T *BindCpuBuffer() + { + return data_; + } + + int BindVBO() + { + return 0; + } + + // TODO(sergey): Support UpdateData(). + + protected: + T *data_; +}; + +template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> { + public: + RawDataWrapperVertexBuffer(T *data, int num_vertices) + : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices) + { + } + + int GetNumVertices() + { + return num_vertices_; + } + + protected: + int num_vertices_; +}; + +class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> { + public: + ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices) + : RawDataWrapperVertexBuffer(data, num_vertices) + { + } +}; +} // namespace + +// Discriminators used in FaceVaryingVolatileEval in order to detect whether we are using adaptive +// patches as the CPU and OpenGL PatchTable have different APIs. +bool is_adaptive(CpuPatchTable *patch_table); +bool is_adaptive(GLPatchTable *patch_table); + +template<typename EVAL_VERTEX_BUFFER, + typename STENCIL_TABLE, + typename PATCH_TABLE, + typename EVALUATOR, + typename DEVICE_CONTEXT = void> +class FaceVaryingVolatileEval { + public: + typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; + + FaceVaryingVolatileEval(int face_varying_channel, + const StencilTable *face_varying_stencils, + int face_varying_width, + PATCH_TABLE *patch_table, + EvaluatorCache *evaluator_cache = NULL, + DEVICE_CONTEXT *device_context = NULL) + : face_varying_channel_(face_varying_channel), + src_face_varying_desc_(0, face_varying_width, face_varying_width), + patch_table_(patch_table), + evaluator_cache_(evaluator_cache), + device_context_(device_context) + { + using OpenSubdiv::Osd::convertToCompatibleStencilTable; + num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices(); + const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() + + face_varying_stencils->GetNumStencils(); + src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create( + 2, num_total_face_varying_vertices, device_context); + face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(face_varying_stencils, + device_context_); + } + + ~FaceVaryingVolatileEval() + { + delete src_face_varying_data_; + delete face_varying_stencils_; + } + + void updateData(const float *src, int start_vertex, int num_vertices) + { + src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void refine() + { + BufferDescriptor dst_face_varying_desc = src_face_varying_desc_; + dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ * + src_face_varying_desc_.stride; + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_); + // in and out points to same buffer so output is put directly after coarse vertices, needed in + // adaptive mode + EVALUATOR::EvalStencils(src_face_varying_data_, + src_face_varying_desc_, + src_face_varying_data_, + dst_face_varying_desc, + face_varying_stencils_, + eval_instance, + device_context_); + } + + // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords. + void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying) + { + RawDataWrapperBuffer<float> face_varying_data(face_varying); + BufferDescriptor face_varying_desc(0, 2, 2); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_); + + BufferDescriptor src_desc = get_src_varying_desc(); + + EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_, + src_desc, + &face_varying_data, + face_varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + face_varying_channel_, + eval_instance, + device_context_); + } + + EVAL_VERTEX_BUFFER *getSrcBuffer() const + { + return src_face_varying_data_; + } + + int getFVarSrcBufferOffset() const + { + BufferDescriptor src_desc = get_src_varying_desc(); + return src_desc.offset; + } + + PATCH_TABLE *getPatchTable() const + { + return patch_table_; + } + + private: + BufferDescriptor get_src_varying_desc() const + { + // src_face_varying_data_ always contains coarse vertices at the beginning. + // In adaptive mode they are followed by number of blocks for intermediate + // subdivision levels, and this is what OSD expects in this mode. + // In non-adaptive mode (generateIntermediateLevels == false), + // they are followed by max subdivision level, but they break interpolation as OSD + // expects only one subd level in this buffer. + // So in non-adaptive mode we put offset into buffer descriptor to skip over coarse vertices. + BufferDescriptor src_desc = src_face_varying_desc_; + if (!is_adaptive(patch_table_)) { + src_desc.offset += num_coarse_face_varying_vertices_ * src_face_varying_desc_.stride; + } + return src_desc; + } + + protected: + int face_varying_channel_; + + BufferDescriptor src_face_varying_desc_; + + int num_coarse_face_varying_vertices_; + EVAL_VERTEX_BUFFER *src_face_varying_data_; + const STENCIL_TABLE *face_varying_stencils_; + + // NOTE: We reference this, do not own it. + PATCH_TABLE *patch_table_; + + EvaluatorCache *evaluator_cache_; + DEVICE_CONTEXT *device_context_; +}; + +// Volatile evaluator which can be used from threads. +// +// TODO(sergey): Make it possible to evaluate coordinates in chunks. +// TODO(sergey): Make it possible to evaluate multiple face varying layers. +// (or maybe, it's cheap to create new evaluator for existing +// topology to evaluate all needed face varying layers?) +template<typename SRC_VERTEX_BUFFER, + typename EVAL_VERTEX_BUFFER, + typename STENCIL_TABLE, + typename PATCH_TABLE, + typename EVALUATOR, + typename DEVICE_CONTEXT = void> +class VolatileEvalOutput : public EvalOutputAPI::EvalOutput { + public: + typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; + typedef FaceVaryingVolatileEval<EVAL_VERTEX_BUFFER, + STENCIL_TABLE, + PATCH_TABLE, + EVALUATOR, + DEVICE_CONTEXT> + FaceVaryingEval; + + VolatileEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector<const StencilTable *> &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + EvaluatorCache *evaluator_cache = NULL, + DEVICE_CONTEXT *device_context = NULL) + : src_desc_(0, 3, 3), + src_varying_desc_(0, 3, 3), + face_varying_width_(face_varying_width), + evaluator_cache_(evaluator_cache), + device_context_(device_context) + { + // Total number of vertices = coarse points + refined points + local points. + int num_total_vertices = vertex_stencils->GetNumControlVertices() + + vertex_stencils->GetNumStencils(); + num_coarse_vertices_ = vertex_stencils->GetNumControlVertices(); + using OpenSubdiv::Osd::convertToCompatibleStencilTable; + src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); + src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); + patch_table_ = PATCH_TABLE::Create(patch_table, device_context_); + vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils, + device_context_); + varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils, + device_context_); + // Create evaluators for every face varying channel. + face_varying_evaluators.reserve(all_face_varying_stencils.size()); + int face_varying_channel = 0; + for (const StencilTable *face_varying_stencils : all_face_varying_stencils) { + face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel, + face_varying_stencils, + face_varying_width, + patch_table_, + evaluator_cache_, + device_context_)); + ++face_varying_channel; + } + } + + ~VolatileEvalOutput() override + { + delete src_data_; + delete src_varying_data_; + delete patch_table_; + delete vertex_stencils_; + delete varying_stencils_; + for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { + delete face_varying_evaluator; + } + } + + // TODO(sergey): Implement binding API. + + void updateData(const float *src, int start_vertex, int num_vertices) override + { + src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void updateVaryingData(const float *src, int start_vertex, int num_vertices) override + { + src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); + } + + void updateFaceVaryingData(const int face_varying_channel, + const float *src, + int start_vertex, + int num_vertices) override + { + assert(face_varying_channel >= 0); + assert(face_varying_channel < face_varying_evaluators.size()); + face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices); + } + + bool hasVaryingData() const + { + // return varying_stencils_ != NULL; + // TODO(sergey): Check this based on actual topology. + return false; + } + + bool hasFaceVaryingData() const + { + return face_varying_evaluators.size() != 0; + } + + void refine() override + { + // Evaluate vertex positions. + BufferDescriptor dst_desc = src_desc_; + dst_desc.offset += num_coarse_vertices_ * src_desc_.stride; + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_desc_, dst_desc, device_context_); + EVALUATOR::EvalStencils(src_data_, + src_desc_, + src_data_, + dst_desc, + vertex_stencils_, + eval_instance, + device_context_); + // Evaluate varying data. + if (hasVaryingData()) { + BufferDescriptor dst_varying_desc = src_varying_desc_; + dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride; + eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_); + EVALUATOR::EvalStencils(src_varying_data_, + src_varying_desc_, + src_varying_data_, + dst_varying_desc, + varying_stencils_, + eval_instance, + device_context_); + } + // Evaluate face-varying data. + if (hasFaceVaryingData()) { + for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { + face_varying_evaluator->refine(); + } + } + } + + // NOTE: P must point to a memory of at least float[3]*num_patch_coords. + void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P) override + { + RawDataWrapperBuffer<float> P_data(P); + // TODO(sergey): Support interleaved vertex-varying data. + BufferDescriptor P_desc(0, 3, 3); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_desc_, P_desc, device_context_); + EVALUATOR::EvalPatches(src_data_, + src_desc_, + &P_data, + P_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + + // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords. + void evalPatchesWithDerivatives(const PatchCoord *patch_coord, + const int num_patch_coords, + float *P, + float *dPdu, + float *dPdv) override + { + assert(dPdu); + assert(dPdv); + RawDataWrapperBuffer<float> P_data(P); + RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv); + // TODO(sergey): Support interleaved vertex-varying data. + BufferDescriptor P_desc(0, 3, 3); + BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_); + EVALUATOR::EvalPatches(src_data_, + src_desc_, + &P_data, + P_desc, + &dPdu_data, + dpDu_desc, + &dPdv_data, + pPdv_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + + // NOTE: varying must point to a memory of at least float[3]*num_patch_coords. + void evalPatchesVarying(const PatchCoord *patch_coord, + const int num_patch_coords, + float *varying) override + { + RawDataWrapperBuffer<float> varying_data(varying); + BufferDescriptor varying_desc(3, 3, 6); + ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); + const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( + evaluator_cache_, src_varying_desc_, varying_desc, device_context_); + EVALUATOR::EvalPatchesVarying(src_varying_data_, + src_varying_desc_, + &varying_data, + varying_desc, + patch_coord_buffer.GetNumVertices(), + &patch_coord_buffer, + patch_table_, + eval_instance, + device_context_); + } + + void evalPatchesFaceVarying(const int face_varying_channel, + const PatchCoord *patch_coord, + const int num_patch_coords, + float face_varying[2]) override + { + assert(face_varying_channel >= 0); + assert(face_varying_channel < face_varying_evaluators.size()); + face_varying_evaluators[face_varying_channel]->evalPatches( + patch_coord, num_patch_coords, face_varying); + } + + SRC_VERTEX_BUFFER *getSrcBuffer() const + { + return src_data_; + } + + PATCH_TABLE *getPatchTable() const + { + return patch_table_; + } + + SRC_VERTEX_BUFFER *getFVarSrcBuffer(const int face_varying_channel) const + { + return face_varying_evaluators[face_varying_channel]->getSrcBuffer(); + } + + int getFVarSrcBufferOffset(const int face_varying_channel) const + { + return face_varying_evaluators[face_varying_channel]->getFVarSrcBufferOffset(); + } + + PATCH_TABLE *getFVarPatchTable(const int face_varying_channel) const + { + return face_varying_evaluators[face_varying_channel]->getPatchTable(); + } + + private: + SRC_VERTEX_BUFFER *src_data_; + SRC_VERTEX_BUFFER *src_varying_data_; + PATCH_TABLE *patch_table_; + BufferDescriptor src_desc_; + BufferDescriptor src_varying_desc_; + + int num_coarse_vertices_; + + const STENCIL_TABLE *vertex_stencils_; + const STENCIL_TABLE *varying_stencils_; + + int face_varying_width_; + vector<FaceVaryingEval *> face_varying_evaluators; + + EvaluatorCache *evaluator_cache_; + DEVICE_CONTEXT *device_context_; +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_EVAL_OUTPUT_H_ diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc new file mode 100644 index 00000000000..02a41cb1580 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.cc @@ -0,0 +1,23 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +namespace blender { +namespace opensubdiv { + +} +} // namespace blender diff --git a/intern/opensubdiv/internal/evaluator/eval_output_cpu.h b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h new file mode 100644 index 00000000000..58bae7a322e --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output_cpu.h @@ -0,0 +1,66 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVAL_OUTPUT_CPU_H_ +#define OPENSUBDIV_EVAL_OUTPUT_CPU_H_ + +#include "internal/evaluator/eval_output.h" + +#include <opensubdiv/osd/cpuEvaluator.h> +#include <opensubdiv/osd/cpuPatchTable.h> +#include <opensubdiv/osd/cpuVertexBuffer.h> + +using OpenSubdiv::Far::StencilTable; +using OpenSubdiv::Osd::CpuEvaluator; +using OpenSubdiv::Osd::CpuVertexBuffer; + +namespace blender { +namespace opensubdiv { + +// Note: Define as a class instead of typedef to make it possible +// to have anonymous class in opensubdiv_evaluator_internal.h +class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer, + CpuVertexBuffer, + StencilTable, + CpuPatchTable, + CpuEvaluator> { + public: + CpuEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector<const StencilTable *> &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + EvaluatorCache *evaluator_cache = NULL) + : VolatileEvalOutput<CpuVertexBuffer, + CpuVertexBuffer, + StencilTable, + CpuPatchTable, + CpuEvaluator>(vertex_stencils, + varying_stencils, + all_face_varying_stencils, + face_varying_width, + patch_table, + evaluator_cache) + { + } +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_EVAL_OUTPUT_CPU_H_ diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc new file mode 100644 index 00000000000..b352ed2c014 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.cc @@ -0,0 +1,120 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#include "internal/evaluator/eval_output_gpu.h" + +#include "opensubdiv_evaluator_capi.h" + +using OpenSubdiv::Osd::PatchArray; +using OpenSubdiv::Osd::PatchArrayVector; + +namespace blender { +namespace opensubdiv { + +namespace { + +static void buildPatchArraysBufferFromVector(const PatchArrayVector &patch_arrays, + OpenSubdiv_Buffer *patch_arrays_buffer) +{ + const size_t patch_array_size = sizeof(PatchArray); + const size_t patch_array_byte_site = patch_array_size * patch_arrays.size(); + patch_arrays_buffer->device_alloc(patch_arrays_buffer, patch_arrays.size()); + patch_arrays_buffer->bind_gpu(patch_arrays_buffer); + patch_arrays_buffer->device_update( + patch_arrays_buffer, 0, patch_array_byte_site, &patch_arrays[0]); +} + +} // namespace + +GpuEvalOutput::GpuEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector<const StencilTable *> &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + VolatileEvalOutput::EvaluatorCache *evaluator_cache) + : VolatileEvalOutput<GLVertexBuffer, + GLVertexBuffer, + GLStencilTableSSBO, + GLPatchTable, + GLComputeEvaluator>(vertex_stencils, + varying_stencils, + all_face_varying_stencils, + face_varying_width, + patch_table, + evaluator_cache) +{ +} + +void GpuEvalOutput::fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer) +{ + GLPatchTable *patch_table = getPatchTable(); + buildPatchArraysBufferFromVector(patch_table->GetPatchArrays(), patch_arrays_buffer); +} + +void GpuEvalOutput::wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer) +{ + GLPatchTable *patch_table = getPatchTable(); + patch_index_buffer->wrap_device_handle(patch_index_buffer, patch_table->GetPatchIndexBuffer()); +} + +void GpuEvalOutput::wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer) +{ + GLPatchTable *patch_table = getPatchTable(); + patch_param_buffer->wrap_device_handle(patch_param_buffer, patch_table->GetPatchParamBuffer()); +} + +void GpuEvalOutput::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) +{ + GLVertexBuffer *vertex_buffer = getSrcBuffer(); + src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO()); +} + +void GpuEvalOutput::fillFVarPatchArraysBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_arrays_buffer) +{ + GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel); + buildPatchArraysBufferFromVector(patch_table->GetFVarPatchArrays(face_varying_channel), + patch_arrays_buffer); +} + +void GpuEvalOutput::wrapFVarPatchIndexBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_index_buffer) +{ + GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel); + patch_index_buffer->wrap_device_handle( + patch_index_buffer, patch_table->GetFVarPatchIndexBuffer(face_varying_channel)); +} + +void GpuEvalOutput::wrapFVarPatchParamBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_param_buffer) +{ + GLPatchTable *patch_table = getFVarPatchTable(face_varying_channel); + patch_param_buffer->wrap_device_handle( + patch_param_buffer, patch_table->GetFVarPatchParamBuffer(face_varying_channel)); +} + +void GpuEvalOutput::wrapFVarSrcBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *src_buffer) +{ + GLVertexBuffer *vertex_buffer = getFVarSrcBuffer(face_varying_channel); + src_buffer->buffer_offset = getFVarSrcBufferOffset(face_varying_channel); + src_buffer->wrap_device_handle(src_buffer, vertex_buffer->BindVBO()); +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/evaluator/eval_output_gpu.h b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h new file mode 100644 index 00000000000..783efd484aa --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/eval_output_gpu.h @@ -0,0 +1,71 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +// +// Author: Sergey Sharybin + +#ifndef OPENSUBDIV_EVAL_OUTPUT_GPU_H_ +#define OPENSUBDIV_EVAL_OUTPUT_GPU_H_ + +#include "internal/evaluator/eval_output.h" + +#include <opensubdiv/osd/glComputeEvaluator.h> +#include <opensubdiv/osd/glPatchTable.h> +#include <opensubdiv/osd/glVertexBuffer.h> + +using OpenSubdiv::Osd::GLComputeEvaluator; +using OpenSubdiv::Osd::GLStencilTableSSBO; +using OpenSubdiv::Osd::GLVertexBuffer; + +namespace blender { +namespace opensubdiv { + +class GpuEvalOutput : public VolatileEvalOutput<GLVertexBuffer, + GLVertexBuffer, + GLStencilTableSSBO, + GLPatchTable, + GLComputeEvaluator> { + public: + GpuEvalOutput(const StencilTable *vertex_stencils, + const StencilTable *varying_stencils, + const vector<const StencilTable *> &all_face_varying_stencils, + const int face_varying_width, + const PatchTable *patch_table, + EvaluatorCache *evaluator_cache = NULL); + + void fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer) override; + + void wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer) override; + + void wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer) override; + + void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) override; + + void fillFVarPatchArraysBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_arrays_buffer) override; + + void wrapFVarPatchIndexBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_index_buffer) override; + + void wrapFVarPatchParamBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_param_buffer) override; + + void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer) override; +}; + +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_EVAL_OUTPUT_GPU_H_ diff --git a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc new file mode 100644 index 00000000000..2fffcefa460 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.cc @@ -0,0 +1,47 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#include "internal/evaluator/evaluator_cache_impl.h" + +#include "internal/evaluator/eval_output_gpu.h" + +OpenSubdiv_EvaluatorCacheImpl::OpenSubdiv_EvaluatorCacheImpl() +{ +} + +OpenSubdiv_EvaluatorCacheImpl::~OpenSubdiv_EvaluatorCacheImpl() +{ + delete static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>(eval_cache); +} + +OpenSubdiv_EvaluatorCacheImpl *openSubdiv_createEvaluatorCacheInternal( + eOpenSubdivEvaluator evaluator_type) +{ + if (evaluator_type != eOpenSubdivEvaluator::OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) { + return nullptr; + } + OpenSubdiv_EvaluatorCacheImpl *evaluator_cache; + evaluator_cache = new OpenSubdiv_EvaluatorCacheImpl; + blender::opensubdiv::GpuEvalOutput::EvaluatorCache *eval_cache; + eval_cache = new blender::opensubdiv::GpuEvalOutput::EvaluatorCache(); + evaluator_cache->eval_cache = eval_cache; + return evaluator_cache; +} + +void openSubdiv_deleteEvaluatorCacheInternal(OpenSubdiv_EvaluatorCacheImpl *evaluator_cache) +{ + delete evaluator_cache; +} diff --git a/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h new file mode 100644 index 00000000000..060a78e5cbd --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/evaluator_cache_impl.h @@ -0,0 +1,38 @@ +// Copyright 2021 Blender Foundation. All rights reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software Foundation, +// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +#ifndef OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_ +#define OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_ + +#include "internal/base/memory.h" + +#include "opensubdiv_capi_type.h" + +struct OpenSubdiv_EvaluatorCacheImpl { + public: + OpenSubdiv_EvaluatorCacheImpl(); + ~OpenSubdiv_EvaluatorCacheImpl(); + + void *eval_cache; + MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorCacheImpl"); +}; + +OpenSubdiv_EvaluatorCacheImpl *openSubdiv_createEvaluatorCacheInternal( + eOpenSubdivEvaluator evaluator_type); + +void openSubdiv_deleteEvaluatorCacheInternal(OpenSubdiv_EvaluatorCacheImpl *evaluator_cache); + +#endif // OPENSUBDIV_EVALUATOR_CACHE_IMPL_H_ diff --git a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc index 4b12206e103..567afd3a763 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_capi.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_capi.cc @@ -18,9 +18,12 @@ #include "opensubdiv_evaluator_capi.h" +#include <opensubdiv/osd/glslPatchShaderSource.h> + #include "MEM_guardedalloc.h" #include <new> +#include "internal/evaluator/evaluator_cache_impl.h" #include "internal/evaluator/evaluator_impl.h" namespace { @@ -132,6 +135,74 @@ void evaluateFaceVarying(OpenSubdiv_Evaluator *evaluator, face_varying_channel, ptex_face_index, face_u, face_v, face_varying); } +void getPatchMap(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_map_handles, + struct OpenSubdiv_Buffer *patch_map_quadtree, + int *min_patch_face, + int *max_patch_face, + int *max_depth, + int *patches_are_triangular) +{ + evaluator->impl->eval_output->getPatchMap(patch_map_handles, + patch_map_quadtree, + min_patch_face, + max_patch_face, + max_depth, + patches_are_triangular); +} + +void fillPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_array_buffer) +{ + evaluator->impl->eval_output->fillPatchArraysBuffer(patch_array_buffer); +} + +void wrapPatchIndexBuffer(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_index_buffer) +{ + evaluator->impl->eval_output->wrapPatchIndexBuffer(patch_index_buffer); +} + +void wrapPatchParamBuffer(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_param_buffer) +{ + evaluator->impl->eval_output->wrapPatchParamBuffer(patch_param_buffer); +} + +void wrapSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, struct OpenSubdiv_Buffer *src_buffer) +{ + evaluator->impl->eval_output->wrapSrcBuffer(src_buffer); +} + +void fillFVarPatchArraysBuffer(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_array_buffer) +{ + evaluator->impl->eval_output->fillFVarPatchArraysBuffer(face_varying_channel, + patch_array_buffer); +} + +void wrapFVarPatchIndexBuffer(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_index_buffer) +{ + evaluator->impl->eval_output->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer); +} + +void wrapFVarPatchParamBuffer(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_param_buffer) +{ + evaluator->impl->eval_output->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer); +} + +void wrapFVarSrcBuffer(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *src_buffer) +{ + evaluator->impl->eval_output->wrapFVarSrcBuffer(face_varying_channel, src_buffer); +} + void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) { evaluator->setCoarsePositions = setCoarsePositions; @@ -149,21 +220,64 @@ void assignFunctionPointers(OpenSubdiv_Evaluator *evaluator) evaluator->evaluateFaceVarying = evaluateFaceVarying; evaluator->evaluatePatchesLimit = evaluatePatchesLimit; + + evaluator->getPatchMap = getPatchMap; + + evaluator->fillPatchArraysBuffer = fillPatchArraysBuffer; + evaluator->wrapPatchIndexBuffer = wrapPatchIndexBuffer; + evaluator->wrapPatchParamBuffer = wrapPatchParamBuffer; + evaluator->wrapSrcBuffer = wrapSrcBuffer; + + evaluator->fillFVarPatchArraysBuffer = fillFVarPatchArraysBuffer; + evaluator->wrapFVarPatchIndexBuffer = wrapFVarPatchIndexBuffer; + evaluator->wrapFVarPatchParamBuffer = wrapFVarPatchParamBuffer; + evaluator->wrapFVarSrcBuffer = wrapFVarSrcBuffer; } } // namespace OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( - OpenSubdiv_TopologyRefiner *topology_refiner) + OpenSubdiv_TopologyRefiner *topology_refiner, + eOpenSubdivEvaluator evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache) { - OpenSubdiv_Evaluator *evaluator = OBJECT_GUARDED_NEW(OpenSubdiv_Evaluator); + OpenSubdiv_Evaluator *evaluator = MEM_new<OpenSubdiv_Evaluator>(__func__); assignFunctionPointers(evaluator); - evaluator->impl = openSubdiv_createEvaluatorInternal(topology_refiner); + evaluator->impl = openSubdiv_createEvaluatorInternal( + topology_refiner, evaluator_type, evaluator_cache ? evaluator_cache->impl : nullptr); + evaluator->type = evaluator->impl ? evaluator_type : static_cast<eOpenSubdivEvaluator>(0); return evaluator; } void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator) { openSubdiv_deleteEvaluatorInternal(evaluator->impl); - OBJECT_GUARDED_DELETE(evaluator, OpenSubdiv_Evaluator); + MEM_delete(evaluator); +} + +OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator evaluator_type) +{ + OpenSubdiv_EvaluatorCache *evaluator_cache = MEM_new<OpenSubdiv_EvaluatorCache>(__func__); + evaluator_cache->impl = openSubdiv_createEvaluatorCacheInternal(evaluator_type); + return evaluator_cache; +} + +void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache *evaluator_cache) +{ + if (!evaluator_cache) { + return; + } + + openSubdiv_deleteEvaluatorCacheInternal(evaluator_cache->impl); + MEM_delete(evaluator_cache); +} + +const char *openSubdiv_getGLSLPatchBasisSource(void) +{ + /* Using a global string to avoid dealing with memory allocation/ownership. */ + static std::string patch_basis_source; + if (patch_basis_source.empty()) { + patch_basis_source = OpenSubdiv::Osd::GLSLPatchShaderSource::GetPatchBasisShaderSource(); + } + return patch_basis_source.c_str(); } diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc index 4f4f332ff15..755b8bfbc81 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_impl.cc +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.cc @@ -28,9 +28,6 @@ #include <opensubdiv/far/patchMap.h> #include <opensubdiv/far/patchTable.h> #include <opensubdiv/far/patchTableFactory.h> -#include <opensubdiv/osd/cpuEvaluator.h> -#include <opensubdiv/osd/cpuPatchTable.h> -#include <opensubdiv/osd/cpuVertexBuffer.h> #include <opensubdiv/osd/mesh.h> #include <opensubdiv/osd/types.h> #include <opensubdiv/version.h> @@ -38,19 +35,20 @@ #include "MEM_guardedalloc.h" #include "internal/base/type.h" +#include "internal/evaluator/eval_output_cpu.h" +#include "internal/evaluator/eval_output_gpu.h" +#include "internal/evaluator/evaluator_cache_impl.h" +#include "internal/evaluator/patch_map.h" #include "internal/topology/topology_refiner_impl.h" +#include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -using OpenSubdiv::Far::PatchMap; using OpenSubdiv::Far::PatchTable; using OpenSubdiv::Far::PatchTableFactory; using OpenSubdiv::Far::StencilTable; using OpenSubdiv::Far::StencilTableFactory; using OpenSubdiv::Far::TopologyRefiner; -using OpenSubdiv::Osd::BufferDescriptor; -using OpenSubdiv::Osd::CpuEvaluator; -using OpenSubdiv::Osd::CpuPatchTable; -using OpenSubdiv::Osd::CpuVertexBuffer; +using OpenSubdiv::Osd::PatchArray; using OpenSubdiv::Osd::PatchCoord; namespace blender { @@ -140,407 +138,9 @@ template<typename T, int kNumMaxElementsOnStack> class StackOrHeapArray { // 32 is a number of inner vertices along the patch size at subdivision level 6. typedef StackOrHeapArray<PatchCoord, 32 * 32> StackOrHeapPatchCoordArray; -// Buffer which implements API required by OpenSubdiv and uses an existing memory as an underlying -// storage. -template<typename T> class RawDataWrapperBuffer { - public: - RawDataWrapperBuffer(T *data) : data_(data) - { - } - - T *BindCpuBuffer() - { - return data_; - } - - // TODO(sergey): Support UpdateData(). - - protected: - T *data_; -}; - -template<typename T> class RawDataWrapperVertexBuffer : public RawDataWrapperBuffer<T> { - public: - RawDataWrapperVertexBuffer(T *data, int num_vertices) - : RawDataWrapperBuffer<T>(data), num_vertices_(num_vertices) - { - } - - int GetNumVertices() - { - return num_vertices_; - } - - protected: - int num_vertices_; -}; - -class ConstPatchCoordWrapperBuffer : public RawDataWrapperVertexBuffer<const PatchCoord> { - public: - ConstPatchCoordWrapperBuffer(const PatchCoord *data, int num_vertices) - : RawDataWrapperVertexBuffer(data, num_vertices) - { - } -}; - -template<typename EVAL_VERTEX_BUFFER, - typename STENCIL_TABLE, - typename PATCH_TABLE, - typename EVALUATOR, - typename DEVICE_CONTEXT = void> -class FaceVaryingVolatileEval { - public: - typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; - - FaceVaryingVolatileEval(int face_varying_channel, - const StencilTable *face_varying_stencils, - int face_varying_width, - PATCH_TABLE *patch_table, - EvaluatorCache *evaluator_cache = NULL, - DEVICE_CONTEXT *device_context = NULL) - : face_varying_channel_(face_varying_channel), - src_face_varying_desc_(0, face_varying_width, face_varying_width), - patch_table_(patch_table), - evaluator_cache_(evaluator_cache), - device_context_(device_context) - { - using OpenSubdiv::Osd::convertToCompatibleStencilTable; - num_coarse_face_varying_vertices_ = face_varying_stencils->GetNumControlVertices(); - const int num_total_face_varying_vertices = face_varying_stencils->GetNumControlVertices() + - face_varying_stencils->GetNumStencils(); - src_face_varying_data_ = EVAL_VERTEX_BUFFER::Create( - 2, num_total_face_varying_vertices, device_context); - face_varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(face_varying_stencils, - device_context_); - } - - ~FaceVaryingVolatileEval() - { - delete src_face_varying_data_; - delete face_varying_stencils_; - } - - void updateData(const float *src, int start_vertex, int num_vertices) - { - src_face_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void refine() - { - BufferDescriptor dst_face_varying_desc = src_face_varying_desc_; - dst_face_varying_desc.offset += num_coarse_face_varying_vertices_ * - src_face_varying_desc_.stride; - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_face_varying_desc_, dst_face_varying_desc, device_context_); - // in and out points to same buffer so output is put directly after coarse vertices, needed in - // adaptive mode - EVALUATOR::EvalStencils(src_face_varying_data_, - src_face_varying_desc_, - src_face_varying_data_, - dst_face_varying_desc, - face_varying_stencils_, - eval_instance, - device_context_); - } - - // NOTE: face_varying must point to a memory of at least float[2]*num_patch_coords. - void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *face_varying) - { - RawDataWrapperBuffer<float> face_varying_data(face_varying); - BufferDescriptor face_varying_desc(0, 2, 2); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_face_varying_desc_, face_varying_desc, device_context_); - - // src_face_varying_data_ always contains coarse vertices at the beginning. - // In adaptive mode they are followed by number of blocks for intermediate - // subdivision levels, and this is what OSD expects in this mode. - // In non-adaptive mode (generateIntermediateLevels == false), - // they are followed by max subdivision level, but they break interpolation as OSD - // expects only one subd level in this buffer. - // So in non-adaptive mode we put offset into buffer descriptor to skip over coarse vertices. - BufferDescriptor src_desc = src_face_varying_desc_; - if (!patch_table_->GetPatchArrayBuffer()[0].GetDescriptor().IsAdaptive()) { - src_desc.offset += num_coarse_face_varying_vertices_ * src_face_varying_desc_.stride; - } - - EVALUATOR::EvalPatchesFaceVarying(src_face_varying_data_, - src_desc, - &face_varying_data, - face_varying_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - face_varying_channel_, - eval_instance, - device_context_); - } - - protected: - int face_varying_channel_; - - BufferDescriptor src_face_varying_desc_; - - int num_coarse_face_varying_vertices_; - EVAL_VERTEX_BUFFER *src_face_varying_data_; - const STENCIL_TABLE *face_varying_stencils_; - - // NOTE: We reference this, do not own it. - PATCH_TABLE *patch_table_; - - EvaluatorCache *evaluator_cache_; - DEVICE_CONTEXT *device_context_; -}; - -// Volatile evaluator which can be used from threads. -// -// TODO(sergey): Make it possible to evaluate coordinates in chunks. -// TODO(sergey): Make it possible to evaluate multiple face varying layers. -// (or maybe, it's cheap to create new evaluator for existing -// topology to evaluate all needed face varying layers?) -template<typename SRC_VERTEX_BUFFER, - typename EVAL_VERTEX_BUFFER, - typename STENCIL_TABLE, - typename PATCH_TABLE, - typename EVALUATOR, - typename DEVICE_CONTEXT = void> -class VolatileEvalOutput { - public: - typedef OpenSubdiv::Osd::EvaluatorCacheT<EVALUATOR> EvaluatorCache; - typedef FaceVaryingVolatileEval<EVAL_VERTEX_BUFFER, - STENCIL_TABLE, - PATCH_TABLE, - EVALUATOR, - DEVICE_CONTEXT> - FaceVaryingEval; - - VolatileEvalOutput(const StencilTable *vertex_stencils, - const StencilTable *varying_stencils, - const vector<const StencilTable *> &all_face_varying_stencils, - const int face_varying_width, - const PatchTable *patch_table, - EvaluatorCache *evaluator_cache = NULL, - DEVICE_CONTEXT *device_context = NULL) - : src_desc_(0, 3, 3), - src_varying_desc_(0, 3, 3), - face_varying_width_(face_varying_width), - evaluator_cache_(evaluator_cache), - device_context_(device_context) - { - // Total number of vertices = coarse points + refined points + local points. - int num_total_vertices = vertex_stencils->GetNumControlVertices() + - vertex_stencils->GetNumStencils(); - num_coarse_vertices_ = vertex_stencils->GetNumControlVertices(); - using OpenSubdiv::Osd::convertToCompatibleStencilTable; - src_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); - src_varying_data_ = SRC_VERTEX_BUFFER::Create(3, num_total_vertices, device_context_); - patch_table_ = PATCH_TABLE::Create(patch_table, device_context_); - vertex_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(vertex_stencils, - device_context_); - varying_stencils_ = convertToCompatibleStencilTable<STENCIL_TABLE>(varying_stencils, - device_context_); - // Create evaluators for every face varying channel. - face_varying_evaluators.reserve(all_face_varying_stencils.size()); - int face_varying_channel = 0; - for (const StencilTable *face_varying_stencils : all_face_varying_stencils) { - face_varying_evaluators.push_back(new FaceVaryingEval(face_varying_channel, - face_varying_stencils, - face_varying_width, - patch_table_, - evaluator_cache_, - device_context_)); - ++face_varying_channel; - } - } - - ~VolatileEvalOutput() - { - delete src_data_; - delete src_varying_data_; - delete patch_table_; - delete vertex_stencils_; - delete varying_stencils_; - for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { - delete face_varying_evaluator; - } - } - - // TODO(sergey): Implement binding API. - - void updateData(const float *src, int start_vertex, int num_vertices) - { - src_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void updateVaryingData(const float *src, int start_vertex, int num_vertices) - { - src_varying_data_->UpdateData(src, start_vertex, num_vertices, device_context_); - } - - void updateFaceVaryingData(const int face_varying_channel, - const float *src, - int start_vertex, - int num_vertices) - { - assert(face_varying_channel >= 0); - assert(face_varying_channel < face_varying_evaluators.size()); - face_varying_evaluators[face_varying_channel]->updateData(src, start_vertex, num_vertices); - } - - bool hasVaryingData() const - { - // return varying_stencils_ != NULL; - // TODO(sergey): Check this based on actual topology. - return false; - } - - bool hasFaceVaryingData() const - { - return face_varying_evaluators.size() != 0; - } - - void refine() - { - // Evaluate vertex positions. - BufferDescriptor dst_desc = src_desc_; - dst_desc.offset += num_coarse_vertices_ * src_desc_.stride; - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_desc_, dst_desc, device_context_); - EVALUATOR::EvalStencils(src_data_, - src_desc_, - src_data_, - dst_desc, - vertex_stencils_, - eval_instance, - device_context_); - // Evaluate varying data. - if (hasVaryingData()) { - BufferDescriptor dst_varying_desc = src_varying_desc_; - dst_varying_desc.offset += num_coarse_vertices_ * src_varying_desc_.stride; - eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_varying_desc_, dst_varying_desc, device_context_); - EVALUATOR::EvalStencils(src_varying_data_, - src_varying_desc_, - src_varying_data_, - dst_varying_desc, - varying_stencils_, - eval_instance, - device_context_); - } - // Evaluate face-varying data. - if (hasFaceVaryingData()) { - for (FaceVaryingEval *face_varying_evaluator : face_varying_evaluators) { - face_varying_evaluator->refine(); - } - } - } - - // NOTE: P must point to a memory of at least float[3]*num_patch_coords. - void evalPatches(const PatchCoord *patch_coord, const int num_patch_coords, float *P) - { - RawDataWrapperBuffer<float> P_data(P); - // TODO(sergey): Support interleaved vertex-varying data. - BufferDescriptor P_desc(0, 3, 3); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_desc_, P_desc, device_context_); - EVALUATOR::EvalPatches(src_data_, - src_desc_, - &P_data, - P_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - eval_instance, - device_context_); - } - - // NOTE: P, dPdu, dPdv must point to a memory of at least float[3]*num_patch_coords. - void evalPatchesWithDerivatives(const PatchCoord *patch_coord, - const int num_patch_coords, - float *P, - float *dPdu, - float *dPdv) - { - assert(dPdu); - assert(dPdv); - RawDataWrapperBuffer<float> P_data(P); - RawDataWrapperBuffer<float> dPdu_data(dPdu), dPdv_data(dPdv); - // TODO(sergey): Support interleaved vertex-varying data. - BufferDescriptor P_desc(0, 3, 3); - BufferDescriptor dpDu_desc(0, 3, 3), pPdv_desc(0, 3, 3); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_desc_, P_desc, dpDu_desc, pPdv_desc, device_context_); - EVALUATOR::EvalPatches(src_data_, - src_desc_, - &P_data, - P_desc, - &dPdu_data, - dpDu_desc, - &dPdv_data, - pPdv_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - eval_instance, - device_context_); - } - - // NOTE: varying must point to a memory of at least float[3]*num_patch_coords. - void evalPatchesVarying(const PatchCoord *patch_coord, - const int num_patch_coords, - float *varying) - { - RawDataWrapperBuffer<float> varying_data(varying); - BufferDescriptor varying_desc(3, 3, 6); - ConstPatchCoordWrapperBuffer patch_coord_buffer(patch_coord, num_patch_coords); - const EVALUATOR *eval_instance = OpenSubdiv::Osd::GetEvaluator<EVALUATOR>( - evaluator_cache_, src_varying_desc_, varying_desc, device_context_); - EVALUATOR::EvalPatchesVarying(src_varying_data_, - src_varying_desc_, - &varying_data, - varying_desc, - patch_coord_buffer.GetNumVertices(), - &patch_coord_buffer, - patch_table_, - eval_instance, - device_context_); - } - - void evalPatchesFaceVarying(const int face_varying_channel, - const PatchCoord *patch_coord, - const int num_patch_coords, - float face_varying[2]) - { - assert(face_varying_channel >= 0); - assert(face_varying_channel < face_varying_evaluators.size()); - face_varying_evaluators[face_varying_channel]->evalPatches( - patch_coord, num_patch_coords, face_varying); - } - - private: - SRC_VERTEX_BUFFER *src_data_; - SRC_VERTEX_BUFFER *src_varying_data_; - PATCH_TABLE *patch_table_; - BufferDescriptor src_desc_; - BufferDescriptor src_varying_desc_; - - int num_coarse_vertices_; - - const STENCIL_TABLE *vertex_stencils_; - const STENCIL_TABLE *varying_stencils_; - - int face_varying_width_; - vector<FaceVaryingEval *> face_varying_evaluators; - - EvaluatorCache *evaluator_cache_; - DEVICE_CONTEXT *device_context_; -}; - void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords, const int num_patch_coords, - const OpenSubdiv::Far::PatchMap *patch_map, + const PatchMap *patch_map, StackOrHeapPatchCoordArray *array) { array->resize(num_patch_coords); @@ -553,79 +153,50 @@ void convertPatchCoordsToArray(const OpenSubdiv_PatchCoord *patch_coords, } // namespace -// Note: Define as a class instead of typedef to make it possible -// to have anonymous class in opensubdiv_evaluator_internal.h -class CpuEvalOutput : public VolatileEvalOutput<CpuVertexBuffer, - CpuVertexBuffer, - StencilTable, - CpuPatchTable, - CpuEvaluator> { - public: - CpuEvalOutput(const StencilTable *vertex_stencils, - const StencilTable *varying_stencils, - const vector<const StencilTable *> &all_face_varying_stencils, - const int face_varying_width, - const PatchTable *patch_table, - EvaluatorCache *evaluator_cache = NULL) - : VolatileEvalOutput<CpuVertexBuffer, - CpuVertexBuffer, - StencilTable, - CpuPatchTable, - CpuEvaluator>(vertex_stencils, - varying_stencils, - all_face_varying_stencils, - face_varying_width, - patch_table, - evaluator_cache) - { - } -}; - //////////////////////////////////////////////////////////////////////////////// // Evaluator wrapper for anonymous API. -CpuEvalOutputAPI::CpuEvalOutputAPI(CpuEvalOutput *implementation, - OpenSubdiv::Far::PatchMap *patch_map) - : implementation_(implementation), patch_map_(patch_map) +EvalOutputAPI::EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map) + : patch_map_(patch_map), implementation_(implementation) { } -CpuEvalOutputAPI::~CpuEvalOutputAPI() +EvalOutputAPI::~EvalOutputAPI() { delete implementation_; } -void CpuEvalOutputAPI::setCoarsePositions(const float *positions, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setCoarsePositions(const float *positions, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. implementation_->updateData(positions, start_vertex_index, num_vertices); } -void CpuEvalOutputAPI::setVaryingData(const float *varying_data, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setVaryingData(const float *varying_data, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. implementation_->updateVaryingData(varying_data, start_vertex_index, num_vertices); } -void CpuEvalOutputAPI::setFaceVaryingData(const int face_varying_channel, - const float *face_varying_data, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setFaceVaryingData(const int face_varying_channel, + const float *face_varying_data, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. implementation_->updateFaceVaryingData( face_varying_channel, face_varying_data, start_vertex_index, num_vertices); } -void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. const unsigned char *current_buffer = (unsigned char *)buffer; @@ -638,11 +209,11 @@ void CpuEvalOutputAPI::setCoarsePositionsFromBuffer(const void *buffer, } } -void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setVaryingDataFromBuffer(const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. const unsigned char *current_buffer = (unsigned char *)buffer; @@ -655,12 +226,12 @@ void CpuEvalOutputAPI::setVaryingDataFromBuffer(const void *buffer, } } -void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel, - const void *buffer, - const int start_offset, - const int stride, - const int start_vertex_index, - const int num_vertices) +void EvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_channel, + const void *buffer, + const int start_offset, + const int stride, + const int start_vertex_index, + const int num_vertices) { // TODO(sergey): Add sanity check on indices. const unsigned char *current_buffer = (unsigned char *)buffer; @@ -675,17 +246,17 @@ void CpuEvalOutputAPI::setFaceVaryingDataFromBuffer(const int face_varying_chann } } -void CpuEvalOutputAPI::refine() +void EvalOutputAPI::refine() { implementation_->refine(); } -void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index, - float face_u, - float face_v, - float P[3], - float dPdu[3], - float dPdv[3]) +void EvalOutputAPI::evaluateLimit(const int ptex_face_index, + float face_u, + float face_v, + float P[3], + float dPdu[3], + float dPdv[3]) { assert(face_u >= 0.0f); assert(face_u <= 1.0f); @@ -701,10 +272,10 @@ void CpuEvalOutputAPI::evaluateLimit(const int ptex_face_index, } } -void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index, - float face_u, - float face_v, - float varying[3]) +void EvalOutputAPI::evaluateVarying(const int ptex_face_index, + float face_u, + float face_v, + float varying[3]) { assert(face_u >= 0.0f); assert(face_u <= 1.0f); @@ -715,11 +286,11 @@ void CpuEvalOutputAPI::evaluateVarying(const int ptex_face_index, implementation_->evalPatchesVarying(&patch_coord, 1, varying); } -void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, - const int ptex_face_index, - float face_u, - float face_v, - float face_varying[2]) +void EvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, + const int ptex_face_index, + float face_u, + float face_v, + float face_varying[2]) { assert(face_u >= 0.0f); assert(face_u <= 1.0f); @@ -730,11 +301,11 @@ void CpuEvalOutputAPI::evaluateFaceVarying(const int face_varying_channel, implementation_->evalPatchesFaceVarying(face_varying_channel, &patch_coord, 1, face_varying); } -void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords, - const int num_patch_coords, - float *P, - float *dPdu, - float *dPdv) +void EvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_coords, + const int num_patch_coords, + float *P, + float *dPdu, + float *dPdv) { StackOrHeapPatchCoordArray patch_coords_array; convertPatchCoordsToArray(patch_coords, num_patch_coords, patch_map_, &patch_coords_array); @@ -747,6 +318,73 @@ void CpuEvalOutputAPI::evaluatePatchesLimit(const OpenSubdiv_PatchCoord *patch_c } } +void EvalOutputAPI::getPatchMap(OpenSubdiv_Buffer *patch_map_handles, + OpenSubdiv_Buffer *patch_map_quadtree, + int *min_patch_face, + int *max_patch_face, + int *max_depth, + int *patches_are_triangular) +{ + *min_patch_face = patch_map_->getMinPatchFace(); + *max_patch_face = patch_map_->getMaxPatchFace(); + *max_depth = patch_map_->getMaxDepth(); + *patches_are_triangular = patch_map_->getPatchesAreTriangular(); + + const std::vector<PatchTable::PatchHandle> &handles = patch_map_->getHandles(); + PatchTable::PatchHandle *buffer_handles = static_cast<PatchTable::PatchHandle *>( + patch_map_handles->alloc(patch_map_handles, handles.size())); + memcpy(buffer_handles, &handles[0], sizeof(PatchTable::PatchHandle) * handles.size()); + + const std::vector<PatchMap::QuadNode> &quadtree = patch_map_->nodes(); + PatchMap::QuadNode *buffer_nodes = static_cast<PatchMap::QuadNode *>( + patch_map_quadtree->alloc(patch_map_quadtree, quadtree.size())); + memcpy(buffer_nodes, &quadtree[0], sizeof(PatchMap::QuadNode) * quadtree.size()); +} + +void EvalOutputAPI::fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer) +{ + implementation_->fillPatchArraysBuffer(patch_arrays_buffer); +} + +void EvalOutputAPI::wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer) +{ + implementation_->wrapPatchIndexBuffer(patch_index_buffer); +} + +void EvalOutputAPI::wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer) +{ + implementation_->wrapPatchParamBuffer(patch_param_buffer); +} + +void EvalOutputAPI::wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer) +{ + implementation_->wrapSrcBuffer(src_buffer); +} + +void EvalOutputAPI::fillFVarPatchArraysBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_arrays_buffer) +{ + implementation_->fillFVarPatchArraysBuffer(face_varying_channel, patch_arrays_buffer); +} + +void EvalOutputAPI::wrapFVarPatchIndexBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_index_buffer) +{ + implementation_->wrapFVarPatchIndexBuffer(face_varying_channel, patch_index_buffer); +} + +void EvalOutputAPI::wrapFVarPatchParamBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_param_buffer) +{ + implementation_->wrapFVarPatchParamBuffer(face_varying_channel, patch_param_buffer); +} + +void EvalOutputAPI::wrapFVarSrcBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *src_buffer) +{ + implementation_->wrapFVarSrcBuffer(face_varying_channel, src_buffer); +} + } // namespace opensubdiv } // namespace blender @@ -763,8 +401,15 @@ OpenSubdiv_EvaluatorImpl::~OpenSubdiv_EvaluatorImpl() } OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( - OpenSubdiv_TopologyRefiner *topology_refiner) + OpenSubdiv_TopologyRefiner *topology_refiner, + eOpenSubdivEvaluator evaluator_type, + OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr) { + // Only CPU and GLCompute are implemented at the moment. + if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU && + evaluator_type != OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) { + return NULL; + } using blender::opensubdiv::vector; TopologyRefiner *refiner = topology_refiner->impl->topology_refiner; if (refiner == NULL) { @@ -867,14 +512,34 @@ OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( } } // Create OpenSubdiv's CPU side evaluator. - // TODO(sergey): Make it possible to use different evaluators. - blender::opensubdiv::CpuEvalOutput *eval_output = new blender::opensubdiv::CpuEvalOutput( - vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); - OpenSubdiv::Far::PatchMap *patch_map = new PatchMap(*patch_table); + blender::opensubdiv::EvalOutputAPI::EvalOutput *eval_output = nullptr; + + const bool use_gl_evaluator = evaluator_type == OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; + if (use_gl_evaluator) { + blender::opensubdiv::GpuEvalOutput::EvaluatorCache *evaluator_cache = nullptr; + if (evaluator_cache_descr) { + evaluator_cache = static_cast<blender::opensubdiv::GpuEvalOutput::EvaluatorCache *>( + evaluator_cache_descr->eval_cache); + } + + eval_output = new blender::opensubdiv::GpuEvalOutput(vertex_stencils, + varying_stencils, + all_face_varying_stencils, + 2, + patch_table, + evaluator_cache); + } + else { + eval_output = new blender::opensubdiv::CpuEvalOutput( + vertex_stencils, varying_stencils, all_face_varying_stencils, 2, patch_table); + } + + blender::opensubdiv::PatchMap *patch_map = new blender::opensubdiv::PatchMap(*patch_table); // Wrap everything we need into an object which we control from our side. OpenSubdiv_EvaluatorImpl *evaluator_descr; evaluator_descr = new OpenSubdiv_EvaluatorImpl(); - evaluator_descr->eval_output = new blender::opensubdiv::CpuEvalOutputAPI(eval_output, patch_map); + + evaluator_descr->eval_output = new blender::opensubdiv::EvalOutputAPI(eval_output, patch_map); evaluator_descr->patch_map = patch_map; evaluator_descr->patch_table = patch_table; // TOOD(sergey): Look into whether we've got duplicated stencils arrays. diff --git a/intern/opensubdiv/internal/evaluator/evaluator_impl.h b/intern/opensubdiv/internal/evaluator/evaluator_impl.h index e7ccc9b376a..e24d47cba79 100644 --- a/intern/opensubdiv/internal/evaluator/evaluator_impl.h +++ b/intern/opensubdiv/internal/evaluator/evaluator_impl.h @@ -28,14 +28,17 @@ #include "internal/base/memory.h" +#include "opensubdiv_capi_type.h" + +struct OpenSubdiv_Buffer; +struct OpenSubdiv_EvaluatorCacheImpl; struct OpenSubdiv_PatchCoord; struct OpenSubdiv_TopologyRefiner; namespace blender { namespace opensubdiv { -// Anonymous forward declaration of actual evaluator implementation. -class CpuEvalOutput; +class PatchMap; // Wrapper around implementation, which defines API which we are capable to // provide over the implementation. @@ -43,11 +46,15 @@ class CpuEvalOutput; // TODO(sergey): It is almost the same as C-API object, so ideally need to // merge them somehow, but how to do this and keep files with all the templates // and such separate? -class CpuEvalOutputAPI { +class EvalOutputAPI { public: - // NOTE: API object becomes an owner of evaluator. Patch we are referencing. - CpuEvalOutputAPI(CpuEvalOutput *implementation, OpenSubdiv::Far::PatchMap *patch_map); - ~CpuEvalOutputAPI(); + // Anonymous forward declaration of actual evaluator implementation. + class EvalOutput; + + // NOTE: PatchMap is not owned, only referenced. + EvalOutputAPI(EvalOutput *implementation, PatchMap *patch_map); + + ~EvalOutputAPI(); // Set coarse positions from a continuous array of coordinates. void setCoarsePositions(const float *positions, @@ -130,9 +137,47 @@ class CpuEvalOutputAPI { float *dPdu, float *dPdv); + // Fill the output buffers and variables with data from the PatchMap. + void getPatchMap(OpenSubdiv_Buffer *patch_map_handles, + OpenSubdiv_Buffer *patch_map_quadtree, + int *min_patch_face, + int *max_patch_face, + int *max_depth, + int *patches_are_triangular); + + // Copy the patch arrays buffer used by OpenSubDiv for the source data to the given buffer. + void fillPatchArraysBuffer(OpenSubdiv_Buffer *patch_arrays_buffer); + + // Wrap the patch index buffer used by OpenSubDiv for the source data with the given buffer. + void wrapPatchIndexBuffer(OpenSubdiv_Buffer *patch_index_buffer); + + // Wrap the patch param buffer used by OpenSubDiv for the source data with the given buffer. + void wrapPatchParamBuffer(OpenSubdiv_Buffer *patch_param_buffer); + + // Wrap the buffer used by OpenSubDiv for the source data with the given buffer. + void wrapSrcBuffer(OpenSubdiv_Buffer *src_buffer); + + // Copy the patch arrays buffer used by OpenSubDiv for the face varying channel with the given + // buffer. + void fillFVarPatchArraysBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_arrays_buffer); + + // Wrap the patch index buffer used by OpenSubDiv for the face varying channel with the given + // buffer. + void wrapFVarPatchIndexBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_index_buffer); + + // Wrap the patch param buffer used by OpenSubDiv for the face varying channel with the given + // buffer. + void wrapFVarPatchParamBuffer(const int face_varying_channel, + OpenSubdiv_Buffer *patch_param_buffer); + + // Wrap thebuffer used by OpenSubDiv for the face varying channel with the given buffer. + void wrapFVarSrcBuffer(const int face_varying_channel, OpenSubdiv_Buffer *src_buffer); + protected: - CpuEvalOutput *implementation_; - OpenSubdiv::Far::PatchMap *patch_map_; + PatchMap *patch_map_; + EvalOutput *implementation_; }; } // namespace opensubdiv @@ -143,15 +188,17 @@ struct OpenSubdiv_EvaluatorImpl { OpenSubdiv_EvaluatorImpl(); ~OpenSubdiv_EvaluatorImpl(); - blender::opensubdiv::CpuEvalOutputAPI *eval_output; - const OpenSubdiv::Far::PatchMap *patch_map; + blender::opensubdiv::EvalOutputAPI *eval_output; + const blender::opensubdiv::PatchMap *patch_map; const OpenSubdiv::Far::PatchTable *patch_table; MEM_CXX_CLASS_ALLOC_FUNCS("OpenSubdiv_EvaluatorImpl"); }; OpenSubdiv_EvaluatorImpl *openSubdiv_createEvaluatorInternal( - struct OpenSubdiv_TopologyRefiner *topology_refiner); + struct OpenSubdiv_TopologyRefiner *topology_refiner, + eOpenSubdivEvaluator evaluator_type, + OpenSubdiv_EvaluatorCacheImpl *evaluator_cache_descr); void openSubdiv_deleteEvaluatorInternal(OpenSubdiv_EvaluatorImpl *evaluator); diff --git a/intern/opensubdiv/internal/evaluator/patch_map.cc b/intern/opensubdiv/internal/evaluator/patch_map.cc new file mode 100644 index 00000000000..1b10c1118b9 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/patch_map.cc @@ -0,0 +1,213 @@ +// Original code copyright 2013 Pixar. +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +// Modifications copyright 2021 Blender Foundation. All rights reserved. + +#include "internal/evaluator/patch_map.h" +#include <algorithm> + +using OpenSubdiv::Far::ConstPatchParamArray; +using OpenSubdiv::Far::Index; +using OpenSubdiv::Far::PatchParam; +using OpenSubdiv::Far::PatchParamTable; +using OpenSubdiv::Far::PatchTable; + +namespace blender { +namespace opensubdiv { + +// +// Inline quadtree assembly methods used by the constructor: +// + +// sets all the children to point to the patch of given index +inline void PatchMap::QuadNode::SetChildren(int index) +{ + + for (int i = 0; i < 4; ++i) { + children[i].isSet = true; + children[i].isLeaf = true; + children[i].index = index; + } +} + +// sets the child in "quadrant" to point to the node or patch of the given index +inline void PatchMap::QuadNode::SetChild(int quadrant, int index, bool isLeaf) +{ + + assert(!children[quadrant].isSet); + children[quadrant].isSet = true; + children[quadrant].isLeaf = isLeaf; + children[quadrant].index = index; +} + +inline void PatchMap::assignRootNode(QuadNode *node, int index) +{ + + // Assign the given index to all children of the node (all leaves) + node->SetChildren(index); +} + +inline PatchMap::QuadNode *PatchMap::assignLeafOrChildNode(QuadNode *node, + bool isLeaf, + int quadrant, + int index) +{ + + // Assign the node given if it is a leaf node, otherwise traverse + // the node -- creating/assigning a new child node if needed + + if (isLeaf) { + node->SetChild(quadrant, index, true); + return node; + } + if (node->children[quadrant].isSet) { + return &_quadtree[node->children[quadrant].index]; + } + else { + int newChildNodeIndex = (int)_quadtree.size(); + _quadtree.push_back(QuadNode()); + node->SetChild(quadrant, newChildNodeIndex, false); + return &_quadtree[newChildNodeIndex]; + } +} + +// +// Constructor and initialization methods for the handles and quadtree: +// +PatchMap::PatchMap(PatchTable const &patchTable) + : _minPatchFace(-1), _maxPatchFace(-1), _maxDepth(0) +{ + + _patchesAreTriangular = patchTable.GetVaryingPatchDescriptor().GetNumControlVertices() == 3; + + if (patchTable.GetNumPatchesTotal() > 0) { + initializeHandles(patchTable); + initializeQuadtree(patchTable); + } +} + +void PatchMap::initializeHandles(PatchTable const &patchTable) +{ + + // + // Populate the vector of patch Handles. Keep track of the min and max + // face indices to allocate resources accordingly and limit queries: + // + _minPatchFace = (int)patchTable.GetPatchParamTable()[0].GetFaceId(); + _maxPatchFace = _minPatchFace; + + int numArrays = (int)patchTable.GetNumPatchArrays(); + int numPatches = (int)patchTable.GetNumPatchesTotal(); + + _handles.resize(numPatches); + + for (int pArray = 0, handleIndex = 0; pArray < numArrays; ++pArray) { + + ConstPatchParamArray params = patchTable.GetPatchParams(pArray); + + int patchSize = patchTable.GetPatchArrayDescriptor(pArray).GetNumControlVertices(); + + for (Index j = 0; j < patchTable.GetNumPatches(pArray); ++j, ++handleIndex) { + + Handle &h = _handles[handleIndex]; + + h.arrayIndex = pArray; + h.patchIndex = handleIndex; + h.vertIndex = j * patchSize; + + int patchFaceId = params[j].GetFaceId(); + _minPatchFace = std::min(_minPatchFace, patchFaceId); + _maxPatchFace = std::max(_maxPatchFace, patchFaceId); + } + } +} + +void PatchMap::initializeQuadtree(PatchTable const &patchTable) +{ + + // + // Reserve quadtree nodes for the worst case and prune later. Set the + // initial size to accomodate the root node of each patch face: + // + int nPatchFaces = (_maxPatchFace - _minPatchFace) + 1; + + int nHandles = (int)_handles.size(); + + _quadtree.reserve(nPatchFaces + nHandles); + _quadtree.resize(nPatchFaces); + + PatchParamTable const ¶ms = patchTable.GetPatchParamTable(); + + for (int handle = 0; handle < nHandles; ++handle) { + + PatchParam const ¶m = params[handle]; + + int depth = param.GetDepth(); + int rootDepth = param.NonQuadRoot(); + + _maxDepth = std::max(_maxDepth, depth); + + QuadNode *node = &_quadtree[param.GetFaceId() - _minPatchFace]; + + if (depth == rootDepth) { + assignRootNode(node, handle); + continue; + } + + if (!_patchesAreTriangular) { + // Use the UV bits of the PatchParam directly for quad patches: + int u = param.GetU(); + int v = param.GetV(); + + for (int j = rootDepth + 1; j <= depth; ++j) { + int uBit = (u >> (depth - j)) & 1; + int vBit = (v >> (depth - j)) & 1; + + int quadrant = (vBit << 1) | uBit; + + node = assignLeafOrChildNode(node, (j == depth), quadrant, handle); + } + } + else { + // Use an interior UV point of triangles to identify quadrants: + double u = 0.25; + double v = 0.25; + param.UnnormalizeTriangle(u, v); + + double median = 0.5; + bool triRotated = false; + + for (int j = rootDepth + 1; j <= depth; ++j, median *= 0.5) { + int quadrant = transformUVToTriQuadrant(median, u, v, triRotated); + + node = assignLeafOrChildNode(node, (j == depth), quadrant, handle); + } + } + } + + // Swap the Node vector with a copy to reduce worst case memory allocation: + QuadTree tmpTree = _quadtree; + _quadtree.swap(tmpTree); +} + +} // namespace opensubdiv +} // namespace blender diff --git a/intern/opensubdiv/internal/evaluator/patch_map.h b/intern/opensubdiv/internal/evaluator/patch_map.h new file mode 100644 index 00000000000..af804d6ca71 --- /dev/null +++ b/intern/opensubdiv/internal/evaluator/patch_map.h @@ -0,0 +1,264 @@ +// Original code copyright 2013 Pixar. +// +// Licensed under the Apache License, Version 2.0 (the "Apache License") +// with the following modification; you may not use this file except in +// compliance with the Apache License and the following modification to it: +// Section 6. Trademarks. is deleted and replaced with: +// +// 6. Trademarks. This License does not grant permission to use the trade +// names, trademarks, service marks, or product names of the Licensor +// and its affiliates, except as required to comply with Section 4(c) of +// the License and to reproduce the content of the NOTICE file. +// +// You may obtain a copy of the Apache License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the Apache License with the above modification is +// distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the Apache License for the specific +// language governing permissions and limitations under the Apache License. +// +// Modifications copyright 2021 Blender Foundation. All rights reserved. + +#ifndef OPENSUBDIV_PATCH_MAP_H_ +#define OPENSUBDIV_PATCH_MAP_H_ + +#include <opensubdiv/far/patchTable.h> + +namespace blender { +namespace opensubdiv { + +/// \brief An quadtree-based map connecting coarse faces to their sub-patches +/// +/// PatchTable::PatchArrays contain lists of patches that represent the limit +/// surface of a mesh, sorted by their topological type. These arrays break the +/// connection between coarse faces and their sub-patches. +/// +/// The PatchMap provides a quad-tree based lookup structure that, given a singular +/// parametric location, can efficiently return a handle to the sub-patch that +/// contains this location. +/// +class PatchMap { + public: + // Quadtree node with 4 children, tree is just a vector of nodes + struct QuadNode { + QuadNode() + { + std::memset(this, 0, sizeof(QuadNode)); + } + + struct Child { + unsigned int isSet : 1; // true if the child has been set + unsigned int isLeaf : 1; // true if the child is a QuadNode + unsigned int index : 30; // child index (either QuadNode or Handle) + }; + + // sets all the children to point to the patch of given index + void SetChildren(int index); + + // sets the child in "quadrant" to point to the node or patch of the given index + void SetChild(int quadrant, int index, bool isLeaf); + + Child children[4]; + }; + + typedef OpenSubdiv::Far::PatchTable::PatchHandle Handle; + + /// \brief Constructor + /// + /// @param patchTable A valid PatchTable + /// + PatchMap(OpenSubdiv::Far::PatchTable const &patchTable); + + /// \brief Returns a handle to the sub-patch of the face at the given (u,v). + /// Note that the patch face ID corresponds to potentially quadrangulated + /// face indices and not the base face indices (see Far::PtexIndices for more + /// details). + /// + /// @param patchFaceId The index of the patch (Ptex) face + /// + /// @param u Local u parameter + /// + /// @param v Local v parameter + /// + /// @return A patch handle or 0 if the face is not supported (index + /// out of bounds) or is tagged as a hole + /// + Handle const *FindPatch(int patchFaceId, double u, double v) const; + + int getMinPatchFace() const + { + return _minPatchFace; + } + + int getMaxPatchFace() const + { + return _maxPatchFace; + } + + int getMaxDepth() const + { + return _maxDepth; + } + + bool getPatchesAreTriangular() const + { + return _patchesAreTriangular; + } + + const std::vector<Handle> &getHandles() + { + return _handles; + } + + const std::vector<QuadNode> &nodes() + { + return _quadtree; + } + + private: + void initializeHandles(OpenSubdiv::Far::PatchTable const &patchTable); + void initializeQuadtree(OpenSubdiv::Far::PatchTable const &patchTable); + + typedef std::vector<QuadNode> QuadTree; + + // Internal methods supporting quadtree construction and queries + void assignRootNode(QuadNode *node, int index); + QuadNode *assignLeafOrChildNode(QuadNode *node, bool isLeaf, int quad, int index); + + template<class T> static int transformUVToQuadQuadrant(T const &median, T &u, T &v); + template<class T> + static int transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated); + + private: + bool _patchesAreTriangular; // tri and quad assembly and search requirements differ + + int _minPatchFace; // minimum patch face index supported by the map + int _maxPatchFace; // maximum patch face index supported by the map + int _maxDepth; // maximum depth of a patch in the tree + + std::vector<Handle> _handles; // all the patches in the PatchTable + std::vector<QuadNode> _quadtree; // quadtree nodes +}; + +// +// Given a median value for both U and V, these methods transform a (u,v) pair +// into the quadrant that contains them and returns the quadrant index. +// +// Quadrant indexing for tri and quad patches -- consistent with PatchParam's +// usage of UV bits: +// +// (0,1) o-----o-----o (1,1) (0,1) o (1,0) o-----o-----o (0,0) +// | | | |\ \ 1 |\ 0 | +// | 2 | 3 | | \ \ | \ | +// | | | | 2 \ \| 3 \| +// o-----o-----o o-----o o-----o +// | | | |\ 3 |\ \ 2 | +// | 0 | 1 | | \ | \ \ | +// | | | | 0 \| 1 \ \| +// (0,0) o-----o-----o (1,0) (0,0) o-----o-----o (1,0) o (0,1) +// +// The triangular case also takes and returns/affects the rotation of the +// quadrant being searched and identified (quadrant 3 imparts a rotation). +// +template<class T> inline int PatchMap::transformUVToQuadQuadrant(T const &median, T &u, T &v) +{ + + int uHalf = (u >= median); + if (uHalf) + u -= median; + + int vHalf = (v >= median); + if (vHalf) + v -= median; + + return (vHalf << 1) | uHalf; +} + +template<class T> +int inline PatchMap::transformUVToTriQuadrant(T const &median, T &u, T &v, bool &rotated) +{ + + if (!rotated) { + if (u >= median) { + u -= median; + return 1; + } + if (v >= median) { + v -= median; + return 2; + } + if ((u + v) >= median) { + rotated = true; + return 3; + } + return 0; + } + else { + if (u < median) { + v -= median; + return 1; + } + if (v < median) { + u -= median; + return 2; + } + u -= median; + v -= median; + if ((u + v) < median) { + rotated = false; + return 3; + } + return 0; + } +} + +/// Returns a handle to the sub-patch of the face at the given (u,v). +inline PatchMap::Handle const *PatchMap::FindPatch(int faceid, double u, double v) const +{ + + // + // Reject patch faces not supported by this map, or those corresponding + // to holes or otherwise unassigned (the root node for a patch will + // have all or no quadrants set): + // + if ((faceid < _minPatchFace) || (faceid > _maxPatchFace)) + return 0; + + QuadNode const *node = &_quadtree[faceid - _minPatchFace]; + + if (!node->children[0].isSet) + return 0; + + // + // Search the tree for the sub-patch containing the given (u,v) + // + assert((u >= 0.0) && (u <= 1.0) && (v >= 0.0) && (v <= 1.0)); + + double median = 0.5; + bool triRotated = false; + + for (int depth = 0; depth <= _maxDepth; ++depth, median *= 0.5) { + + int quadrant = _patchesAreTriangular ? transformUVToTriQuadrant(median, u, v, triRotated) : + transformUVToQuadQuadrant(median, u, v); + + // holes should have been rejected at the root node of the face + assert(node->children[quadrant].isSet); + + if (node->children[quadrant].isLeaf) { + return &_handles[node->children[quadrant].index]; + } + else { + node = &_quadtree[node->children[quadrant].index]; + } + } + assert(0); + return 0; +} +} // namespace opensubdiv +} // namespace blender + +#endif // OPENSUBDIV_PATCH_MAP_H_ diff --git a/intern/opensubdiv/internal/topology/mesh_topology.cc b/intern/opensubdiv/internal/topology/mesh_topology.cc index 29c387876ef..461a85fbdfb 100644 --- a/intern/opensubdiv/internal/topology/mesh_topology.cc +++ b/intern/opensubdiv/internal/topology/mesh_topology.cc @@ -183,7 +183,7 @@ void MeshTopology::setNumFaces(int num_faces) num_faces_ = num_faces; // NOTE: Extra element to store fake face past the last real one to make it - // possible to calculate number of verticies in the last face. + // possible to calculate number of vertices in the last face. faces_first_vertex_index_.resize(num_faces + 1, 0); } diff --git a/intern/opensubdiv/internal/topology/mesh_topology.h b/intern/opensubdiv/internal/topology/mesh_topology.h index 861614482ef..a2fad890d9d 100644 --- a/intern/opensubdiv/internal/topology/mesh_topology.h +++ b/intern/opensubdiv/internal/topology/mesh_topology.h @@ -111,7 +111,7 @@ class MeshTopology { // Pipeline related. // This function is to be called when number of vertices, edges, faces, and - // face-verticies are known. + // face-vertices are known. // // Usually is called from the end of topology refiner factory's // resizeComponentTopology(). @@ -162,7 +162,7 @@ class MeshTopology { int num_faces_; - // Continuous array of all verticies of all faces: + // Continuous array of all vertices of all faces: // [vertex indices of face 0][vertex indices of face 1] .. [vertex indices of face n]. vector<int> face_vertex_indices_; diff --git a/intern/opensubdiv/internal/topology/topology_refiner_capi.cc b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc index b30d509be20..547ea190837 100644 --- a/intern/opensubdiv/internal/topology/topology_refiner_capi.cc +++ b/intern/opensubdiv/internal/topology/topology_refiner_capi.cc @@ -225,7 +225,7 @@ void assignFunctionPointers(OpenSubdiv_TopologyRefiner *topology_refiner) OpenSubdiv_TopologyRefiner *allocateTopologyRefiner() { - OpenSubdiv_TopologyRefiner *topology_refiner = OBJECT_GUARDED_NEW(OpenSubdiv_TopologyRefiner); + OpenSubdiv_TopologyRefiner *topology_refiner = MEM_new<OpenSubdiv_TopologyRefiner>(__func__); assignFunctionPointers(topology_refiner); return topology_refiner; } @@ -252,7 +252,7 @@ OpenSubdiv_TopologyRefiner *openSubdiv_createTopologyRefinerFromConverter( void openSubdiv_deleteTopologyRefiner(OpenSubdiv_TopologyRefiner *topology_refiner) { delete topology_refiner->impl; - OBJECT_GUARDED_DELETE(topology_refiner, OpenSubdiv_TopologyRefiner); + MEM_delete(topology_refiner); } bool openSubdiv_topologyRefinerCompareWithConverter( diff --git a/intern/opensubdiv/opensubdiv_converter_capi.h b/intern/opensubdiv/opensubdiv_converter_capi.h index 6f914a20bf5..164a6dfeb03 100644 --- a/intern/opensubdiv/opensubdiv_converter_capi.h +++ b/intern/opensubdiv/opensubdiv_converter_capi.h @@ -135,7 +135,7 @@ typedef struct OpenSubdiv_Converter { // specified in precalcUVLayer(). int (*getNumUVCoordinates)(const struct OpenSubdiv_Converter *converter); // For the given face index and its corner (known as loop in Blender) - // get corrsponding UV coordinate index. + // get corresponding UV coordinate index. int (*getFaceCornerUVIndex)(const struct OpenSubdiv_Converter *converter, const int face_index, const int corner_index); diff --git a/intern/opensubdiv/opensubdiv_evaluator_capi.h b/intern/opensubdiv/opensubdiv_evaluator_capi.h index b860ae8db2e..1afd3e966f6 100644 --- a/intern/opensubdiv/opensubdiv_evaluator_capi.h +++ b/intern/opensubdiv/opensubdiv_evaluator_capi.h @@ -19,6 +19,10 @@ #ifndef OPENSUBDIV_EVALUATOR_CAPI_H_ #define OPENSUBDIV_EVALUATOR_CAPI_H_ +#include <stdint.h> // for uint64_t + +#include "opensubdiv_capi_type.h" + #ifdef __cplusplus extern "C" { #endif @@ -27,6 +31,38 @@ struct OpenSubdiv_EvaluatorInternal; struct OpenSubdiv_PatchCoord; struct OpenSubdiv_TopologyRefiner; +// Callback type for doing input/output operations on buffers. +// Useful to abstract GPU buffers. +typedef struct OpenSubdiv_Buffer { + // Bind the buffer to the GPU. + void (*bind_gpu)(const struct OpenSubdiv_Buffer *buffer); + + // Allocate the buffer directly on the host for the given size in bytes. This has to return + // a pointer to the newly allocated memory. + void *(*alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size); + + // Allocate the buffer directly on the device for the given size in bytes. + void (*device_alloc)(const struct OpenSubdiv_Buffer *buffer, const unsigned int size); + + // Update the given range of the buffer with new data. + void (*device_update)(const struct OpenSubdiv_Buffer *buffer, + unsigned int start, + unsigned int len, + const void *data); + + // Wrap an existing GPU buffer, given its device handle, into the client's buffer type for + // read-only use. + void (*wrap_device_handle)(const struct OpenSubdiv_Buffer *buffer, uint64_t device_ptr); + + // Offset in the buffer where the data starts, if a single buffer is used for multiple data + // channels. + int buffer_offset; + + // Pointer to the client buffer data, which is modified or initialized through the various + // callbacks. + void *data; +} OpenSubdiv_Buffer; + typedef struct OpenSubdiv_Evaluator { // Set coarse positions from a continuous array of coordinates. void (*setCoarsePositions)(struct OpenSubdiv_Evaluator *evaluator, @@ -122,15 +158,78 @@ typedef struct OpenSubdiv_Evaluator { float *dPdu, float *dPdv); + // Copy the patch map to the given buffers, and output some topology information. + void (*getPatchMap)(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_map_handles, + struct OpenSubdiv_Buffer *patch_map_quadtree, + int *min_patch_face, + int *max_patch_face, + int *max_depth, + int *patches_are_triangular); + + // Fill the given buffer with data from the evaluator's patch array buffer. + void (*fillPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_array_buffer); + + // Fill the given buffer with data from the evaluator's patch index buffer. + void (*wrapPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_index_buffer); + + // Fill the given buffer with data from the evaluator's patch parameter buffer. + void (*wrapPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *patch_param_buffer); + + // Fill the given buffer with data from the evaluator's source buffer. + void (*wrapSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator, + struct OpenSubdiv_Buffer *src_buffer); + + // Fill the given buffer with data from the evaluator's face varying patch array buffer. + void (*fillFVarPatchArraysBuffer)(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_array_buffer); + + // Fill the given buffer with data from the evaluator's face varying patch index buffer. + void (*wrapFVarPatchIndexBuffer)(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_index_buffer); + + // Fill the given buffer with data from the evaluator's face varying patch parameter buffer. + void (*wrapFVarPatchParamBuffer)(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *patch_param_buffer); + + // Fill the given buffer with data from the evaluator's face varying source buffer. + void (*wrapFVarSrcBuffer)(struct OpenSubdiv_Evaluator *evaluator, + const int face_varying_channel, + struct OpenSubdiv_Buffer *src_buffer); + // Implementation of the evaluator. struct OpenSubdiv_EvaluatorImpl *impl; + + // Type of the evaluator. + eOpenSubdivEvaluator type; } OpenSubdiv_Evaluator; +typedef struct OpenSubdiv_EvaluatorCache { + // Implementation of the evaluator cache. + struct OpenSubdiv_EvaluatorCacheImpl *impl; +} OpenSubdiv_EvaluatorCache; + OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( - struct OpenSubdiv_TopologyRefiner *topology_refiner); + struct OpenSubdiv_TopologyRefiner *topology_refiner, + eOpenSubdivEvaluator evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache); void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator *evaluator); +OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator evaluator_type); + +void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache *evaluator_cache); + +// Return the GLSL source code from the OpenSubDiv library used for patch evaluation. +// This function is not thread-safe. +const char *openSubdiv_getGLSLPatchBasisSource(void); + #ifdef __cplusplus } #endif diff --git a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc index b7c19bf4f9b..bc39326b57d 100644 --- a/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc +++ b/intern/opensubdiv/stub/opensubdiv_evaluator_stub.cc @@ -21,7 +21,9 @@ #include <cstddef> OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( - struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/) + struct OpenSubdiv_TopologyRefiner * /*topology_refiner*/, + eOpenSubdivEvaluator /*evaluator_type*/, + OpenSubdiv_EvaluatorCache * /*evaluator_cache*/) { return NULL; } @@ -29,3 +31,17 @@ OpenSubdiv_Evaluator *openSubdiv_createEvaluatorFromTopologyRefiner( void openSubdiv_deleteEvaluator(OpenSubdiv_Evaluator * /*evaluator*/) { } + +OpenSubdiv_EvaluatorCache *openSubdiv_createEvaluatorCache(eOpenSubdivEvaluator /*evaluator_type*/) +{ + return NULL; +} + +void openSubdiv_deleteEvaluatorCache(OpenSubdiv_EvaluatorCache * /*evaluator_cache*/) +{ +} + +const char *openSubdiv_getGLSLPatchBasisSource() +{ + return NULL; +} diff --git a/intern/utfconv/utfconv.c b/intern/utfconv/utfconv.c index 00094b84042..673c567070c 100644 --- a/intern/utfconv/utfconv.c +++ b/intern/utfconv/utfconv.c @@ -56,7 +56,7 @@ size_t count_utf_8_from_16(const wchar_t *string16) } else { if (u < 0xE000) { - /*illigal*/; + /*illegal*/; } else { count += 3; diff --git a/release/datafiles/fonts/droidsans.ttf b/release/datafiles/fonts/droidsans.ttf Binary files differindex eea72f53ccd..b03e47f087e 100644 --- a/release/datafiles/fonts/droidsans.ttf +++ b/release/datafiles/fonts/droidsans.ttf diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 9d270fd007f628b23ccbcbd87caa2dc35286b26 +Subproject 620b85f16d03a6aadd7cae56969c9c29b06b992 diff --git a/release/datafiles/userdef/userdef_default.c b/release/datafiles/userdef/userdef_default.c index 3cbc6b26b4a..94d8c13aa06 100644 --- a/release/datafiles/userdef/userdef_default.c +++ b/release/datafiles/userdef/userdef_default.c @@ -61,7 +61,7 @@ const UserDef U_default = { USER_HIDE_DOT | USER_SHOW_GIZMO_NAVIGATE | USER_SHOW_VIEWPORTNAME | USER_SHOW_FPS | USER_CONTINUOUS_MOUSE | USER_SAVE_PROMPT), .uiflag2 = USER_REGION_OVERLAP, - .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE, + .gpu_flag = USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE | USER_GPU_FLAG_SUBDIVISION_EVALUATION, .app_flag = 0, /** Default language of English (1), not Automatic (0). */ .language = 1, diff --git a/release/scripts/addons b/release/scripts/addons -Subproject b3c179b2869d86c44a4b29e2c638ce2a596a820 +Subproject c08568cc376d2e4298710c4172fb0c74f0611de diff --git a/release/scripts/addons_contrib b/release/scripts/addons_contrib -Subproject 16467648282500cc229c271f62201ef897f2c2c +Subproject 7936dde9ece881d531b1a2ee6c45ddb56d30038 diff --git a/release/scripts/modules/bl_i18n_utils/settings.py b/release/scripts/modules/bl_i18n_utils/settings.py index ac932fe38dc..bdc345ee50a 100644 --- a/release/scripts/modules/bl_i18n_utils/settings.py +++ b/release/scripts/modules/bl_i18n_utils/settings.py @@ -100,6 +100,7 @@ LANGUAGES = ( (45, "Abkhaz (Аԥсуа бызшәа)", "ab"), (46, "Thai (ภาษาไทย)", "th_TH"), (47, "Slovak (Slovenčina)", "sk_SK"), + (48, "Georgian (ქართული)", "ka"), ) # Default context, in py (keep in sync with `BLT_translation.h`)! diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index e13eb15dfd2..2e0113051a5 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -1135,6 +1135,7 @@ class I18nMessages: # XXX Temp solution, until I can make own mo generator working... import subprocess with tempfile.NamedTemporaryFile(mode='w+', encoding="utf-8") as tmp_po_f: + os.makedirs(os.path.dirname(fname), exist_ok=True) self.write_messages_to_po(tmp_po_f) cmd = ( self.settings.GETTEXT_MSGFMT_EXECUTABLE, diff --git a/release/scripts/modules/rna_manual_reference.py b/release/scripts/modules/rna_manual_reference.py index 33ce674c672..2983a326358 100644 --- a/release/scripts/modules/rna_manual_reference.py +++ b/release/scripts/modules/rna_manual_reference.py @@ -46,18 +46,21 @@ url_manual_mapping = ( ("bpy.types.fluiddomainsettings.sndparticle_potential_min_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-trappedair"), ("bpy.types.fluiddomainsettings.sndparticle_potential_max_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-wavecrest"), ("bpy.types.fluiddomainsettings.sndparticle_potential_min_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-wavecrest"), + ("bpy.types.lineartgpencilmodifier.use_offset_towards_custom_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-offset-towards-custom-camera"), ("bpy.types.movietrackingsettings.refine_intrinsics_principal_point*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-principal-point"), ("bpy.types.cyclesobjectsettings.shadow_terminator_geometry_offset*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-shadow-terminator-geometry-offset"), ("bpy.types.cyclesrenderlayersettings.denoising_optix_input_passes*", "render/layers/denoising.html#bpy-types-cyclesrenderlayersettings-denoising-optix-input-passes"), ("bpy.types.sequencertoolsettings.use_snap_current_frame_to_strips*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-use-snap-current-frame-to-strips"), ("bpy.types.fluiddomainsettings.sndparticle_potential_max_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-max-energy"), ("bpy.types.fluiddomainsettings.sndparticle_potential_min_energy*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-min-energy"), + ("bpy.types.lineartgpencilmodifier.use_overlap_edge_type_support*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-overlap-edge-type-support"), ("bpy.types.movietrackingsettings.refine_intrinsics_focal_length*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-refine-intrinsics-focal-length"), ("bpy.types.rigidbodyconstraint.rigidbodyconstraint.use_breaking*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-rigidbodyconstraint-use-breaking"), ("bpy.types.cyclesrendersettings.preview_denoising_input_passes*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-input-passes"), ("bpy.types.cyclesrendersettings.preview_denoising_start_sample*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-start-sample"), ("bpy.types.fluiddomainsettings.sndparticle_sampling_trappedair*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-trappedair"), ("bpy.types.fluiddomainsettings.sndparticle_sampling_wavecrest*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-sampling-wavecrest"), + ("bpy.types.lineartgpencilmodifier.use_image_boundary_trimming*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-image-boundary-trimming"), ("bpy.types.rigidbodyconstraint.use_override_solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-use-override-solver-iterations"), ("bpy.types.toolsettings.use_transform_correct_face_attributes*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-transform-correct-face-attributes"), ("bpy.types.cyclesrendersettings.adaptive_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-scrambling-distance"), @@ -67,6 +70,7 @@ url_manual_mapping = ( ("bpy.types.cyclesrendersettings.preview_denoising_prefilter*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoising-prefilter"), ("bpy.types.cyclesrendersettings.preview_scrambling_distance*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-scrambling-distance"), ("bpy.types.fluiddomainsettings.sndparticle_potential_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-potential-radius"), + ("bpy.types.brushgpencilsettings.use_stroke_random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-strength"), ("bpy.types.cyclesrendersettings.film_transparent_roughness*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-roughness"), ("bpy.types.cyclesrendersettings.preview_adaptive_threshold*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-adaptive-threshold"), ("bpy.types.fluiddomainsettings.openvdb_cache_compress_type*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-openvdb-cache-compress-type"), @@ -74,13 +78,19 @@ url_manual_mapping = ( ("bpy.types.fluiddomainsettings.sndparticle_combined_export*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-combined-export"), ("bpy.types.fluiddomainsettings.use_collision_border_bottom*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-bottom"), ("bpy.types.fluiddomainsettings.vector_scale_with_magnitude*", "physics/fluid/type/domain/gas/viewport_display.html#bpy-types-fluiddomainsettings-vector-scale-with-magnitude"), + ("bpy.types.lineartgpencilmodifier.use_face_mark_boundaries*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-boundaries"), ("bpy.types.movietrackingstabilization.use_2d_stabilization*", "movie_clip/tracking/clip/sidebar/stabilization/panel.html#bpy-types-movietrackingstabilization-use-2d-stabilization"), ("bpy.types.spacespreadsheet.display_context_path_collapsed*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-display-context-path-collapsed"), ("bpy.types.toolsettings.annotation_stroke_placement_view2d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view2d"), ("bpy.types.toolsettings.annotation_stroke_placement_view3d*", "interface/annotate_tool.html#bpy-types-toolsettings-annotation-stroke-placement-view3d"), + ("bpy.types.brushgpencilsettings.use_random_press_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-strength"), ("bpy.types.fluiddomainsettings.use_collision_border_front*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-front"), ("bpy.types.fluiddomainsettings.use_collision_border_right*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-right"), ("bpy.types.sequencertimelineoverlay.waveform_display_type*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-waveform-display-type"), + ("bpy.types.view3doverlay.use_normals_constant_screen_size*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-use-normals-constant-screen-size"), + ("bpy.types.brushgpencilsettings.random_saturation_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-saturation-factor"), + ("bpy.types.brushgpencilsettings.use_settings_postprocess*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-postprocess"), + ("bpy.types.brushgpencilsettings.use_stroke_random_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-radius"), ("bpy.types.cyclesmaterialsettings.use_transparent_shadow*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-use-transparent-shadow"), ("bpy.types.cyclesobjectsettings.shadow_terminator_offset*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-shadow-terminator-offset"), ("bpy.types.cyclesobjectsettings.use_adaptive_subdivision*", "render/cycles/object_settings/adaptive_subdiv.html#bpy-types-cyclesobjectsettings-use-adaptive-subdivision"), @@ -91,28 +101,44 @@ url_manual_mapping = ( ("bpy.types.fluiddomainsettings.sndparticle_update_radius*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-update-radius"), ("bpy.types.fluiddomainsettings.use_collision_border_back*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-back"), ("bpy.types.fluiddomainsettings.use_collision_border_left*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-left"), + ("bpy.types.lineartgpencilmodifier.use_intersection_match*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-match"), ("bpy.types.rendersettings_simplify_gpencil_view_modifier*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-modifier"), + ("bpy.types.brushgpencilsettings.eraser_thickness_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-thickness-factor"), + ("bpy.types.brushgpencilsettings.use_random_press_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-radius"), ("bpy.types.brushgpencilsettings.use_settings_stabilizer*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-stabilizer"), ("bpy.types.colormanagedsequencercolorspacesettings.name*", "render/color_management.html#bpy-types-colormanagedsequencercolorspacesettings-name"), ("bpy.types.cyclesrendersettings.max_transparent_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-max-transparent-bounces"), ("bpy.types.cyclesrendersettings.min_transparent_bounces*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-min-transparent-bounces"), ("bpy.types.fluiddomainsettings.use_collision_border_top*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-use-collision-border-top"), + ("bpy.types.gpencilsculptsettings.intersection_threshold*", "grease_pencil/modes/draw/tools/cutter.html#bpy-types-gpencilsculptsettings-intersection-threshold"), ("bpy.types.gpencilsculptsettings.use_multiframe_falloff*", "grease_pencil/multiframe.html#bpy-types-gpencilsculptsettings-use-multiframe-falloff"), + ("bpy.types.lineartgpencilmodifier.use_intersection_mask*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-intersection-mask"), ("bpy.types.movietrackingsettings.use_keyframe_selection*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-keyframe-selection"), ("bpy.types.rendersettings.simplify_gpencil_antialiasing*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-antialiasing"), ("bpy.types.sequencertimelineoverlay.show_strip_duration*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-duration"), ("bpy.types.spaceoutliner.use_filter_lib_override_system*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override-system"), ("bpy.types.toolsettings.use_transform_pivot_point_align*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-pivot-point-align"), + ("bpy.types.animvizmotionpaths.show_keyframe_action_all*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-action-all"), ("bpy.types.brush.show_multiplane_scrape_planes_preview*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-show-multiplane-scrape-planes-preview"), + ("bpy.types.brushgpencilsettings.eraser_strength_factor*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-strength-factor"), ("bpy.types.cyclesmaterialsettings.volume_interpolation*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-volume-interpolation"), ("bpy.types.cyclesrendersettings.debug_optix_curves_api*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-optix-curves-api"), ("bpy.types.cyclesrendersettings.denoising_input_passes*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoising-input-passes"), ("bpy.types.cyclesrendersettings.film_transparent_glass*", "render/cycles/render_settings/film.html#bpy-types-cyclesrendersettings-film-transparent-glass"), ("bpy.types.cyclesrendersettings.offscreen_dicing_scale*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-offscreen-dicing-scale"), ("bpy.types.fluiddomainsettings.sndparticle_bubble_drag*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-sndparticle-bubble-drag"), + ("bpy.types.lineartgpencilmodifier.use_crease_on_smooth*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-smooth"), + ("bpy.types.lineartgpencilmodifier.use_face_mark_invert*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark-invert"), ("bpy.types.linestylegeometrymodifier_backbonestretcher*", "render/freestyle/view_layer/line_style/modifiers/geometry/backbone_stretcher.html#bpy-types-linestylegeometrymodifier-backbonestretcher"), ("bpy.types.linestylegeometrymodifier_sinusdisplacement*", "render/freestyle/view_layer/line_style/modifiers/geometry/sinus_displacement.html#bpy-types-linestylegeometrymodifier-sinusdisplacement"), ("bpy.types.sequencertoolsettings.snap_to_current_frame*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-to-current-frame"), + ("bpy.ops.object.geometry_nodes_input_attribute_toggle*", "modeling/modifiers/generate/geometry_nodes.html#bpy-ops-object-geometry-nodes-input-attribute-toggle"), + ("bpy.types.animvizmotionpaths.show_keyframe_highlight*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-highlight"), + ("bpy.types.brushgpencilsettings.pen_subdivision_steps*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-subdivision-steps"), + ("bpy.types.brushgpencilsettings.use_strength_pressure*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-use-strength-pressure"), + ("bpy.types.brushgpencilsettings.use_stroke_random_hue*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-hue"), + ("bpy.types.brushgpencilsettings.use_stroke_random_sat*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-sat"), + ("bpy.types.brushgpencilsettings.use_stroke_random_val*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-val"), ("bpy.types.colormanageddisplaysettings.display_device*", "render/color_management.html#bpy-types-colormanageddisplaysettings-display-device"), ("bpy.types.colormanagedviewsettings.use_curve_mapping*", "render/color_management.html#bpy-types-colormanagedviewsettings-use-curve-mapping"), ("bpy.types.cyclesrendersettings.sample_clamp_indirect*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-sample-clamp-indirect"), @@ -126,11 +152,19 @@ url_manual_mapping = ( ("bpy.types.gpencillayer.annotation_onion_before_range*", "interface/annotate_tool.html#bpy-types-gpencillayer-annotation-onion-before-range"), ("bpy.types.gpencillayer.use_annotation_onion_skinning*", "interface/annotate_tool.html#bpy-types-gpencillayer-use-annotation-onion-skinning"), ("bpy.types.greasepencil.use_adaptive_curve_resolution*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-adaptive-curve-resolution"), + ("bpy.types.lineartgpencilmodifier.stroke_depth_offset*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-stroke-depth-offset"), + ("bpy.types.lineartgpencilmodifier.use_crease_on_sharp*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-crease-on-sharp"), ("bpy.types.linestylegeometrymodifier_polygonalization*", "render/freestyle/view_layer/line_style/modifiers/geometry/polygonization.html#bpy-types-linestylegeometrymodifier-polygonalization"), ("bpy.types.sequencertimelineoverlay.show_strip_source*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-source"), ("bpy.types.toolsettings.use_gpencil_automerge_strokes*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-automerge-strokes"), ("bpy.types.toolsettings.use_proportional_edit_objects*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit-objects"), ("bpy.ops.view3d.edit_mesh_extrude_move_shrink_fatten*", "modeling/meshes/editing/face/extrude_faces_normal.html#bpy-ops-view3d-edit-mesh-extrude-move-shrink-fatten"), + ("bpy.types.brushgpencilsettings.active_smooth_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-active-smooth-factor"), + ("bpy.types.brushgpencilsettings.extend_stroke_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-extend-stroke-factor"), + ("bpy.types.brushgpencilsettings.use_random_press_hue*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-hue"), + ("bpy.types.brushgpencilsettings.use_random_press_sat*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-sat"), + ("bpy.types.brushgpencilsettings.use_random_press_val*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-val"), + ("bpy.types.brushgpencilsettings.use_stroke_random_uv*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-stroke-random-uv"), ("bpy.types.cyclesmaterialsettings.homogeneous_volume*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-homogeneous-volume"), ("bpy.types.cyclesrendersettings.adaptive_min_samples*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-min-samples"), ("bpy.types.cyclesrendersettings.debug_bvh_time_steps*", "render/cycles/render_settings/performance.html#bpy-types-cyclesrendersettings-debug-bvh-time-steps"), @@ -153,11 +187,15 @@ url_manual_mapping = ( ("bpy.types.rendersettings_simplify_gpencil_view_fill*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-view-fill"), ("bpy.types.sequencertoolsettings.snap_to_hold_offset*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-to-hold-offset"), ("bpy.types.toolsettings.use_mesh_automerge_and_split*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-mesh-automerge-and-split"), + ("bpy.types.animvizmotionpaths.show_keyframe_numbers*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-keyframe-numbers"), ("bpy.types.brush.cloth_constraint_softbody_strength*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-constraint-softbody-strength"), ("bpy.types.brush.elastic_deform_volume_preservation*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-volume-preservation"), ("bpy.types.brushgpencilsettings.fill_simplify_level*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-simplify-level"), + ("bpy.types.brushgpencilsettings.random_value_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-value-factor"), ("bpy.types.brushgpencilsettings.use_jitter_pressure*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-jitter-pressure"), + ("bpy.types.brushgpencilsettings.use_random_press_uv*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-random-press-uv"), ("bpy.types.brushgpencilsettings.use_settings_random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-settings-random"), + ("bpy.types.collection.lineart_use_intersection_mask*", "scene_layout/collections/collections.html#bpy-types-collection-lineart-use-intersection-mask"), ("bpy.types.colormanagedinputcolorspacesettings.name*", "editors/image/image_settings.html#bpy-types-colormanagedinputcolorspacesettings-name"), ("bpy.types.cyclesrendersettings.denoising_prefilter*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-denoising-prefilter"), ("bpy.types.cyclesrendersettings.preview_dicing_rate*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-preview-dicing-rate"), @@ -171,9 +209,11 @@ url_manual_mapping = ( ("bpy.types.fluiddomainsettings.sys_particle_maximum*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-sys-particle-maximum"), ("bpy.types.fluiddomainsettings.use_bubble_particles*", "physics/fluid/type/domain/liquid/particles.html#bpy-types-fluiddomainsettings-use-bubble-particles"), ("bpy.types.freestylelineset.select_external_contour*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-select-external-contour"), + ("bpy.types.lineartgpencilmodifier.use_custom_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-custom-camera"), ("bpy.types.linestylegeometrymodifier_simplification*", "render/freestyle/view_layer/line_style/modifiers/geometry/simplification.html#bpy-types-linestylegeometrymodifier-simplification"), ("bpy.types.materialgpencilstyle.use_overlap_strokes*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-overlap-strokes"), ("bpy.types.sequencertimelineoverlay.show_strip_name*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-strip-name"), + ("bpy.types.sequencertimelineoverlay.show_thumbnails*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-thumbnails"), ("bpy.types.spacespreadsheet.geometry_component_type*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-geometry-component-type"), ("bpy.types.toolsettings.use_gpencil_weight_data_add*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-weight-data-add"), ("bpy.types.view3doverlay.texture_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-texture-paint-mode-opacity"), @@ -189,6 +229,7 @@ url_manual_mapping = ( ("bpy.types.cyclesrendersettings.adaptive_threshold*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-adaptive-threshold"), ("bpy.types.cyclesrendersettings.camera_cull_margin*", "render/cycles/render_settings/simplify.html#bpy-types-cyclesrendersettings-camera-cull-margin"), ("bpy.types.cyclesrendersettings.debug_use_hair_bvh*", "render/cycles/render_settings/performance.html#bpy-types-cyclesrendersettings-debug-use-hair-bvh"), + ("bpy.types.fileassetselectparams.asset_library_ref*", "editors/asset_browser.html#bpy-types-fileassetselectparams-asset-library-ref"), ("bpy.types.fluiddomainsettings.export_manta_script*", "physics/fluid/type/domain/cache.html#bpy-types-fluiddomainsettings-export-manta-script"), ("bpy.types.fluiddomainsettings.fractions_threshold*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-fractions-threshold"), ("bpy.types.fluiddomainsettings.particle_band_width*", "physics/fluid/type/domain/settings.html#bpy-types-fluiddomainsettings-particle-band-width"), @@ -200,26 +241,29 @@ url_manual_mapping = ( ("bpy.types.freestylelineset.select_by_image_border*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset-select-by-image-border"), ("bpy.types.freestylesettings.kr_derivative_epsilon*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-kr-derivative-epsilon"), ("bpy.types.geometrynodecurveprimitivebeziersegment*", "modeling/geometry_nodes/curve_primitives/bezier_segment.html#bpy-types-geometrynodecurveprimitivebeziersegment"), + ("bpy.types.lineartgpencilmodifier.smooth_tolerance*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-smooth-tolerance"), ("bpy.types.linestylegeometrymodifier_perlinnoise1d*", "render/freestyle/view_layer/line_style/modifiers/geometry/perlin_noise_1d.html#bpy-types-linestylegeometrymodifier-perlinnoise1d"), ("bpy.types.linestylegeometrymodifier_perlinnoise2d*", "render/freestyle/view_layer/line_style/modifiers/geometry/perlin_noise_2d.html#bpy-types-linestylegeometrymodifier-perlinnoise2d"), ("bpy.types.materialgpencilstyle.use_stroke_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-stroke-holdout"), ("bpy.types.movietrackingsettings.use_tripod_solver*", "movie_clip/tracking/clip/toolbar/solve.html#bpy-types-movietrackingsettings-use-tripod-solver"), ("bpy.types.rendersettings.simplify_child_particles*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-child-particles"), ("bpy.types.rendersettings.use_high_quality_normals*", "render/eevee/render_settings/performance.html#bpy-types-rendersettings-use-high-quality-normals"), - ("bpy.types.sequencerpreviewoverlay.show_annotation*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-annotation"), - ("bpy.types.sequencerpreviewoverlay.show_safe_areas*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-safe-areas"), + ("bpy.types.sequencerpreviewoverlay.show_annotation*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-annotation"), + ("bpy.types.sequencerpreviewoverlay.show_safe_areas*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-safe-areas"), ("bpy.types.sequencertoolsettings.snap_ignore_muted*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-ignore-muted"), ("bpy.types.sequencertoolsettings.snap_ignore_sound*", "video_editing/sequencer/editing.html#bpy-types-sequencertoolsettings-snap-ignore-sound"), ("bpy.types.spaceoutliner.use_filter_case_sensitive*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-case-sensitive"), ("bpy.types.spaceoutliner.use_filter_object_content*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-content"), + ("bpy.types.spacesequenceeditor.show_gizmo_navigate*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo-navigate"), ("bpy.types.toolsettings.use_proportional_connected*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-connected"), ("bpy.types.toolsettings.use_proportional_projected*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-projected"), ("bpy.types.view3doverlay.vertex_paint_mode_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-vertex-paint-mode-opacity"), - ("bpy.types.viewlayer.use_pass_cryptomatte_accurate*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-accurate"), ("bpy.types.viewlayer.use_pass_cryptomatte_material*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-material"), ("bpy.ops.gpencil.vertex_color_brightness_contrast*", "grease_pencil/modes/vertex_paint/editing.html#bpy-ops-gpencil-vertex-color-brightness-contrast"), ("bpy.ops.view3d.edit_mesh_extrude_individual_move*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-individual-move"), ("bpy.ops.view3d.edit_mesh_extrude_manifold_normal*", "modeling/meshes/tools/extrude_manifold.html#bpy-ops-view3d-edit-mesh-extrude-manifold-normal"), + ("bpy.types.brushgpencilsettings.pen_smooth_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-smooth-factor"), + ("bpy.types.brushgpencilsettings.random_hue_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-hue-factor"), ("bpy.types.cyclescurverendersettings.subdivisions*", "render/cycles/render_settings/hair.html#bpy-types-cyclescurverendersettings-subdivisions"), ("bpy.types.cyclesmaterialsettings.sample_as_light*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-sample-as-light"), ("bpy.types.cyclesmaterialsettings.volume_sampling*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-volume-sampling"), @@ -248,6 +292,8 @@ url_manual_mapping = ( ("bpy.types.linestylegeometrymodifier_guidinglines*", "render/freestyle/view_layer/line_style/modifiers/geometry/guiding_lines.html#bpy-types-linestylegeometrymodifier-guidinglines"), ("bpy.types.linestylegeometrymodifier_spatialnoise*", "render/freestyle/view_layer/line_style/modifiers/geometry/spatial_noise.html#bpy-types-linestylegeometrymodifier-spatialnoise"), ("bpy.types.linestylethicknessmodifier_calligraphy*", "render/freestyle/view_layer/line_style/modifiers/thickness/calligraphy.html#bpy-types-linestylethicknessmodifier-calligraphy"), + ("bpy.types.materiallineart.use_material_mask_bits*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask-bits"), + ("bpy.types.movietrackingdopesheet.use_invert_sort*", "movie_clip/tracking/dope_sheet.html#bpy-types-movietrackingdopesheet-use-invert-sort"), ("bpy.types.rendersettings_simplify_gpencil_onplay*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-gpencil-onplay"), ("bpy.types.rigidbodyconstraint.breaking_threshold*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-breaking-threshold"), ("bpy.types.spaceclipeditor.use_manual_calibration*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-manual-calibration"), @@ -255,14 +301,19 @@ url_manual_mapping = ( ("bpy.types.spaceoutliner.use_filter_object_camera*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-camera"), ("bpy.types.spaceoutliner.use_filter_object_others*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object-others"), ("bpy.types.spacesequenceeditor.show_strip_overlay*", "editors/video_sequencer/sequencer/display.html#bpy-types-spacesequenceeditor-show-strip-overlay"), + ("bpy.types.spaceuveditor.custom_grid_subdivisions*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-custom-grid-subdivisions"), ("bpy.types.toolsettings.proportional_edit_falloff*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-proportional-edit-falloff"), ("bpy.types.toolsettings.use_edge_path_live_unwrap*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-use-edge-path-live-unwrap"), ("bpy.types.toolsettings.use_gpencil_draw_additive*", "grease_pencil/modes/draw/introduction.html#bpy-types-toolsettings-use-gpencil-draw-additive"), ("bpy.types.toolsettings.use_snap_backface_culling*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-backface-culling"), + ("bpy.types.toolsettings.use_snap_uv_grid_absolute*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-use-snap-uv-grid-absolute"), ("bpy.types.toolsettings.use_transform_data_origin*", "scene_layout/object/tools/tool_settings.html#bpy-types-toolsettings-use-transform-data-origin"), ("bpy.types.view3doverlay.sculpt_mode_mask_opacity*", "sculpt_paint/sculpting/editing/mask.html#bpy-types-view3doverlay-sculpt-mode-mask-opacity"), ("bpy.ops.mesh.customdata_custom_splitnormals_add*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-custom-splitnormals-add"), ("bpy.ops.outliner.collection_indirect_only_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-indirect-only-clear"), + ("bpy.types.animvizmotionpaths.show_frame_numbers*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-show-frame-numbers"), + ("bpy.types.brushgpencilsettings.pen_smooth_steps*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-smooth-steps"), + ("bpy.types.brushgpencilsettings.show_fill_extend*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-show-fill-extend"), ("bpy.types.cyclesrendersettings.max_subdivisions*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-max-subdivisions"), ("bpy.types.cyclesrendersettings.preview_denoiser*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-preview-denoiser"), ("bpy.types.cyclesrendersettings.sampling_pattern*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-sampling-pattern"), @@ -293,7 +344,7 @@ url_manual_mapping = ( ("bpy.types.materialgpencilstyle.use_fill_holdout*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-use-fill-holdout"), ("bpy.types.particlesettings.use_parent_particles*", "physics/particles/emitter/render.html#bpy-types-particlesettings-use-parent-particles"), ("bpy.types.rigidbodyconstraint.solver_iterations*", "physics/rigid_body/constraints/introduction.html#bpy-types-rigidbodyconstraint-solver-iterations"), - ("bpy.types.sequencerpreviewoverlay.show_metadata*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay-show-metadata"), + ("bpy.types.sequencerpreviewoverlay.show_metadata*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-metadata"), ("bpy.types.sequencertimelineoverlay.show_fcurves*", "editors/video_sequencer/sequencer/display.html#bpy-types-sequencertimelineoverlay-show-fcurves"), ("bpy.types.spaceclipeditor.use_grayscale_preview*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-grayscale-preview"), ("bpy.types.spaceoutliner.use_filter_lib_override*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-lib-override"), @@ -307,6 +358,9 @@ url_manual_mapping = ( ("bpy.types.viewlayer.use_pass_cryptomatte_object*", "render/layers/passes.html#bpy-types-viewlayer-use-pass-cryptomatte-object"), ("bpy.ops.armature.rigify_apply_selection_colors*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-apply-selection-colors"), ("bpy.types.brushgpencilsettings.fill_layer_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-layer-mode"), + ("bpy.types.brushgpencilsettings.random_strength*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random-strength"), + ("bpy.types.brushgpencilsettings.simplify_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-simplify-factor"), + ("bpy.types.collection.lineart_intersection_mask*", "scene_layout/collections/collections.html#bpy-types-collection-lineart-intersection-mask"), ("bpy.types.cyclesobjectsettings.use_camera_cull*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-use-camera-cull"), ("bpy.types.cyclesobjectsettings.use_motion_blur*", "render/cycles/object_settings/object_data.html#bpy-types-cyclesobjectsettings-use-motion-blur"), ("bpy.types.cyclesrendersettings.diffuse_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-diffuse-bounces"), @@ -325,6 +379,8 @@ url_manual_mapping = ( ("bpy.types.freestylesettings.use_view_map_cache*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-view-map-cache"), ("bpy.types.geometrynodecurvehandletypeselection*", "modeling/geometry_nodes/curve/handle_type_selection.html#bpy-types-geometrynodecurvehandletypeselection"), ("bpy.types.greasepencil.curve_edit_corner_angle*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-corner-angle"), + ("bpy.types.lineartgpencilmodifier.source_camera*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-source-camera"), + ("bpy.types.lineartgpencilmodifier.use_face_mark*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-face-mark"), ("bpy.types.linestylegeometrymodifier_tipremover*", "render/freestyle/view_layer/line_style/modifiers/geometry/tip_remover.html#bpy-types-linestylegeometrymodifier-tipremover"), ("bpy.types.movieclipuser.use_render_undistorted*", "editors/clip/display/clip_display.html#bpy-types-movieclipuser-use-render-undistorted"), ("bpy.types.movietrackingcamera.distortion_model*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-distortion-model"), @@ -345,9 +401,11 @@ url_manual_mapping = ( ("bpy.types.brushgpencilsettings.fill_direction*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-direction"), ("bpy.types.brushgpencilsettings.fill_draw_mode*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-draw-mode"), ("bpy.types.brushgpencilsettings.fill_threshold*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-threshold"), + ("bpy.types.brushgpencilsettings.use_fill_limit*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-use-fill-limit"), ("bpy.types.clothsettings.vertex_group_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-pressure"), ("bpy.types.cyclesmaterialsettings.displacement*", "render/cycles/material_settings.html#bpy-types-cyclesmaterialsettings-displacement"), ("bpy.types.cyclesrendersettings.debug_bvh_type*", "render/cycles/render_settings/debug.html#bpy-types-cyclesrendersettings-debug-bvh-type"), + ("bpy.types.cyclesrendersettings.fast_gi_method*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-fast-gi-method"), ("bpy.types.cyclesrendersettings.glossy_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-glossy-bounces"), ("bpy.types.cyclesrendersettings.volume_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-volume-bounces"), ("bpy.types.cyclesworldsettings.sampling_method*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings-sampling-method"), @@ -376,9 +434,12 @@ url_manual_mapping = ( ("bpy.types.particlesettings.use_modifier_stack*", "physics/particles/emitter/emission.html#bpy-types-particlesettings-use-modifier-stack"), ("bpy.types.rendersettings.sequencer_gl_preview*", "video_editing/preview/sidebar.html#bpy-types-rendersettings-sequencer-gl-preview"), ("bpy.types.rendersettings.simplify_subdivision*", "render/cycles/render_settings/simplify.html#bpy-types-rendersettings-simplify-subdivision"), + ("bpy.types.sequencerpreviewoverlay.show_cursor*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay-show-cursor"), ("bpy.types.spacegrapheditor.show_extrapolation*", "editors/graph_editor/introduction.html#bpy-types-spacegrapheditor-show-extrapolation"), ("bpy.types.spaceoutliner.use_filter_collection*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-collection"), + ("bpy.types.spacesequenceeditor.cursor_location*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-cursor-location"), ("bpy.types.spacesequenceeditor.display_channel*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-display-channel"), + ("bpy.types.spacesequenceeditor.show_gizmo_tool*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo-tool"), ("bpy.types.spacesequenceeditor.show_region_hud*", "video_editing/sequencer/navigating.html#bpy-types-spacesequenceeditor-show-region-hud"), ("bpy.types.spacespreadsheet.show_only_selected*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-show-only-selected"), ("bpy.types.spacespreadsheetrowfilter.operation*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-operation"), @@ -386,12 +447,12 @@ url_manual_mapping = ( ("bpy.types.toolsettings.use_snap_grid_absolute*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-grid-absolute"), ("bpy.types.view3doverlay.show_face_orientation*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-show-face-orientation"), ("bpy.ops.gpencil.bake_grease_pencil_animation*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-bake-grease-pencil-animation"), - ("bpy.ops.object.blenderkit_material_thumbnail*", "addons/3d_view/blenderkit.html#bpy-ops-object-blenderkit-material-thumbnail"), ("bpy.ops.object.multires_higher_levels_delete*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-higher-levels-delete"), ("bpy.ops.object.vertex_group_copy_to_selected*", "modeling/meshes/properties/vertex_groups/vertex_groups.html#bpy-ops-object-vertex-group-copy-to-selected"), ("bpy.ops.outliner.collection_duplicate_linked*", "editors/outliner/editing.html#bpy-ops-outliner-collection-duplicate-linked"), ("bpy.ops.view3d.edit_mesh_extrude_move_normal*", "modeling/meshes/editing/face/extrude_faces.html#bpy-ops-view3d-edit-mesh-extrude-move-normal"), ("bpy.types.bakesettings.use_pass_transmission*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-transmission"), + ("bpy.types.brushgpencilsettings.input_samples*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-input-samples"), ("bpy.types.clothsettings.internal_compression*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-compression"), ("bpy.types.cyclescamerasettings.panorama_type*", "render/cycles/object_settings/cameras.html#bpy-types-cyclescamerasettings-panorama-type"), ("bpy.types.cyclesrendersettings.dicing_camera*", "render/cycles/render_settings/subdivision.html#bpy-types-cyclesrendersettings-dicing-camera"), @@ -425,6 +486,7 @@ url_manual_mapping = ( ("bpy.types.greasepencil.edit_curve_resolution*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-edit-curve-resolution"), ("bpy.types.linestylegeometrymodifier_2doffset*", "render/freestyle/view_layer/line_style/modifiers/geometry/2d_offset.html#bpy-types-linestylegeometrymodifier-2doffset"), ("bpy.types.linestylegeometrymodifier_sampling*", "render/freestyle/view_layer/line_style/modifiers/geometry/sampling.html#bpy-types-linestylegeometrymodifier-sampling"), + ("bpy.types.movietrackingdopesheet.sort_method*", "movie_clip/tracking/dope_sheet.html#bpy-types-movietrackingdopesheet-sort-method"), ("bpy.types.nodesocketinterface*.default_value*", "interface/controls/nodes/groups.html#bpy-types-nodesocketinterface-default-value"), ("bpy.types.rendersettings.line_thickness_mode*", "render/freestyle/render.html#bpy-types-rendersettings-line-thickness-mode"), ("bpy.types.rendersettings.motion_blur_shutter*", "render/cycles/render_settings/motion_blur.html#bpy-types-rendersettings-motion-blur-shutter"), @@ -434,9 +496,12 @@ url_manual_mapping = ( ("bpy.types.spaceclipeditor.show_green_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-green-channel"), ("bpy.types.spaceoutliner.show_restrict_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-restrict-column"), ("bpy.types.spacespreadsheet.object_eval_state*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-object-eval-state"), + ("bpy.types.spaceuveditor.display_stretch_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-display-stretch-type"), ("bpy.types.toolsettings.transform_pivot_point*", "editors/3dview/controls/pivot_point/index.html#bpy-types-toolsettings-transform-pivot-point"), ("bpy.types.toolsettings.use_proportional_edit*", "editors/3dview/controls/proportional_editing.html#bpy-types-toolsettings-use-proportional-edit"), ("bpy.types.volumedisplay.interpolation_method*", "modeling/volumes/properties.html#bpy-types-volumedisplay-interpolation-method"), + ("bpy.types.brushgpencilsettings.angle_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle-factor"), + ("bpy.types.brushgpencilsettings.pen_strength*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-pen-strength"), ("bpy.types.clothsettings.use_pressure_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-use-pressure-volume"), ("bpy.types.clothsettings.vertex_group_intern*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-vertex-group-intern"), ("bpy.types.colormanagedviewsettings.exposure*", "render/color_management.html#bpy-types-colormanagedviewsettings-exposure"), @@ -459,11 +524,13 @@ url_manual_mapping = ( ("bpy.types.geometrynodeinputsplineresolution*", "modeling/geometry_nodes/curve/spline_resolution.html#bpy-types-geometrynodeinputsplineresolution"), ("bpy.types.greasepencil.curve_edit_threshold*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-curve-edit-threshold"), ("bpy.types.materialgpencilstyle.stroke_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-stroke-style"), + ("bpy.types.materiallineart.use_material_mask*", "render/materials/line_art.html#bpy-types-materiallineart-use-material-mask"), ("bpy.types.objectlineart.use_crease_override*", "scene_layout/object/properties/line_art.html#bpy-types-objectlineart-use-crease-override"), ("bpy.types.rendersettings.preview_pixel_size*", "render/cycles/render_settings/performance.html#bpy-types-rendersettings-preview-pixel-size"), ("bpy.types.rendersettings.use_crop_to_border*", "render/output/properties/format.html#bpy-types-rendersettings-use-crop-to-border"), ("bpy.types.rendersettings.use_file_extension*", "render/output/properties/output.html#bpy-types-rendersettings-use-file-extension"), ("bpy.types.sculpt.constant_detail_resolution*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-sculpt-constant-detail-resolution"), + ("bpy.types.sequencertoolsettings.pivot_point*", "editors/video_sequencer/preview/controls/pivot_point.html#bpy-types-sequencertoolsettings-pivot-point"), ("bpy.types.spaceclipeditor.annotation_source*", "movie_clip/tracking/clip/sidebar/view.html#bpy-types-spaceclipeditor-annotation-source"), ("bpy.types.spaceclipeditor.show_blue_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-blue-channel"), ("bpy.types.spacefilebrowser.system_bookmarks*", "editors/file_browser.html#bpy-types-spacefilebrowser-system-bookmarks"), @@ -471,6 +538,7 @@ url_manual_mapping = ( ("bpy.types.spaceoutliner.use_filter_complete*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-complete"), ("bpy.types.spacespreadsheet.attribute_domain*", "editors/spreadsheet.html#bpy-types-spacespreadsheet-attribute-domain"), ("bpy.types.spacespreadsheetrowfilter.enabled*", "editors/spreadsheet.html#bpy-types-spacespreadsheetrowfilter-enabled"), + ("bpy.types.spaceuveditor.show_modified_edges*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-modified-edges"), ("bpy.types.spaceview3d.transform_orientation*", "editors/3dview/controls/orientation.html#bpy-types-spaceview3d-transform-orientation"), ("bpy.types.spaceview3d.use_local_collections*", "editors/3dview/sidebar.html#bpy-types-spaceview3d-use-local-collections"), ("bpy.types.toolsettings.use_snap_peel_object*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-peel-object"), @@ -482,6 +550,7 @@ url_manual_mapping = ( ("bpy.ops.scene.freestyle_alpha_modifier_add*", "render/freestyle/view_layer/line_style/alpha.html#bpy-ops-scene-freestyle-alpha-modifier-add"), ("bpy.ops.scene.freestyle_color_modifier_add*", "render/freestyle/view_layer/line_style/color.html#bpy-ops-scene-freestyle-color-modifier-add"), ("bpy.types.brush.cloth_simulation_area_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-simulation-area-type"), + ("bpy.types.brushgpencilsettings.eraser_mode*", "grease_pencil/modes/draw/tools/erase.html#bpy-types-brushgpencilsettings-eraser-mode"), ("bpy.types.brushgpencilsettings.fill_factor*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-factor"), ("bpy.types.curve.bevel_factor_mapping_start*", "modeling/curves/properties/geometry.html#bpy-types-curve-bevel-factor-mapping-start"), ("bpy.types.cyclescamerasettings.fisheye_fov*", "render/cycles/object_settings/cameras.html#bpy-types-cyclescamerasettings-fisheye-fov"), @@ -512,6 +581,8 @@ url_manual_mapping = ( ("bpy.types.freestylesettings.as_render_pass*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-as-render-pass"), ("bpy.types.freestylesettings.use_smoothness*", "render/freestyle/view_layer/freestyle.html#bpy-types-freestylesettings-use-smoothness"), ("bpy.types.geometrynodecurvequadraticbezier*", "modeling/geometry_nodes/curve_primitives/quadratic_bezier.html#bpy-types-geometrynodecurvequadraticbezier"), + ("bpy.types.lineartgpencilmodifier.use_cache*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-cache"), + ("bpy.types.lineartgpencilmodifier.use_loose*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-use-loose"), ("bpy.types.materialgpencilstyle.show_stroke*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-show-stroke"), ("bpy.types.mesh.use_customdata_vertex_bevel*", "modeling/meshes/properties/custom_data.html#bpy-types-mesh-use-customdata-vertex-bevel"), ("bpy.types.movietrackingcamera.focal_length*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-focal-length"), @@ -522,6 +593,8 @@ url_manual_mapping = ( ("bpy.types.scenegpencil.antialias_threshold*", "render/cycles/render_settings/grease_pencil.html#bpy-types-scenegpencil-antialias-threshold"), ("bpy.types.spaceclipeditor.show_red_channel*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-show-red-channel"), ("bpy.types.spaceclipeditor.use_mute_footage*", "editors/clip/display/clip_display.html#bpy-types-spaceclipeditor-use-mute-footage"), + ("bpy.types.spacenodeoverlay.show_wire_color*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-wire-color"), + ("bpy.types.spacesequenceeditor.display_mode*", "video_editing/preview/display_mode.html#bpy-types-spacesequenceeditor-display-mode"), ("bpy.types.spacesequenceeditor.overlay_type*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-overlay-type"), ("bpy.types.spaceuveditor.sticky_select_mode*", "editors/uv/selecting.html#bpy-types-spaceuveditor-sticky-select-mode"), ("bpy.types.spaceview3d.show_object_viewport*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-viewport"), @@ -538,9 +611,11 @@ url_manual_mapping = ( ("bpy.ops.outliner.collection_holdout_clear*", "render/layers/introduction.html#bpy-ops-outliner-collection-holdout-clear"), ("bpy.ops.sculpt.face_set_change_visibility*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-set-change-visibility"), ("bpy.ops.sculpt.face_sets_randomize_colors*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-randomize-colors"), + ("bpy.types.animvizmotionpaths.frame_before*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-before"), ("bpy.types.brush.disconnected_distance_max*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-disconnected-distance-max"), ("bpy.types.brush.surface_smooth_iterations*", "sculpt_paint/sculpting/tools/smooth.html#bpy-types-brush-surface-smooth-iterations"), ("bpy.types.brushgpencilsettings.pen_jitter*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-pen-jitter"), + ("bpy.types.brushgpencilsettings.show_lasso*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-show-lasso"), ("bpy.types.cyclescurverendersettings.shape*", "render/cycles/render_settings/hair.html#bpy-types-cyclescurverendersettings-shape"), ("bpy.types.cyclesrendersettings.ao_bounces*", "render/cycles/render_settings/light_paths.html#bpy-types-cyclesrendersettings-ao-bounces"), ("bpy.types.cyclesrendersettings.time_limit*", "render/cycles/render_settings/sampling.html#bpy-types-cyclesrendersettings-time-limit"), @@ -566,6 +641,7 @@ url_manual_mapping = ( ("bpy.types.gpencilsculptsettings.lock_axis*", "grease_pencil/modes/draw/drawing_planes.html#bpy-types-gpencilsculptsettings-lock-axis"), ("bpy.types.imageformatsettings.file_format*", "render/output/properties/output.html#bpy-types-imageformatsettings-file-format"), ("bpy.types.imagepaint.use_backface_culling*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-use-backface-culling"), + ("bpy.types.lineartgpencilmodifier.overscan*", "grease_pencil/modifiers/generate/line_art.html#bpy-types-lineartgpencilmodifier-overscan"), ("bpy.types.linestyle*modifier_curvature_3d*", "render/freestyle/view_layer/line_style/modifiers/color/curvature_3d.html#bpy-types-linestyle-modifier-curvature-3d"), ("bpy.types.materialgpencilstyle.fill_color*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-fill-color"), ("bpy.types.materialgpencilstyle.fill_style*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-fill-style"), @@ -580,10 +656,13 @@ url_manual_mapping = ( ("bpy.types.rendersettings.use_single_layer*", "render/layers/view_layer.html#bpy-types-rendersettings-use-single-layer"), ("bpy.types.sceneeevee.use_taa_reprojection*", "render/eevee/render_settings/sampling.html#bpy-types-sceneeevee-use-taa-reprojection"), ("bpy.types.sequenceeditor.use_overlay_lock*", "video_editing/preview/sidebar.html#bpy-types-sequenceeditor-use-overlay-lock"), + ("bpy.types.spaceclipeditor.cursor_location*", "editors/clip/sidebar.html#bpy-types-spaceclipeditor-cursor-location"), ("bpy.types.spacefilebrowser.recent_folders*", "editors/file_browser.html#bpy-types-spacefilebrowser-recent-folders"), ("bpy.types.spacefilebrowser.system_folders*", "editors/file_browser.html#bpy-types-spacefilebrowser-system-folders"), + ("bpy.types.spacenodeeditor.show_annotation*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeeditor-show-annotation"), ("bpy.types.spaceoutliner.use_filter_object*", "editors/outliner/interface.html#bpy-types-spaceoutliner-use-filter-object"), ("bpy.types.spacesequenceeditor.use_proxies*", "video_editing/preview/sidebar.html#bpy-types-spacesequenceeditor-use-proxies"), + ("bpy.types.spaceuveditor.edge_display_type*", "editors/uv/overlays.html#bpy-types-spaceuveditor-edge-display-type"), ("bpy.types.spaceuveditor.show_pixel_coords*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-show-pixel-coords"), ("bpy.types.spaceview3d.show_reconstruction*", "editors/3dview/display/overlays.html#bpy-types-spaceview3d-show-reconstruction"), ("bpy.types.toolsettings.gpencil_selectmode*", "grease_pencil/selecting.html#bpy-types-toolsettings-gpencil-selectmode"), @@ -593,6 +672,7 @@ url_manual_mapping = ( ("bpy.types.toolsettings.use_snap_translate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-translate"), ("bpy.types.toolsettings.use_uv_select_sync*", "editors/uv/selecting.html#bpy-types-toolsettings-use-uv-select-sync"), ("bpy.types.view3doverlay.wireframe_opacity*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-wireframe-opacity"), + ("bpy.ops.asset.open_containing_blend_file*", "editors/asset_browser.html#bpy-ops-asset-open-containing-blend-file"), ("bpy.ops.gpencil.active_frames_delete_all*", "grease_pencil/animation/tools.html#bpy-ops-gpencil-active-frames-delete-all"), ("bpy.ops.gpencil.stroke_merge_by_distance*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-stroke-merge-by-distance"), ("bpy.ops.node.collapse_hide_unused_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-collapse-hide-unused-toggle"), @@ -601,8 +681,11 @@ url_manual_mapping = ( ("bpy.ops.object.modifier_copy_to_selected*", "modeling/modifiers/introduction.html#bpy-ops-object-modifier-copy-to-selected"), ("bpy.ops.preferences.app_template_install*", "advanced/app_templates.html#bpy-ops-preferences-app-template-install"), ("bpy.types.actionposemarkers.active_index*", "animation/armatures/properties/pose_library.html#bpy-types-actionposemarkers-active-index"), + ("bpy.types.animvizmotionpaths.frame_after*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-after"), + ("bpy.types.animvizmotionpaths.frame_start*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-start"), ("bpy.types.bakesettings.use_pass_indirect*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-indirect"), ("bpy.types.brush.cloth_force_falloff_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-force-falloff-type"), + ("bpy.types.brushgpencilsettings.caps_type*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-caps-type"), ("bpy.types.brushgpencilsettings.fill_leak*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-fill-leak"), ("bpy.types.brushgpencilsettings.show_fill*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-show-fill"), ("bpy.types.brushgpencilsettings.uv_random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-uv-random"), @@ -655,12 +738,15 @@ url_manual_mapping = ( ("bpy.types.shadernodesubsurfacescattering*", "render/shader_nodes/shader/sss.html#bpy-types-shadernodesubsurfacescattering"), ("bpy.types.spaceclipeditor.lock_selection*", "editors/clip/introduction.html#bpy-types-spaceclipeditor-lock-selection"), ("bpy.types.spacedopesheeteditor.auto_snap*", "editors/dope_sheet/editing.html#bpy-types-spacedopesheeteditor-auto-snap"), + ("bpy.types.spacenodeoverlay.show_overlays*", "interface/controls/nodes/introduction.html#bpy-types-spacenodeoverlay-show-overlays"), ("bpy.types.spaceoutliner.show_mode_column*", "editors/outliner/interface.html#bpy-types-spaceoutliner-show-mode-column"), + ("bpy.types.spacesequenceeditor.show_gizmo*", "editors/video_sequencer/preview/display/gizmos.html#bpy-types-spacesequenceeditor-show-gizmo"), ("bpy.types.spacetexteditor.use_match_case*", "editors/text_editor.html#bpy-types-spacetexteditor-use-match-case"), ("bpy.types.spaceview3d.show_object_select*", "editors/3dview/display/visibility.html#bpy-types-spaceview3d-show-object-select"), ("bpy.types.toolsettings.use_lock_relative*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-toolsettings-use-lock-relative"), ("bpy.types.vertexpaint.use_group_restrict*", "sculpt_paint/weight_paint/tool_settings/options.html#bpy-types-vertexpaint-use-group-restrict"), ("bpy.types.volumedisplay.wireframe_detail*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-detail"), + ("bpy.types.windowmanager.asset_path_dummy*", "editors/asset_browser.html#bpy-types-windowmanager-asset-path-dummy"), ("bpy.ops.armature.rigify_add_bone_groups*", "addons/rigging/rigify/metarigs.html#bpy-ops-armature-rigify-add-bone-groups"), ("bpy.ops.object.assign_property_defaults*", "animation/armatures/posing/editing/apply.html#bpy-ops-object-assign-property-defaults"), ("bpy.ops.object.vertex_group_limit_total*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-limit-total"), @@ -669,12 +755,16 @@ url_manual_mapping = ( ("bpy.ops.outliner.collection_hide_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-hide-inside"), ("bpy.ops.outliner.collection_holdout_set*", "render/layers/introduction.html#bpy-ops-outliner-collection-holdout-set"), ("bpy.ops.outliner.collection_show_inside*", "editors/outliner/editing.html#bpy-ops-outliner-collection-show-inside"), + ("bpy.ops.poselib.restore_previous_action*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-restore-previous-action"), ("bpy.ops.preferences.reset_default_theme*", "editors/preferences/themes.html#bpy-ops-preferences-reset-default-theme"), ("bpy.ops.sequencer.strip_transform_clear*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-clear"), ("bpy.ops.spreadsheet.add_row_filter_rule*", "editors/spreadsheet.html#bpy-ops-spreadsheet-add-row-filter-rule"), ("bpy.types.animdata.action_extrapolation*", "editors/nla/sidebar.html#bpy-types-animdata-action-extrapolation"), + ("bpy.types.animvizmotionpaths.frame_step*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-step"), ("bpy.types.bakesettings.max_ray_distance*", "render/cycles/baking.html#bpy-types-bakesettings-max-ray-distance"), ("bpy.types.brush.multiplane_scrape_angle*", "sculpt_paint/sculpting/tools/multiplane_scrape.html#bpy-types-brush-multiplane-scrape-angle"), + ("bpy.types.brushgpencilsettings.hardness*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-hardness"), + ("bpy.types.brushgpencilsettings.use_trim*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-use-trim"), ("bpy.types.clothsettings.internal_spring*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-internal-spring"), ("bpy.types.clothsettings.pressure_factor*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-pressure-factor"), ("bpy.types.colormanagedviewsettings.look*", "render/color_management.html#bpy-types-colormanagedviewsettings-look"), @@ -709,6 +799,7 @@ url_manual_mapping = ( ("bpy.types.layercollection.hide_viewport*", "editors/outliner/interface.html#bpy-types-layercollection-hide-viewport"), ("bpy.types.layercollection.indirect_only*", "editors/outliner/interface.html#bpy-types-layercollection-indirect-only"), ("bpy.types.material.use_sss_translucency*", "render/eevee/materials/settings.html#bpy-types-material-use-sss-translucency"), + ("bpy.types.materiallineart.mat_occlusion*", "render/materials/line_art.html#bpy-types-materiallineart-mat-occlusion"), ("bpy.types.movietrackingcamera.principal*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-principal"), ("bpy.types.object.use_camera_lock_parent*", "scene_layout/object/properties/relations.html#bpy-types-object-use-camera-lock-parent"), ("bpy.types.object.visible_volume_scatter*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-volume-scatter"), @@ -724,6 +815,7 @@ url_manual_mapping = ( ("bpy.types.spacetexteditor.margin_column*", "editors/text_editor.html#bpy-types-spacetexteditor-margin-column"), ("bpy.types.spacetexteditor.use_find_wrap*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-wrap"), ("bpy.types.spaceuveditor.pixel_snap_mode*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-pixel-snap-mode"), + ("bpy.types.spaceuveditor.use_custom_grid*", "editors/uv/sidebar.html#bpy-types-spaceuveditor-use-custom-grid"), ("bpy.types.spaceuveditor.use_live_unwrap*", "modeling/meshes/uv/editing.html#bpy-types-spaceuveditor-use-live-unwrap"), ("bpy.types.toolsettings.double_threshold*", "modeling/meshes/tools/tool_settings.html#bpy-types-toolsettings-double-threshold"), ("bpy.types.toolsettings.lock_object_mode*", "interface/window_system/topbar.html#bpy-types-toolsettings-lock-object-mode"), @@ -738,7 +830,7 @@ url_manual_mapping = ( ("bpy.ops.mesh.vertices_smooth_laplacian*", "modeling/meshes/editing/vertex/laplacian_smooth.html#bpy-ops-mesh-vertices-smooth-laplacian"), ("bpy.ops.object.multires_rebuild_subdiv*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-rebuild-subdiv"), ("bpy.ops.sequencer.select_side_of_frame*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-side-of-frame"), - ("bpy.ops.view3d.blenderkit_set_category*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-set-category"), + ("bpy.types.animvizmotionpaths.frame_end*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-frame-end"), ("bpy.types.armature.rigify_colors_index*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-colors-index"), ("bpy.types.armature.rigify_theme_to_add*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-theme-to-add"), ("bpy.types.bakesettings.use_pass_direct*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-direct"), @@ -785,11 +877,13 @@ url_manual_mapping = ( ("bpy.types.spacepreferences.filter_type*", "editors/preferences/keymap.html#bpy-types-spacepreferences-filter-type"), ("bpy.types.spacetexteditor.replace_text*", "editors/text_editor.html#bpy-types-spacetexteditor-replace-text"), ("bpy.types.spacetexteditor.use_find_all*", "editors/text_editor.html#bpy-types-spacetexteditor-use-find-all"), + ("bpy.types.toolsettings.snap_uv_element*", "editors/uv/controls/snapping.html#bpy-types-toolsettings-snap-uv-element"), ("bpy.types.toolsettings.use_snap_rotate*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-rotate"), ("bpy.types.view3doverlay.display_handle*", "editors/3dview/display/overlays.html#bpy-types-view3doverlay-display-handle"), ("bpy.types.volumedisplay.wireframe_type*", "modeling/volumes/properties.html#bpy-types-volumedisplay-wireframe-type"), ("bpy.ops.anim.channels_editable_toggle*", "editors/graph_editor/channels.html#bpy-ops-anim-channels-editable-toggle"), ("bpy.ops.curve.normals_make_consistent*", "modeling/curves/editing/control_points.html#bpy-ops-curve-normals-make-consistent"), + ("bpy.ops.ed.lib_id_load_custom_preview*", "editors/asset_browser.html#bpy-ops-ed-lib-id-load-custom-preview"), ("bpy.ops.gpencil.frame_clean_duplicate*", "grease_pencil/modes/edit/grease_pencil_menu.html#bpy-ops-gpencil-frame-clean-duplicate"), ("bpy.ops.gpencil.stroke_simplify_fixed*", "grease_pencil/modes/edit/stroke_menu.html#bpy-ops-gpencil-stroke-simplify-fixed"), ("bpy.ops.mesh.faces_select_linked_flat*", "modeling/meshes/selecting/linked.html#bpy-ops-mesh-faces-select-linked-flat"), @@ -803,15 +897,19 @@ url_manual_mapping = ( ("bpy.ops.outliner.collection_duplicate*", "editors/outliner/editing.html#bpy-ops-outliner-collection-duplicate"), ("bpy.ops.pose.select_constraint_target*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-constraint-target"), ("bpy.ops.sequencer.change_effect_input*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-effect-input"), + ("bpy.ops.sequencer.strip_color_tag_set*", "video_editing/sequencer/sidebar/strip.html#bpy-ops-sequencer-strip-color-tag-set"), ("bpy.ops.sequencer.strip_transform_fit*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-strip-transform-fit"), ("bpy.types.armature.rigify_colors_lock*", "addons/rigging/rigify/metarigs.html#bpy-types-armature-rigify-colors-lock"), ("bpy.types.bakesettings.cage_extrusion*", "render/cycles/baking.html#bpy-types-bakesettings-cage-extrusion"), ("bpy.types.bakesettings.use_pass_color*", "render/cycles/baking.html#bpy-types-bakesettings-use-pass-color"), ("bpy.types.brush.boundary_falloff_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-falloff-type"), ("bpy.types.brush.texture_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-texture-overlay-alpha"), + ("bpy.types.brushgpencilsettings.aspect*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-aspect"), + ("bpy.types.brushgpencilsettings.dilate*", "grease_pencil/modes/draw/tools/fill.html#bpy-types-brushgpencilsettings-dilate"), ("bpy.types.brushgpencilsettings.random*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-random"), ("bpy.types.clothsettings.target_volume*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-target-volume"), ("bpy.types.colormanageddisplaysettings*", "render/color_management.html#bpy-types-colormanageddisplaysettings"), + ("bpy.types.colorramp.hue_interpolation*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-hue-interpolation"), ("bpy.types.compositornodebilateralblur*", "compositing/types/filter/bilateral_blur.html#bpy-types-compositornodebilateralblur"), ("bpy.types.compositornodedistancematte*", "compositing/types/matte/distance_key.html#bpy-types-compositornodedistancematte"), ("bpy.types.compositornodesetalpha.mode*", "compositing/types/converter/set_alpha.html#bpy-types-compositornodesetalpha-mode"), @@ -834,6 +932,7 @@ url_manual_mapping = ( ("bpy.types.greasepencil.use_curve_edit*", "grease_pencil/modes/edit/curve_editing.html#bpy-types-greasepencil-use-curve-edit"), ("bpy.types.imagepaint.screen_grab_size*", "sculpt_paint/texture_paint/tool_settings/options.html#bpy-types-imagepaint-screen-grab-size"), ("bpy.types.linestyle*modifier_material*", "render/freestyle/view_layer/line_style/modifiers/color/material.html#bpy-types-linestyle-modifier-material"), + ("bpy.types.motionpath.use_custom_color*", "animation/motion_paths.html#bpy-types-motionpath-use-custom-color"), ("bpy.types.movietrackingcamera.brown_k*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-k"), ("bpy.types.movietrackingcamera.brown_p*", "movie_clip/tracking/clip/sidebar/track/camera.html#bpy-types-movietrackingcamera-brown-p"), ("bpy.types.object.visible_transmission*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-transmission"), @@ -883,8 +982,11 @@ url_manual_mapping = ( ("bpy.types.brush.boundary_deform_type*", "sculpt_paint/sculpting/tools/boundary.html#bpy-types-brush-boundary-deform-type"), ("bpy.types.brush.cursor_overlay_alpha*", "sculpt_paint/brush/cursor.html#bpy-types-brush-cursor-overlay-alpha"), ("bpy.types.brush.normal_radius_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-normal-radius-factor"), + ("bpy.types.brush.smooth_stroke_factor*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke-factor"), + ("bpy.types.brush.smooth_stroke_radius*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke-radius"), ("bpy.types.brush.topology_rake_factor*", "sculpt_paint/sculpting/tool_settings/dyntopo.html#bpy-types-brush-topology-rake-factor"), ("bpy.types.brush.use_pose_ik_anchored*", "sculpt_paint/sculpting/tools/pose.html#bpy-types-brush-use-pose-ik-anchored"), + ("bpy.types.brushgpencilsettings.angle*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brushgpencilsettings-angle"), ("bpy.types.clothsettings.use_pressure*", "physics/cloth/settings/physical_properties.html#bpy-types-clothsettings-use-pressure"), ("bpy.types.compositornodeantialiasing*", "compositing/types/filter/anti_aliasing.html#bpy-types-compositornodeantialiasing"), ("bpy.types.compositornodechannelmatte*", "compositing/types/matte/channel_key.html#bpy-types-compositornodechannelmatte"), @@ -921,6 +1023,7 @@ url_manual_mapping = ( ("bpy.types.spacefilebrowser.bookmarks*", "editors/file_browser.html#bpy-types-spacefilebrowser-bookmarks"), ("bpy.types.spaceoutliner.display_mode*", "editors/outliner/interface.html#bpy-types-spaceoutliner-display-mode"), ("bpy.types.spaceoutliner.filter_state*", "editors/outliner/interface.html#bpy-types-spaceoutliner-filter-state"), + ("bpy.types.spaceuveditor.show_stretch*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-stretch"), ("bpy.types.toolsettings.keyframe_type*", "editors/timeline.html#bpy-types-toolsettings-keyframe-type"), ("bpy.types.toolsettings.snap_elements*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-snap-elements"), ("bpy.types.toolsettings.use_snap_self*", "editors/3dview/controls/snapping.html#bpy-types-toolsettings-use-snap-self"), @@ -942,16 +1045,18 @@ url_manual_mapping = ( ("bpy.ops.object.material_slot_assign*", "render/materials/assignment.html#bpy-ops-object-material-slot-assign"), ("bpy.ops.object.material_slot_select*", "render/materials/assignment.html#bpy-ops-object-material-slot-select"), ("bpy.ops.object.multires_unsubdivide*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-unsubdivide"), + ("bpy.ops.object.paths_update_visible*", "animation/motion_paths.html#bpy-ops-object-paths-update-visible"), ("bpy.ops.object.transforms_to_deltas*", "scene_layout/object/editing/apply.html#bpy-ops-object-transforms-to-deltas"), ("bpy.ops.outliner.collection_disable*", "editors/outliner/editing.html#bpy-ops-outliner-collection-disable"), ("bpy.ops.outliner.collection_isolate*", "editors/outliner/editing.html#bpy-ops-outliner-collection-isolate"), ("bpy.ops.pose.visual_transform_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-visual-transform-apply"), + ("bpy.ops.poselib.convert_old_poselib*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-convert-old-poselib"), ("bpy.ops.render.shutter_curve_preset*", "render/cycles/render_settings/motion_blur.html#bpy-ops-render-shutter-curve-preset"), ("bpy.ops.sequencer.view_ghost_border*", "video_editing/preview/sidebar.html#bpy-ops-sequencer-view-ghost-border"), ("bpy.ops.ui.override_type_set_button*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-override-type-set-button"), - ("bpy.ops.view3d.blenderkit_asset_bar*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-asset-bar"), ("bpy.types.animdata.action_influence*", "editors/nla/sidebar.html#bpy-types-animdata-action-influence"), ("bpy.types.armature.layers_protected*", "animation/armatures/properties/skeleton.html#bpy-types-armature-layers-protected"), + ("bpy.types.assetmetadata.description*", "editors/asset_browser.html#bpy-types-assetmetadata-description"), ("bpy.types.bakesettings.normal_space*", "render/cycles/baking.html#bpy-types-bakesettings-normal-space"), ("bpy.types.brush.crease_pinch_factor*", "sculpt_paint/sculpting/tools/snake_hook.html#bpy-types-brush-crease-pinch-factor"), ("bpy.types.brush.elastic_deform_type*", "sculpt_paint/sculpting/tools/elastic_deform.html#bpy-types-brush-elastic-deform-type"), @@ -960,6 +1065,7 @@ url_manual_mapping = ( ("bpy.types.brush.use_primary_overlay*", "sculpt_paint/brush/cursor.html#bpy-types-brush-use-primary-overlay"), ("bpy.types.brushtextureslot.map_mode*", "sculpt_paint/brush/texture.html#bpy-types-brushtextureslot-map-mode"), ("bpy.types.camera.passepartout_alpha*", "render/cameras.html#bpy-types-camera-passepartout-alpha"), + ("bpy.types.colorrampelement.position*", "interface/controls/templates/color_ramp.html#bpy-types-colorrampelement-position"), ("bpy.types.compositornodechromamatte*", "compositing/types/matte/chroma_key.html#bpy-types-compositornodechromamatte"), ("bpy.types.compositornodedilateerode*", "compositing/types/filter/dilate_erode.html#bpy-types-compositornodedilateerode"), ("bpy.types.compositornodeellipsemask*", "compositing/types/matte/ellipse_mask.html#bpy-types-compositornodeellipsemask"), @@ -988,6 +1094,7 @@ url_manual_mapping = ( ("bpy.types.materialgpencilstyle.flip*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-flip"), ("bpy.types.materialgpencilstyle.mode*", "grease_pencil/materials/properties.html#bpy-types-materialgpencilstyle-mode"), ("bpy.types.modifier.show_in_editmode*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-in-editmode"), + ("bpy.types.motionpath.line_thickness*", "animation/motion_paths.html#bpy-types-motionpath-line-thickness"), ("bpy.types.object.empty_display_size*", "modeling/empties.html#bpy-types-object-empty-display-size"), ("bpy.types.object.empty_display_type*", "modeling/empties.html#bpy-types-object-empty-display-type"), ("bpy.types.regionview3d.use_box_clip*", "editors/3dview/navigate/views.html#bpy-types-regionview3d-use-box-clip"), @@ -1015,6 +1122,7 @@ url_manual_mapping = ( ("bpy.types.volumedisplay.slice_depth*", "modeling/volumes/properties.html#bpy-types-volumedisplay-slice-depth"), ("bpy.types.worldmistsettings.falloff*", "render/cycles/world_settings.html#bpy-types-worldmistsettings-falloff"), ("bpy.ops.clip.lock_selection_toggle*", "editors/clip/introduction.html#bpy-ops-clip-lock-selection-toggle"), + ("bpy.ops.ed.lib_id_generate_preview*", "editors/asset_browser.html#bpy-ops-ed-lib-id-generate-preview"), ("bpy.ops.mesh.customdata_mask_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-mask-clear"), ("bpy.ops.mesh.customdata_skin_clear*", "modeling/meshes/properties/custom_data.html#bpy-ops-mesh-customdata-skin-clear"), ("bpy.ops.mesh.extrude_vertices_move*", "modeling/meshes/editing/vertex/extrude_vertices.html#bpy-ops-mesh-extrude-vertices-move"), @@ -1040,6 +1148,7 @@ url_manual_mapping = ( ("bpy.ops.sequencer.export_subtitles*", "video_editing/preview/introduction.html#bpy-ops-sequencer-export-subtitles"), ("bpy.ops.transform.edge_bevelweight*", "modeling/meshes/editing/edge/edge_data.html#bpy-ops-transform-edge-bevelweight"), ("bpy.ops.wm.previews_batch_generate*", "files/blend/previews.html#bpy-ops-wm-previews-batch-generate"), + ("bpy.types.assetmetadata.active_tag*", "editors/asset_browser.html#bpy-types-assetmetadata-active-tag"), ("bpy.types.bakesettings.cage_object*", "render/cycles/baking.html#bpy-types-bakesettings-cage-object"), ("bpy.types.bone.use_relative_parent*", "animation/armatures/bones/properties/relations.html#bpy-types-bone-use-relative-parent"), ("bpy.types.brush.auto_smooth_factor*", "sculpt_paint/sculpting/tool_settings/brush_settings.html#bpy-types-brush-auto-smooth-factor"), @@ -1092,6 +1201,7 @@ url_manual_mapping = ( ("bpy.types.shadernodeoutputmaterial*", "render/shader_nodes/output/material.html#bpy-types-shadernodeoutputmaterial"), ("bpy.types.shadernodetexenvironment*", "render/shader_nodes/textures/environment.html#bpy-types-shadernodetexenvironment"), ("bpy.types.spacesequenceeditor.show*", "video_editing/preview/introduction.html#bpy-types-spacesequenceeditor-show"), + ("bpy.types.spaceuveditor.show_faces*", "editors/uv/overlays.html#bpy-types-spaceuveditor-show-faces"), ("bpy.types.spaceuveditor.uv_opacity*", "editors/uv/overlays.html#bpy-types-spaceuveditor-uv-opacity"), ("bpy.types.subdividegpencilmodifier*", "grease_pencil/modifiers/generate/subdivide.html#bpy-types-subdividegpencilmodifier"), ("bpy.types.thicknessgpencilmodifier*", "grease_pencil/modifiers/deform/thickness.html#bpy-types-thicknessgpencilmodifier"), @@ -1117,9 +1227,9 @@ url_manual_mapping = ( ("bpy.ops.mesh.vert_connect_concave*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-vert-connect-concave"), ("bpy.ops.object.multires_subdivide*", "modeling/modifiers/generate/multiresolution.html#bpy-ops-object-multires-subdivide"), ("bpy.ops.object.vertex_group_clean*", "sculpt_paint/weight_paint/editing.html#bpy-ops-object-vertex-group-clean"), + ("bpy.ops.poselib.create_pose_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-create-pose-asset"), ("bpy.ops.preferences.theme_install*", "editors/preferences/themes.html#bpy-ops-preferences-theme-install"), ("bpy.ops.render.play-rendered-anim*", "render/output/animation_player.html#bpy-ops-render-play-rendered-anim"), - ("bpy.ops.scene.blenderkit_download*", "addons/3d_view/blenderkit.html#bpy-ops-scene-blenderkit-download"), ("bpy.ops.sculpt.set_pivot_position*", "sculpt_paint/sculpting/editing/sculpt.html#bpy-ops-sculpt-set-pivot-position"), ("bpy.ops.sequencer.image_strip_add*", "video_editing/sequencer/strips/image.html#bpy-ops-sequencer-image-strip-add"), ("bpy.ops.sequencer.movie_strip_add*", "video_editing/sequencer/strips/movie.html#bpy-ops-sequencer-movie-strip-add"), @@ -1127,11 +1237,13 @@ url_manual_mapping = ( ("bpy.ops.sequencer.sound_strip_add*", "video_editing/sequencer/strips/sound.html#bpy-ops-sequencer-sound-strip-add"), ("bpy.ops.ui.remove_override_button*", "files/linked_libraries/library_overrides.html#bpy-ops-ui-remove-override-button"), ("bpy.ops.view3d.view_center_camera*", "editors/3dview/navigate/camera_view.html#bpy-ops-view3d-view-center-camera"), + ("bpy.types.animvizmotionpaths.type*", "animation/motion_paths.html#bpy-types-animvizmotionpaths-type"), ("bpy.types.armaturegpencilmodifier*", "grease_pencil/modifiers/deform/armature.html#bpy-types-armaturegpencilmodifier"), ("bpy.types.brush.cloth_deform_type*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-deform-type"), ("bpy.types.brush.cloth_sim_falloff*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-sim-falloff"), ("bpy.types.brush.slide_deform_type*", "sculpt_paint/sculpting/tools/slide_relax.html#bpy-types-brush-slide-deform-type"), ("bpy.types.camera.show_composition*", "render/cameras.html#bpy-types-camera-show-composition"), + ("bpy.types.colorramp.interpolation*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-interpolation"), ("bpy.types.compositornodealphaover*", "compositing/types/color/alpha_over.html#bpy-types-compositornodealphaover"), ("bpy.types.compositornodebokehblur*", "compositing/types/filter/bokeh_blur.html#bpy-types-compositornodebokehblur"), ("bpy.types.compositornodecomposite*", "compositing/types/output/composite.html#bpy-types-compositornodecomposite"), @@ -1189,7 +1301,7 @@ url_manual_mapping = ( ("bpy.types.rendersettings.fps_base*", "render/output/properties/format.html#bpy-types-rendersettings-fps-base"), ("bpy.types.rigidbodyobject.enabled*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-enabled"), ("bpy.types.sceneeevee.use_overscan*", "render/eevee/render_settings/film.html#bpy-types-sceneeevee-use-overscan"), - ("bpy.types.sequencerpreviewoverlay*", "video_editing/preview/introduction.html#bpy-types-sequencerpreviewoverlay"), + ("bpy.types.sequencerpreviewoverlay*", "editors/video_sequencer/preview/display/overlays.html#bpy-types-sequencerpreviewoverlay"), ("bpy.types.sequencetransform.scale*", "video_editing/sequencer/sidebar/strip.html#bpy-types-sequencetransform-scale"), ("bpy.types.shadernodeeeveespecular*", "render/shader_nodes/shader/specular_bsdf.html#bpy-types-shadernodeeeveespecular"), ("bpy.types.shadernodehuesaturation*", "render/shader_nodes/color/hue_saturation.html#bpy-types-shadernodehuesaturation"), @@ -1237,7 +1349,6 @@ url_manual_mapping = ( ("bpy.ops.sequencer.select_grouped*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-grouped"), ("bpy.ops.sequencer.select_handles*", "video_editing/sequencer/selecting.html#bpy-ops-sequencer-select-handles"), ("bpy.ops.uv.average_islands_scale*", "modeling/meshes/uv/editing.html#bpy-ops-uv-average-islands-scale"), - ("bpy.ops.view3d.blenderkit_search*", "addons/3d_view/blenderkit.html#bpy-ops-view3d-blenderkit-search"), ("bpy.types.armature.axes_position*", "animation/armatures/properties/display.html#bpy-types-armature-axes-position"), ("bpy.types.armature.pose_position*", "animation/armatures/properties/skeleton.html#bpy-types-armature-pose-position"), ("bpy.types.bakesettings.use_clear*", "render/cycles/baking.html#bpy-types-bakesettings-use-clear"), @@ -1250,6 +1361,7 @@ url_manual_mapping = ( ("bpy.types.camerasolverconstraint*", "animation/constraints/motion_tracking/camera_solver.html#bpy-types-camerasolverconstraint"), ("bpy.types.clothcollisionsettings*", "physics/cloth/settings/collisions.html#bpy-types-clothcollisionsettings"), ("bpy.types.collection.hide_select*", "editors/outliner/interface.html#bpy-types-collection-hide-select"), + ("bpy.types.colorrampelement.color*", "interface/controls/templates/color_ramp.html#bpy-types-colorrampelement-color"), ("bpy.types.compositornodecurvergb*", "compositing/types/color/rgb_curves.html#bpy-types-compositornodecurvergb"), ("bpy.types.compositornodecurvevec*", "compositing/types/vector/vector_curves.html#bpy-types-compositornodecurvevec"), ("bpy.types.compositornodedisplace*", "compositing/types/distort/displace.html#bpy-types-compositornodedisplace"), @@ -1290,6 +1402,7 @@ url_manual_mapping = ( ("bpy.types.material.line_priority*", "render/freestyle/material.html#bpy-types-material-line-priority"), ("bpy.types.mesh.auto_smooth_angle*", "modeling/meshes/structure.html#bpy-types-mesh-auto-smooth-angle"), ("bpy.types.modifier.show_viewport*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-viewport"), + ("bpy.types.motionpath.frame_start*", "animation/motion_paths.html#bpy-types-motionpath-frame-start"), ("bpy.types.object.visible_diffuse*", "render/cycles/object_settings/object_data.html#bpy-types-object-visible-diffuse"), ("bpy.types.objectsolverconstraint*", "animation/constraints/motion_tracking/object_solver.html#bpy-types-objectsolverconstraint"), ("bpy.types.opacitygpencilmodifier*", "grease_pencil/modifiers/color/opacity.html#bpy-types-opacitygpencilmodifier"), @@ -1347,6 +1460,8 @@ url_manual_mapping = ( ("bpy.ops.outliner.show_one_level*", "editors/outliner/editing.html#bpy-ops-outliner-show-one-level"), ("bpy.ops.paint.brush_colors_flip*", "sculpt_paint/texture_paint/tool_settings/brush_settings.html#bpy-ops-paint-brush-colors-flip"), ("bpy.ops.paint.weight_from_bones*", "sculpt_paint/weight_paint/editing.html#bpy-ops-paint-weight-from-bones"), + ("bpy.ops.pose.blend_to_neighbour*", "animation/armatures/posing/editing/in_betweens.html#bpy-ops-pose-blend-to-neighbour"), + ("bpy.ops.pose.paths_range_update*", "animation/motion_paths.html#bpy-ops-pose-paths-range-update"), ("bpy.ops.poselib.action_sanitize*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-action-sanitize"), ("bpy.ops.preferences.studiolight*", "editors/preferences/lights.html#bpy-ops-preferences-studiolight"), ("bpy.ops.scene.view_layer_remove*", "render/layers/introduction.html#bpy-ops-scene-view-layer-remove"), @@ -1398,6 +1513,7 @@ url_manual_mapping = ( ("bpy.types.geometrynodetrimcurve*", "modeling/geometry_nodes/curve/trim_curve.html#bpy-types-geometrynodetrimcurve"), ("bpy.types.gpencilsculptsettings*", "grease_pencil/properties/index.html#bpy-types-gpencilsculptsettings"), ("bpy.types.keyframe.handle_right*", "editors/graph_editor/fcurves/properties.html#bpy-types-keyframe-handle-right"), + ("bpy.types.lengthgpencilmodifier*", "grease_pencil/modifiers/generate/length.html#bpy-types-lengthgpencilmodifier"), ("bpy.types.light.cutoff_distance*", "render/eevee/lighting.html#bpy-types-light-cutoff-distance"), ("bpy.types.lockedtrackconstraint*", "animation/constraints/tracking/locked_track.html#bpy-types-lockedtrackconstraint"), ("bpy.types.material.blend_method*", "render/eevee/materials/settings.html#bpy-types-material-blend-method"), @@ -1454,14 +1570,17 @@ url_manual_mapping = ( ("bpy.ops.spreadsheet.toggle_pin*", "editors/spreadsheet.html#bpy-ops-spreadsheet-toggle-pin"), ("bpy.ops.uv.follow_active_quads*", "modeling/meshes/editing/uv.html#bpy-ops-uv-follow-active-quads"), ("bpy.types.arraygpencilmodifier*", "grease_pencil/modifiers/generate/array.html#bpy-types-arraygpencilmodifier"), + ("bpy.types.assetmetadata.author*", "editors/asset_browser.html#bpy-types-assetmetadata-author"), ("bpy.types.bone.envelope_weight*", "animation/armatures/bones/properties/deform.html#bpy-types-bone-envelope-weight"), ("bpy.types.brush.use_persistent*", "sculpt_paint/sculpting/tools/layer.html#bpy-types-brush-use-persistent"), + ("bpy.types.brushgpencilsettings*", "grease_pencil/modes/draw/tools/index.html#bpy-types-brushgpencilsettings"), ("bpy.types.buildgpencilmodifier*", "grease_pencil/modifiers/generate/build.html#bpy-types-buildgpencilmodifier"), ("bpy.types.camera.sensor_height*", "render/cameras.html#bpy-types-camera-sensor-height"), ("bpy.types.colorbalancemodifier*", "video_editing/sequencer/sidebar/modifiers.html#bpy-types-colorbalancemodifier"), ("bpy.types.colorgpencilmodifier*", "grease_pencil/modifiers/color/hue_saturation.html#bpy-types-colorgpencilmodifier"), + ("bpy.types.colorramp.color_mode*", "interface/controls/templates/color_ramp.html#bpy-types-colorramp-color-mode"), ("bpy.types.compositornodefilter*", "compositing/types/filter/filter_node.html#bpy-types-compositornodefilter"), - ("bpy.types.compositornodehuesat*", "compositing/types/color/hue_saturation.html#bpy-types-compositornodehuesat"), + ("bpy.types.compositornodehuesat*", "compositing/types/color/posterize.html#bpy-types-compositornodehuesat"), ("bpy.types.compositornodeidmask*", "compositing/types/converter/id_mask.html#bpy-types-compositornodeidmask"), ("bpy.types.compositornodeinvert*", "compositing/types/color/invert.html#bpy-types-compositornodeinvert"), ("bpy.types.compositornodekeying*", "compositing/types/matte/keying.html#bpy-types-compositornodekeying"), @@ -1479,6 +1598,7 @@ url_manual_mapping = ( ("bpy.types.followpathconstraint*", "animation/constraints/relationship/follow_path.html#bpy-types-followpathconstraint"), ("bpy.types.gaussianblursequence*", "video_editing/sequencer/strips/effects/blur.html#bpy-types-gaussianblursequence"), ("bpy.types.geometrynodeboundbox*", "modeling/geometry_nodes/geometry/bounding_box.html#bpy-types-geometrynodeboundbox"), + ("bpy.types.geometrynodedualmesh*", "modeling/geometry_nodes/mesh/dual_mesh.html#bpy-types-geometrynodedualmesh"), ("bpy.types.geometrynodematerial*", "-1"), ("bpy.types.geometrynodemeshcone*", "modeling/geometry_nodes/mesh_primitives/cone.html#bpy-types-geometrynodemeshcone"), ("bpy.types.geometrynodemeshcube*", "modeling/geometry_nodes/mesh_primitives/cube.html#bpy-types-geometrynodemeshcube"), @@ -1493,8 +1613,10 @@ url_manual_mapping = ( ("bpy.types.mesh.use_auto_smooth*", "modeling/meshes/structure.html#bpy-types-mesh-use-auto-smooth"), ("bpy.types.meshtovolumemodifier*", "modeling/modifiers/generate/mesh_to_volume.html#bpy-types-meshtovolumemodifier"), ("bpy.types.modifier.show_render*", "modeling/modifiers/introduction.html#bpy-types-modifier-show-render"), + ("bpy.types.motionpath.frame_end*", "animation/motion_paths.html#bpy-types-motionpath-frame-end"), ("bpy.types.noisegpencilmodifier*", "grease_pencil/modifiers/deform/noise.html#bpy-types-noisegpencilmodifier"), ("bpy.types.object.hide_viewport*", "scene_layout/object/properties/visibility.html#bpy-types-object-hide-viewport"), + ("bpy.types.object.show_in_front*", "scene_layout/object/properties/display.html#bpy-types-object-show-in-front"), ("bpy.types.posebone.rigify_type*", "addons/rigging/rigify/rig_types/index.html#bpy-types-posebone-rigify-type"), ("bpy.types.preferencesfilepaths*", "editors/preferences/file_paths.html#bpy-types-preferencesfilepaths"), ("bpy.types.rigidbodyobject.mass*", "physics/rigid_body/properties/settings.html#bpy-types-rigidbodyobject-mass"), @@ -1557,10 +1679,11 @@ url_manual_mapping = ( ("bpy.ops.pose.quaternions_flip*", "animation/armatures/posing/editing/flip_quats.html#bpy-ops-pose-quaternions-flip"), ("bpy.ops.pose.select_hierarchy*", "animation/armatures/posing/selecting.html#bpy-ops-pose-select-hierarchy"), ("bpy.ops.pose.transforms_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-transforms-clear"), + ("bpy.ops.poselib.copy_as_asset*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-copy-as-asset"), ("bpy.ops.preferences.copy_prev*", "editors/preferences/introduction.html#bpy-ops-preferences-copy-prev"), ("bpy.ops.preferences.keyconfig*", "editors/preferences/keymap.html#bpy-ops-preferences-keyconfig"), ("bpy.ops.screen.repeat_history*", "interface/undo_redo.html#bpy-ops-screen-repeat-history"), - ("bpy.ops.script.execute_preset*", "interface/controls/templates/list_presets.html#bpy-ops-script-execute-preset"), + ("bpy.ops.script.execute_preset*", "interface/window_system/tabs_panels.html#bpy-ops-script-execute-preset"), ("bpy.ops.sculpt.face_sets_init*", "sculpt_paint/sculpting/editing/face_sets.html#bpy-ops-sculpt-face-sets-init"), ("bpy.ops.sequencer.change_path*", "video_editing/sequencer/editing.html#bpy-ops-sequencer-change-path"), ("bpy.ops.sequencer.refresh_all*", "video_editing/sequencer/navigating.html#bpy-ops-sequencer-refresh-all"), @@ -1577,7 +1700,6 @@ url_manual_mapping = ( ("bpy.types.bakesettings.target*", "render/cycles/baking.html#bpy-types-bakesettings-target"), ("bpy.types.brush.cloth_damping*", "sculpt_paint/sculpting/tools/cloth.html#bpy-types-brush-cloth-damping"), ("bpy.types.brush.icon_filepath*", "sculpt_paint/brush/brush.html#bpy-types-brush-icon-filepath"), - ("bpy.types.brush.smooth_stroke*", "grease_pencil/modes/draw/tools/draw.html#bpy-types-brush-smooth-stroke"), ("bpy.types.brush.tip_roundness*", "sculpt_paint/sculpting/tools/clay_strips.html#bpy-types-brush-tip-roundness"), ("bpy.types.camera.display_size*", "render/cameras.html#bpy-types-camera-display-size"), ("bpy.types.camera.sensor_width*", "render/cameras.html#bpy-types-camera-sensor-width"), @@ -1594,6 +1716,7 @@ url_manual_mapping = ( ("bpy.types.curve.use_fill_caps*", "modeling/curves/properties/geometry.html#bpy-types-curve-use-fill-caps"), ("bpy.types.curve.use_map_taper*", "modeling/curves/properties/geometry.html#bpy-types-curve-use-map-taper"), ("bpy.types.cyclesworldsettings*", "render/cycles/world_settings.html#bpy-types-cyclesworldsettings"), + ("bpy.types.dashgpencilmodifier*", "grease_pencil/modifiers/generate/dash.html#bpy-types-dashgpencilmodifier"), ("bpy.types.fluiddomainsettings*", "physics/fluid/type/domain/index.html#bpy-types-fluiddomainsettings"), ("bpy.types.geometrynodeboolean*", "modeling/geometry_nodes/input/boolean.html#bpy-types-geometrynodeboolean"), ("bpy.types.geometrynodeinputid*", "modeling/geometry_nodes/input/id.html#bpy-types-geometrynodeinputid"), @@ -1643,6 +1766,7 @@ url_manual_mapping = ( ("bpy.ops.armature.bone_layers*", "animation/armatures/bones/editing/change_layers.html#bpy-ops-armature-bone-layers"), ("bpy.ops.armature.select_less*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-less"), ("bpy.ops.armature.select_more*", "animation/armatures/bones/selecting.html#bpy-ops-armature-select-more"), + ("bpy.ops.asset.bundle_install*", "editors/asset_browser.html#bpy-ops-asset-bundle-install"), ("bpy.ops.clip.add_marker_move*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-add-marker-move"), ("bpy.ops.clip.bundles_to_mesh*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-bundles-to-mesh"), ("bpy.ops.clip.detect_features*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-detect-features"), @@ -1673,6 +1797,7 @@ url_manual_mapping = ( ("bpy.ops.object.transfer_mode*", "editors/3dview/modes.html#bpy-ops-object-transfer-mode"), ("bpy.ops.outliner.show_active*", "editors/outliner/editing.html#bpy-ops-outliner-show-active"), ("bpy.ops.paint.add_simple_uvs*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-ops-paint-add-simple-uvs"), + ("bpy.ops.pose.paths_calculate*", "animation/motion_paths.html#bpy-ops-pose-paths-calculate"), ("bpy.ops.pose.rigify_generate*", "addons/rigging/rigify/basics.html#bpy-ops-pose-rigify-generate"), ("bpy.ops.preferences.autoexec*", "editors/preferences/save_load.html#bpy-ops-preferences-autoexec"), ("bpy.ops.scene.view_layer_add*", "render/layers/introduction.html#bpy-ops-scene-view-layer-add"), @@ -1686,11 +1811,11 @@ url_manual_mapping = ( ("bpy.ops.transform.edge_slide*", "modeling/meshes/editing/edge/edge_slide.html#bpy-ops-transform-edge-slide"), ("bpy.ops.transform.vert_slide*", "modeling/meshes/editing/vertex/slide_vertices.html#bpy-ops-transform-vert-slide"), ("bpy.ops.uv.project_from_view*", "modeling/meshes/editing/uv.html#bpy-ops-uv-project-from-view"), - ("bpy.ops.wm.blenderkit_logout*", "addons/3d_view/blenderkit.html#bpy-ops-wm-blenderkit-logout"), ("bpy.ops.wm.memory_statistics*", "advanced/operators.html#bpy-ops-wm-memory-statistics"), ("bpy.ops.wm.recover_auto_save*", "files/blend/open_save.html#bpy-ops-wm-recover-auto-save"), ("bpy.types.adjustmentsequence*", "video_editing/sequencer/strips/adjustment.html#bpy-types-adjustmentsequence"), ("bpy.types.alphaundersequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaundersequence"), + ("bpy.types.animvizmotionpaths*", "animation/motion_paths.html#bpy-types-animvizmotionpaths"), ("bpy.types.armature.show_axes*", "animation/armatures/properties/display.html#bpy-types-armature-show-axes"), ("bpy.types.armatureconstraint*", "animation/constraints/relationship/armature.html#bpy-types-armatureconstraint"), ("bpy.types.compositornodeblur*", "compositing/types/filter/blur_node.html#bpy-types-compositornodeblur"), @@ -1791,6 +1916,7 @@ url_manual_mapping = ( ("bpy.ops.node.preview_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-preview-toggle"), ("bpy.ops.object.origin_clear*", "scene_layout/object/editing/clear.html#bpy-ops-object-origin-clear"), ("bpy.ops.object.parent_clear*", "scene_layout/object/editing/parent.html#bpy-ops-object-parent-clear"), + ("bpy.ops.object.paths_update*", "animation/motion_paths.html#bpy-ops-object-paths-update"), ("bpy.ops.object.shade_smooth*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-smooth"), ("bpy.ops.object.voxel_remesh*", "modeling/meshes/retopology.html#bpy-ops-object-voxel-remesh"), ("bpy.ops.pose.armature_apply*", "animation/armatures/posing/editing/apply.html#bpy-ops-pose-armature-apply"), @@ -1810,7 +1936,6 @@ url_manual_mapping = ( ("bpy.ops.uv.cylinder_project*", "modeling/meshes/editing/uv.html#bpy-ops-uv-cylinder-project"), ("bpy.ops.uv.minimize_stretch*", "modeling/meshes/uv/editing.html#bpy-ops-uv-minimize-stretch"), ("bpy.ops.uv.select_edge_ring*", "editors/uv/selecting.html#bpy-ops-uv-select-edge-ring"), - ("bpy.ops.wm.blenderkit_login*", "addons/3d_view/blenderkit.html#bpy-ops-wm-blenderkit-login"), ("bpy.ops.wm.save_as_mainfile*", "files/blend/open_save.html#bpy-ops-wm-save-as-mainfile"), ("bpy.types.alphaoversequence*", "video_editing/sequencer/strips/effects/alpha_over_under_overdrop.html#bpy-types-alphaoversequence"), ("bpy.types.armatureeditbones*", "animation/armatures/bones/editing/index.html#bpy-types-armatureeditbones"), @@ -1903,6 +2028,7 @@ url_manual_mapping = ( ("bpy.ops.mesh.symmetry_snap*", "modeling/meshes/editing/mesh/snap_symmetry.html#bpy-ops-mesh-symmetry-snap"), ("bpy.ops.node.group_ungroup*", "interface/controls/nodes/groups.html#bpy-ops-node-group-ungroup"), ("bpy.ops.object.gpencil_add*", "grease_pencil/primitives.html#bpy-ops-object-gpencil-add"), + ("bpy.ops.object.paths_clear*", "animation/motion_paths.html#bpy-ops-object-paths-clear"), ("bpy.ops.object.select_less*", "scene_layout/object/selecting.html#bpy-ops-object-select-less"), ("bpy.ops.object.select_more*", "scene_layout/object/selecting.html#bpy-ops-object-select-more"), ("bpy.ops.object.track_clear*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-clear"), @@ -1941,6 +2067,8 @@ url_manual_mapping = ( ("bpy.types.freestylelineset*", "render/freestyle/view_layer/line_set.html#bpy-types-freestylelineset"), ("bpy.types.image.alpha_mode*", "editors/image/image_settings.html#bpy-types-image-alpha-mode"), ("bpy.types.mask.frame_start*", "movie_clip/masking/sidebar.html#bpy-types-mask-frame-start"), + ("bpy.types.motionpath.color*", "animation/motion_paths.html#bpy-types-motionpath-color"), + ("bpy.types.motionpath.lines*", "animation/motion_paths.html#bpy-types-motionpath-lines"), ("bpy.types.multicamsequence*", "video_editing/sequencer/strips/effects/multicam.html#bpy-types-multicamsequence"), ("bpy.types.multiplysequence*", "video_editing/sequencer/strips/effects/multiply.html#bpy-types-multiplysequence"), ("bpy.types.multiresmodifier*", "modeling/modifiers/generate/multiresolution.html#bpy-types-multiresmodifier"), @@ -1984,6 +2112,7 @@ url_manual_mapping = ( ("bpy.ops.armature.separate*", "animation/armatures/bones/editing/separate_bones.html#bpy-ops-armature-separate"), ("bpy.ops.clip.clean_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-clean-tracks"), ("bpy.ops.clip.delete_track*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-delete-track"), + ("bpy.ops.clip.select_lasso*", "movie_clip/tracking/clip/selecting.html#bpy-ops-clip-select-lasso"), ("bpy.ops.clip.solve_camera*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-solve-camera"), ("bpy.ops.constraint.delete*", "animation/constraints/interface/header.html#bpy-ops-constraint-delete"), ("bpy.ops.curve.smooth_tilt*", "modeling/curves/editing/control_points.html#bpy-ops-curve-smooth-tilt"), @@ -1996,6 +2125,7 @@ url_manual_mapping = ( ("bpy.ops.graph.easing_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-easing-type"), ("bpy.ops.graph.handle_type*", "editors/graph_editor/fcurves/editing.html#bpy-ops-graph-handle-type"), ("bpy.ops.mask.parent_clear*", "movie_clip/masking/editing.html#bpy-ops-mask-parent-clear"), + ("bpy.ops.mask.select_lasso*", "movie_clip/masking/selecting.html#bpy-ops-mask-select-lasso"), ("bpy.ops.mesh.bevel.vertex*", "modeling/meshes/editing/vertex/bevel_vertices.html#bpy-ops-mesh-bevel-vertex"), ("bpy.ops.mesh.delete_loose*", "modeling/meshes/editing/mesh/cleanup.html#bpy-ops-mesh-delete-loose"), ("bpy.ops.mesh.face_shading*", "modeling/meshes/editing/face/shading.html#bpy-ops-mesh-face-shading"), @@ -2014,6 +2144,7 @@ url_manual_mapping = ( ("bpy.ops.object.shade_flat*", "scene_layout/object/editing/shading.html#bpy-ops-object-shade-flat"), ("bpy.ops.pose.group_assign*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-assign"), ("bpy.ops.pose.group_select*", "animation/armatures/properties/bone_groups.html#bpy-ops-pose-group-select"), + ("bpy.ops.pose.paths_update*", "animation/motion_paths.html#bpy-ops-pose-paths-update"), ("bpy.ops.poselib.pose_move*", "animation/armatures/properties/pose_library.html#bpy-ops-poselib-pose-move"), ("bpy.ops.preferences.addon*", "editors/preferences/addons.html#bpy-ops-preferences-addon"), ("bpy.ops.scene.light_cache*", "render/eevee/render_settings/indirect_lighting.html#bpy-ops-scene-light-cache"), @@ -2043,6 +2174,7 @@ url_manual_mapping = ( ("bpy.types.fmodifierlimits*", "editors/graph_editor/fcurves/modifiers.html#bpy-types-fmodifierlimits"), ("bpy.types.imagepaint.mode*", "sculpt_paint/texture_paint/tool_settings/texture_slots.html#bpy-types-imagepaint-mode"), ("bpy.types.latticemodifier*", "modeling/modifiers/deform/lattice.html#bpy-types-latticemodifier"), + ("bpy.types.materiallineart*", "render/materials/line_art.html#bpy-types-materiallineart"), ("bpy.types.musgravetexture*", "render/materials/legacy_textures/types/musgrave.html#bpy-types-musgravetexture"), ("bpy.types.object.location*", "scene_layout/object/properties/transforms.html#bpy-types-object-location"), ("bpy.types.object.rotation*", "scene_layout/object/properties/transforms.html#bpy-types-object-rotation"), @@ -2066,6 +2198,7 @@ url_manual_mapping = ( ("bpy.types.subsurfmodifier*", "modeling/modifiers/generate/subdivision_surface.html#bpy-types-subsurfmodifier"), ("bpy.types.texturenodemath*", "editors/texture_node/types/converter/math.html#bpy-types-texturenodemath"), ("bpy.types.volume.filepath*", "modeling/volumes/properties.html#bpy-types-volume-filepath"), + ("bpy.ops.asset.tag_remove*", "editors/asset_browser.html#bpy-ops-asset-tag-remove"), ("bpy.ops.clip.join_tracks*", "movie_clip/tracking/clip/editing/track.html#bpy-ops-clip-join-tracks"), ("bpy.ops.constraint.apply*", "animation/constraints/interface/header.html#bpy-ops-constraint-apply"), ("bpy.ops.curve.select_row*", "modeling/surfaces/selecting.html#bpy-ops-curve-select-row"), @@ -2087,6 +2220,7 @@ url_manual_mapping = ( ("bpy.ops.node.mute_toggle*", "interface/controls/nodes/editing.html#bpy-ops-node-mute-toggle"), ("bpy.ops.object.hide_view*", "scene_layout/object/editing/show_hide.html#bpy-ops-object-hide-view"), ("bpy.ops.object.track_set*", "animation/constraints/interface/adding_removing.html#bpy-ops-object-track-set"), + ("bpy.ops.pose.paths_clear*", "animation/motion_paths.html#bpy-ops-pose-paths-clear"), ("bpy.ops.pose.scale_clear*", "animation/armatures/posing/editing/clear.html#bpy-ops-pose-scale-clear"), ("bpy.ops.poselib.pose_add*", "animation/armatures/posing/editing/pose_library.html#bpy-ops-poselib-pose-add"), ("bpy.ops.scene.view_layer*", "render/layers/introduction.html#bpy-ops-scene-view-layer"), @@ -2191,6 +2325,7 @@ url_manual_mapping = ( ("bpy.types.armature.show*", "animation/armatures/properties/display.html#bpy-types-armature-show"), ("bpy.types.armaturebones*", "animation/armatures/bones/index.html#bpy-types-armaturebones"), ("bpy.types.arraymodifier*", "modeling/modifiers/generate/array.html#bpy-types-arraymodifier"), + ("bpy.types.assetmetadata*", "editors/asset_browser.html#bpy-types-assetmetadata"), ("bpy.types.bevelmodifier*", "modeling/modifiers/generate/bevel.html#bpy-types-bevelmodifier"), ("bpy.types.buildmodifier*", "modeling/modifiers/generate/build.html#bpy-types-buildmodifier"), ("bpy.types.clothmodifier*", "physics/cloth/index.html#bpy-types-clothmodifier"), @@ -2315,6 +2450,7 @@ url_manual_mapping = ( ("bpy.types.weldmodifier*", "modeling/modifiers/generate/weld.html#bpy-types-weldmodifier"), ("bpy.types.wipesequence*", "video_editing/sequencer/strips/transitions/wipe.html#bpy-types-wipesequence"), ("bpy.ops.armature.fill*", "animation/armatures/bones/editing/fill_between_joints.html#bpy-ops-armature-fill"), + ("bpy.ops.asset.tag_add*", "editors/asset_browser.html#bpy-ops-asset-tag-add"), ("bpy.ops.clip.prefetch*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-prefetch"), ("bpy.ops.clip.set_axis*", "movie_clip/tracking/clip/editing/reconstruction.html#bpy-ops-clip-set-axis"), ("bpy.ops.file.pack_all*", "files/blend/packed_data.html#bpy-ops-file-pack-all"), @@ -2399,6 +2535,7 @@ url_manual_mapping = ( ("bpy.types.lightprobe*", "render/eevee/light_probes/index.html#bpy-types-lightprobe"), ("bpy.types.maskparent*", "movie_clip/masking/sidebar.html#bpy-types-maskparent"), ("bpy.types.maskspline*", "movie_clip/masking/sidebar.html#bpy-types-maskspline"), + ("bpy.types.motionpath*", "animation/motion_paths.html#bpy-types-motionpath"), ("bpy.types.node.color*", "interface/controls/nodes/sidebar.html#bpy-types-node-color"), ("bpy.types.node.label*", "interface/controls/nodes/sidebar.html#bpy-types-node-label"), ("bpy.types.nodesocket*", "interface/controls/nodes/parts.html#bpy-types-nodesocket"), @@ -2408,6 +2545,7 @@ url_manual_mapping = ( ("bpy.types.renderview*", "render/output/properties/stereoscopy/index.html#bpy-types-renderview"), ("bpy.types.sceneeevee*", "render/eevee/index.html#bpy-types-sceneeevee"), ("bpy.types.vectorfont*", "modeling/texts/index.html#bpy-types-vectorfont"), + ("bpy.ops.asset.clear*", "files/asset_libraries/introduction.html#bpy-ops-asset-clear"), ("bpy.ops.clip.reload*", "movie_clip/tracking/clip/editing/clip.html#bpy-ops-clip-reload"), ("bpy.ops.curve.split*", "modeling/curves/editing/curve.html#bpy-ops-curve-split"), ("bpy.ops.file.cancel*", "editors/file_browser.html#bpy-ops-file-cancel"), @@ -2427,7 +2565,6 @@ url_manual_mapping = ( ("bpy.ops.uv.rip_move*", "modeling/meshes/uv/tools/rip.html#bpy-ops-uv-rip-move"), ("bpy.ops.view3d.snap*", "scene_layout/object/editing/snap.html#bpy-ops-view3d-snap"), ("bpy.ops.view3d.zoom*", "editors/3dview/navigate/navigation.html#bpy-ops-view3d-zoom"), - ("bpy.ops.wm.url_open*", "addons/3d_view/blenderkit.html#bpy-ops-wm-url-open"), ("bpy.types.*texspace*", "modeling/meshes/uv/uv_texture_spaces.html#bpy-types-texspace"), ("bpy.types.arealight*", "render/lights/light_object.html#bpy-types-arealight"), ("bpy.types.blenddata*", "files/data_blocks.html#bpy-types-blenddata"), @@ -2447,6 +2584,7 @@ url_manual_mapping = ( ("bpy.types.uipiemenu*", "interface/controls/buttons/menus.html#bpy-types-uipiemenu"), ("bpy.types.uipopover*", "interface/controls/buttons/menus.html#bpy-types-uipopover"), ("bpy.types.viewlayer*", "render/layers/introduction.html#bpy-types-viewlayer"), + ("bpy.ops.asset.mark*", "files/asset_libraries/introduction.html#bpy-ops-asset-mark"), ("bpy.ops.collection*", "scene_layout/collections/collections.html#bpy-ops-collection"), ("bpy.ops.constraint*", "animation/constraints/index.html#bpy-ops-constraint"), ("bpy.ops.curve.draw*", "modeling/curves/tools/draw.html#bpy-ops-curve-draw"), @@ -2508,7 +2646,6 @@ url_manual_mapping = ( ("bpy.ops.uv.unwrap*", "modeling/meshes/editing/uv.html#bpy-ops-uv-unwrap"), ("bpy.ops.wm.append*", "files/linked_libraries/link_append.html#bpy-ops-wm-append"), ("bpy.ops.wm.search*", "interface/controls/templates/operator_search.html#bpy-ops-wm-search"), - ("bpy.types.animviz*", "animation/motion_paths.html#bpy-types-animviz"), ("bpy.types.lattice*", "animation/lattice.html#bpy-types-lattice"), ("bpy.types.library*", "files/linked_libraries/index.html#bpy-types-library"), ("bpy.types.speaker*", "render/output/audio/speaker.html#bpy-types-speaker"), diff --git a/release/scripts/startup/bl_operators/presets.py b/release/scripts/startup/bl_operators/presets.py index 514d61e239d..dcf904410dd 100644 --- a/release/scripts/startup/bl_operators/presets.py +++ b/release/scripts/startup/bl_operators/presets.py @@ -649,7 +649,7 @@ class AddPresetGpencilBrush(AddPresetBase, Operator): "settings.uv_random", "settings.pen_jitter", "settings.use_jitter_pressure", - "settings.trim", + "settings.use_trim", ] preset_subdir = "gpencil_brush" diff --git a/release/scripts/startup/bl_operators/sequencer.py b/release/scripts/startup/bl_operators/sequencer.py index 26f1c12d2b8..1a56e77b7b7 100644 --- a/release/scripts/startup/bl_operators/sequencer.py +++ b/release/scripts/startup/bl_operators/sequencer.py @@ -216,11 +216,19 @@ class SequencerFadesAdd(Operator): scene.animation_data.action = action sequences = context.selected_sequences + + if not sequences: + self.report({'ERROR'}, "No sequences selected") + return {'CANCELLED'} + if self.type in {'CURSOR_TO', 'CURSOR_FROM'}: sequences = [ strip for strip in sequences if strip.frame_final_start < scene.frame_current < strip.frame_final_end ] + if not sequences: + self.report({'ERROR'}, "Current frame not within strip framerange") + return {'CANCELLED'} max_duration = min(sequences, key=lambda strip: strip.frame_final_duration).frame_final_duration max_duration = floor(max_duration / 2.0) if self.type == 'IN_OUT' else max_duration diff --git a/release/scripts/startup/bl_ui/properties_constraint.py b/release/scripts/startup/bl_ui/properties_constraint.py index 85381f5ee3c..570a437c213 100644 --- a/release/scripts/startup/bl_ui/properties_constraint.py +++ b/release/scripts/startup/bl_ui/properties_constraint.py @@ -1146,6 +1146,30 @@ class ConstraintButtonsSubPanel: col.prop(con, "frame_start", text="Frame Start") col.prop(con, "frame_end", text="End") + def draw_transform_cache_velocity(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_velocity + ) + + def draw_transform_cache_procedural(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_procedural + ) + + def draw_transform_cache_time(self, context): + self.draw_transform_cache_subpanel( + context, self.layout.template_cache_file_time_settings + ) + + def draw_transform_cache_subpanel(self, context, template_func): + con = self.get_constraint(context) + if con.cache_file is None: + return + + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = True + template_func(con, "cache_file") # Child Of Constraint @@ -1335,7 +1359,7 @@ class BONE_PT_bLockTrackConstraint(BoneConstraintPanel, ConstraintButtonsPanel, self.draw_lock_track(context) -# Disance Limit Constraint +# Distance Limit Constraint class OBJECT_PT_bDistLimitConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel): def draw(self, context): @@ -1534,6 +1558,54 @@ class BONE_PT_bTransformCacheConstraint(BoneConstraintPanel, ConstraintButtonsPa self.draw_transform_cache(context) +class OBJECT_PT_bTransformCacheConstraint_velocity(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Velocity" + + def draw(self, context): + self.draw_transform_cache_velocity(context) + + +class BONE_PT_bTransformCacheConstraint_velocity(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Velocity" + + def draw(self, context): + self.draw_transform_cache_velocity(context) + + +class OBJECT_PT_bTransformCacheConstraint_procedural(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Render Procedural" + + def draw(self, context): + self.draw_transform_cache_procedural(context) + + +class BONE_PT_bTransformCacheConstraint_procedural(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Render Procedural" + + def draw(self, context): + self.draw_transform_cache_procedural(context) + + +class OBJECT_PT_bTransformCacheConstraint_time(ObjectConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "OBJECT_PT_bTransformCacheConstraint" + bl_label = "Time" + + def draw(self, context): + self.draw_transform_cache_time(context) + + +class BONE_PT_bTransformCacheConstraint_time(BoneConstraintPanel, ConstraintButtonsSubPanel, Panel): + bl_parent_id = "BONE_PT_bTransformCacheConstraint" + bl_label = "Time" + + def draw(self, context): + self.draw_transform_cache_time(context) + + # Python Constraint class OBJECT_PT_bPythonConstraint(ObjectConstraintPanel, ConstraintButtonsPanel, Panel): @@ -1620,6 +1692,9 @@ classes = ( OBJECT_PT_bCameraSolverConstraint, OBJECT_PT_bObjectSolverConstraint, OBJECT_PT_bTransformCacheConstraint, + OBJECT_PT_bTransformCacheConstraint_time, + OBJECT_PT_bTransformCacheConstraint_procedural, + OBJECT_PT_bTransformCacheConstraint_velocity, OBJECT_PT_bPythonConstraint, OBJECT_PT_bArmatureConstraint, OBJECT_PT_bArmatureConstraint_bones, @@ -1657,6 +1732,9 @@ classes = ( BONE_PT_bCameraSolverConstraint, BONE_PT_bObjectSolverConstraint, BONE_PT_bTransformCacheConstraint, + BONE_PT_bTransformCacheConstraint_time, + BONE_PT_bTransformCacheConstraint_procedural, + BONE_PT_bTransformCacheConstraint_velocity, BONE_PT_bPythonConstraint, BONE_PT_bArmatureConstraint, BONE_PT_bArmatureConstraint_bones, diff --git a/release/scripts/startup/bl_ui/space_filebrowser.py b/release/scripts/startup/bl_ui/space_filebrowser.py index e33cf8d6cfb..82c5651e5f0 100644 --- a/release/scripts/startup/bl_ui/space_filebrowser.py +++ b/release/scripts/startup/bl_ui/space_filebrowser.py @@ -850,7 +850,7 @@ classes = ( def asset_path_str_get(self): asset_file_handle = bpy.context.asset_file_handle if asset_file_handle is None: - return None + return "" if asset_file_handle.local_id: return "Current File" diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 1562870d64f..3a668f61539 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -298,6 +298,8 @@ class GRAPH_MT_key(Menu): layout.operator("graph.decimate", text="Decimate (Allowed Change)").mode = 'ERROR' layout.operator_context = operator_context + layout.menu("GRAPH_MT_slider", text="Slider Operators") + layout.operator("graph.clean").channels = False layout.operator("graph.clean", text="Clean Channels").channels = True layout.operator("graph.smooth") @@ -337,6 +339,15 @@ class GRAPH_MT_key_snap(Menu): layout.operator("graph.frame_jump", text="Cursor to Selection") layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection") +class GRAPH_MT_slider(Menu): + bl_label = "Slider Operators" + + def draw(self, _context): + layout = self.layout + + layout.operator("graph.breakdown", text="Breakdown") + layout.operator("graph.blend_to_neighbor", text="Blend To Neighbor") + class GRAPH_MT_view_pie(Menu): bl_label = "View" @@ -475,6 +486,7 @@ classes = ( GRAPH_MT_key, GRAPH_MT_key_transform, GRAPH_MT_key_snap, + GRAPH_MT_slider, GRAPH_MT_delete, GRAPH_MT_context_menu, GRAPH_MT_channel_context_menu, diff --git a/release/scripts/startup/bl_ui/space_topbar.py b/release/scripts/startup/bl_ui/space_topbar.py index 518979a5ef3..99abc60db6f 100644 --- a/release/scripts/startup/bl_ui/space_topbar.py +++ b/release/scripts/startup/bl_ui/space_topbar.py @@ -481,6 +481,7 @@ class TOPBAR_MT_file_export(Menu): bl_owner_use_filter = False def draw(self, _context): + self.layout.operator("wm.obj_export", text="Wavefront OBJ (.obj) - New") if bpy.app.build_options.collada: self.layout.operator("wm.collada_export", text="Collada (Default) (.dae)") @@ -588,7 +589,7 @@ class TOPBAR_MT_edit(Menu): layout.separator() - layout.operator("ed.undo_history", text="Undo History...") + layout.menu("TOPBAR_MT_undo_history") layout.separator() diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index 6dbb964e771..e3ae536bc37 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -772,6 +772,17 @@ class USERPREF_PT_viewport_selection(ViewportPanel, CenterAlignMixIn, Panel): layout.prop(system, "use_select_pick_depth") +class USERPREF_PT_viewport_subdivision(ViewportPanel, CenterAlignMixIn, Panel): + bl_label = "Subdivision" + bl_options = {'DEFAULT_CLOSED'} + + def draw_centered(self, context, layout): + prefs = context.preferences + system = prefs.system + + layout.prop(system, "use_gpu_subdivision") + + # ----------------------------------------------------------------------------- # Theme Panels @@ -2342,6 +2353,7 @@ classes = ( USERPREF_PT_viewport_quality, USERPREF_PT_viewport_textures, USERPREF_PT_viewport_selection, + USERPREF_PT_viewport_subdivision, USERPREF_PT_edit_objects, USERPREF_PT_edit_objects_new, diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 01850676519..4d62d7072cb 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -698,6 +698,8 @@ class VIEW3D_PT_tools_weight_gradient(Panel, View3DPaintPanel): @classmethod def poll(cls, context): settings = context.tool_settings.weight_paint + if settings is None: + return False brush = settings.brush return brush is not None diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index c8ddd86a195..6ce11e1eace 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -150,6 +150,7 @@ def mesh_node_items(context): yield NodeItem("GeometryNodeSubdivisionSurface") yield NodeItem("GeometryNodeTriangulate") yield NodeItemCustom(draw=lambda self, layout, context: layout.separator()) + yield NodeItem("GeometryNodeInputMeshEdgeAngle") yield NodeItem("GeometryNodeInputMeshEdgeNeighbors") yield NodeItem("GeometryNodeInputMeshEdgeVertices") yield NodeItem("GeometryNodeInputMeshFaceArea") @@ -753,6 +754,7 @@ geometry_node_categories = [ NodeItem("GeometryNodeImageTexture"), ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ + NodeItem("GeometryNodeAccumulateField"), NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeFloatCurve"), NodeItem("ShaderNodeClamp"), diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 0fff6d27031..932ef234342 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -413,14 +413,6 @@ void DM_calc_loop_tangents(DerivedMesh *dm, const char (*tangent_names)[MAX_NAME], int tangent_names_len); -/* debug only */ -#ifndef NDEBUG -char *DM_debug_info(DerivedMesh *dm); -void DM_debug_print(DerivedMesh *dm); - -bool DM_is_valid(DerivedMesh *dm); -#endif - #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index ea8ee3f93b1..5dd98dbb9a3 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -253,12 +253,28 @@ void BKE_pose_channel_session_uuid_generate(struct bPoseChannel *pchan); */ struct bPoseChannel *BKE_pose_channel_find_name(const struct bPose *pose, const char *name); /** + * Checks if the bone is on a visible armature layer + * + * \return true if on a visible layer, false otherwise. + */ +bool BKE_pose_is_layer_visible(const struct bArmature *arm, const struct bPoseChannel *pchan); +/** * Find the active pose-channel for an object - * (we can't just use pose, as layer info is in armature) * - * \note #Object, not #bPose is used here, as we need layer info from Armature. + * \param check_arm_layer: checks if the bone is on a visible armature layer (this might be skipped + * (e.g. for "Show Active" from the Outliner). + * \return #bPoseChannel if found or NULL. + * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature. + */ +struct bPoseChannel *BKE_pose_channel_active(struct Object *ob, const bool check_arm_layer); +/** + * Find the active pose-channel for an object if it is on a visible armature layer + * (calls #BKE_pose_channel_active with check_arm_layer set to true) + * + * \return #bPoseChannel if found or NULL. + * \note #Object, not #bPose is used here, as we need info (layer/active bone) from Armature. */ -struct bPoseChannel *BKE_pose_channel_active(struct Object *ob); +struct bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob); /** * Use this when detecting the "other selected bone", * when we have multiple armatures in pose mode. diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 6197cb93c95..4733c96543e 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -186,11 +186,6 @@ void BKE_animdata_transfer_by_basepath(struct Main *bmain, struct ID *dstID, struct ListBase *basepaths); -char *BKE_animdata_driver_path_hack(struct bContext *C, - struct PointerRNA *ptr, - struct PropertyRNA *prop, - char *base_path); - /* ************************************* */ /* Batch AnimData API */ diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 2c83bef7517..1e2dcf09b64 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -38,10 +38,6 @@ struct ID; struct ReportList; /* Attribute.domain */ -/** - * \warning Careful when changing existing items. - * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy). - */ typedef enum AttributeDomain { ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index fd30813a506..114d9e1e0d7 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -30,6 +30,39 @@ #include "BLI_float3.hh" #include "BLI_function_ref.hh" +/** + * This file defines classes that help to provide access to attribute data on a #GeometryComponent. + * The API for retrieving attributes is defined in `BKE_geometry_set.hh`, but this comment has some + * general comments about the system. + * + * Attributes are stored in geometry data, though they can also be stored in instances. Their + * storage is often tied to `CustomData`, which is a system to store "layers" of data with specific + * types and names. However, since `CustomData` was added to Blender before attributes were + * conceptualized, it combines the "legacy" style of task-specific attribute types with generic + * types like "Float". The attribute API here only provides access to generic types. + * + * Attributes are retrieved from geometry components by providing an "id" (#AttributeIDRef). This + * is most commonly just an attribute name. The attribute API on geometry components has some more + * advanced capabilities: + * 1. Read-only access: With a `const` geometry component, an attribute on the geometry cannot be + * modified, so the `for_write` and `for_output` versions of the API are not available. This is + * extremely important for writing coherent bug-free code. When an attribute is retrieved with + * write access, via #WriteAttributeLookup or #OutputAttribute, the geometry component must be + * tagged to clear caches that depend on the changed data. + * 2. Domain interpolation: When retrieving an attribute, a domain (#AttributeDomain) can be + * provided. If the attribute is stored on a different domain and conversion is possible, a + * version of the data interpolated to the requested domain will be provided. These conversions + * are implemented in each #GeometryComponent by `attribute_try_adapt_domain_impl`. + * 3. Implicit type conversion: In addition to interpolating domains, attribute types can be + * converted, using the conversions in `BKE_type_conversions.hh`. The #VArray / #GVArray system + * makes it possible to only convert necessary indices on-demand. + * 4. Anonymous attributes: The "id" used to look up an attribute can also be an anonymous + * attribute reference. Currently anonymous attributes are only used in geometry nodes. + * 5. Abstracted storage: Since the data returned from the API is usually a virtual array, + * it doesn't have to be stored contiguously (even though that is generally preferred). This + * allows accessing "legacy" attributes like `material_index`, which is stored in `MPoly`. + */ + namespace blender::bke { /** @@ -181,11 +214,14 @@ struct ReadAttributeLookup { * Used when looking up a "plain attribute" based on a name for reading from it and writing to it. */ struct WriteAttributeLookup { - /* The virtual array that is used to read from and write to the attribute. */ + /** The virtual array that is used to read from and write to the attribute. */ GVMutableArray varray; - /* Domain the attributes lives on in the geometry. */ + /** Domain the attributes lives on in the geometry component. */ AttributeDomain domain; - /* Call this after changing the attribute to invalidate caches that depend on this attribute. */ + /** + * Call this after changing the attribute to invalidate caches that depend on this attribute. + * \note Do not call this after the component the attribute is from has been destructed. + */ std::function<void()> tag_modified_fn; /* Convenience function to check if the attribute has been found. */ @@ -205,6 +241,10 @@ struct WriteAttributeLookup { * VMutableArray_Span in many cases). * - An output attribute can live side by side with an existing attribute with a different domain * or data type. The old attribute will only be overwritten when the #save function is called. + * + * \note The lifetime of an output attribute should not be longer than the the lifetime of the + * geometry component it comes from, since it can keep a reference to the component for use in + * the #save method. */ class OutputAttribute { public: diff --git a/source/blender/blenkernel/BKE_bpath.h b/source/blender/blenkernel/BKE_bpath.h index bae151f6a72..bc9e3f01e96 100644 --- a/source/blender/blenkernel/BKE_bpath.h +++ b/source/blender/blenkernel/BKE_bpath.h @@ -49,6 +49,8 @@ typedef enum eBPathForeachFlag { BKE_BPATH_FOREACH_PATH_SKIP_LINKED = (1 << 1), /** Skip paths when their matching data is packed. */ BKE_BPATH_FOREACH_PATH_SKIP_PACKED = (1 << 2), + /** Resolve tokens within a virtual filepath to a single, concrete, filepath. */ + BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN = (1 << 3), /* Skip weak reference paths. Those paths are typically 'nice to have' extra information, but are * not used as actual source of data by the current .blend file. * diff --git a/source/blender/blenkernel/BKE_collection.h b/source/blender/blenkernel/BKE_collection.h index 46c1fe0d33d..7dfda7b5121 100644 --- a/source/blender/blenkernel/BKE_collection.h +++ b/source/blender/blenkernel/BKE_collection.h @@ -163,7 +163,21 @@ bool BKE_scene_collections_object_remove(struct Main *bmain, struct Scene *scene, struct Object *object, const bool free_us); + +/** + * Check all collections in \a bmain (including embedded ones in scenes) for CollectionObject with + * NULL object pointer, and remove them. + */ void BKE_collections_object_remove_nulls(struct Main *bmain); + +/** + * Check all collections in \a bmain (including embedded ones in scenes) for duplicate + * CollectionObject with a same object pointer within a same object, and remove them. + * + * NOTE: Always keeps the first of the detected duplicates. + */ +void BKE_collections_object_remove_duplicates(struct Main *bmain); + /** * Remove all NULL children from parent collections of changed \a collection. * This is used for library remapping, where these pointers have been set to NULL. diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index ac864c7f82c..f50270ed4e7 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -282,8 +282,9 @@ bool CTX_data_dir(const char *member); ListBase ctx_data_list; \ CollectionPointerLink *ctx_link; \ CTX_data_##member(C, &ctx_data_list); \ - for (ctx_link = ctx_data_list.first; ctx_link; ctx_link = ctx_link->next) { \ - Type instance = ctx_link->ptr.data; + for (ctx_link = (CollectionPointerLink *)ctx_data_list.first; ctx_link; \ + ctx_link = ctx_link->next) { \ + Type instance = (Type)ctx_link->ptr.data; #define CTX_DATA_END \ } \ diff --git a/source/blender/blenkernel/BKE_fcurve_driver.h b/source/blender/blenkernel/BKE_fcurve_driver.h index 18676dfcb38..7e4e0ad3c2a 100644 --- a/source/blender/blenkernel/BKE_fcurve_driver.h +++ b/source/blender/blenkernel/BKE_fcurve_driver.h @@ -105,6 +105,13 @@ void driver_change_variable_type(struct DriverVar *dvar, int type); */ void driver_variable_name_validate(struct DriverVar *dvar); /** + * Ensure the driver variable's name is unique. + * + * Assumes the driver variable has already been assigned to the driver, so that + * the prev/next pointers can be used to find the other variables. + */ +void driver_variable_unique_name(struct DriverVar *dvar); +/** * Add a new driver variable. */ struct DriverVar *driver_add_new_variable(struct ChannelDriver *driver); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 79f29e0954e..88e45baad15 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -93,41 +93,64 @@ class GeometryComponent { GeometryComponentType type() const; - /* Return true when any attribute with this name exists, including built in attributes. */ + /** + * Return true when any attribute with this name exists, including built in attributes. + */ bool attribute_exists(const blender::bke::AttributeIDRef &attribute_id) const; - /* Return the data type and domain of an attribute with the given name if it exists. */ + /** + * Return the data type and domain of an attribute with the given name if it exists. + */ std::optional<AttributeMetaData> attribute_get_meta_data( const blender::bke::AttributeIDRef &attribute_id) const; - /* Returns true when the geometry component supports this attribute domain. */ + /** + * Return true when the geometry component supports this attribute domain. + * \note Conceptually this function is static, the result is always the same for different + * instances of the same geometry component type. + */ bool attribute_domain_supported(const AttributeDomain domain) const; - /* Can only be used with supported domain types. */ + /** + * Return the length of a specific domain, or 0 if the domain is not supported. + */ virtual int attribute_domain_size(const AttributeDomain domain) const; + /** + * Return true if the attribute name corresponds to a built-in attribute with a hardcoded domain + * and data type. + */ bool attribute_is_builtin(const blender::StringRef attribute_name) const; bool attribute_is_builtin(const blender::bke::AttributeIDRef &attribute_id) const; - /* Get read-only access to the highest priority attribute with the given name. - * Returns null if the attribute does not exist. */ + /** + * Get read-only access to an attribute with the given name or id, on the highest priority domain + * if there is a name collision. + * \return null if the attribute does not exist. + */ blender::bke::ReadAttributeLookup attribute_try_get_for_read( const blender::bke::AttributeIDRef &attribute_id) const; - /* Get read and write access to the highest priority attribute with the given name. - * Returns null if the attribute does not exist. */ + /** + * Get read and write access to an attribute with the given name or id, on the highest priority + * domain if there is a name collision. + * \note #WriteAttributeLookup.tag_modified_fn must be called after modifying data. + * \return null if the attribute does not exist + */ blender::bke::WriteAttributeLookup attribute_try_get_for_write( const blender::bke::AttributeIDRef &attribute_id); - /* Get a read-only attribute for the domain based on the given attribute. This can be used to + /** + * Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. - * Returns null if the interpolation is not implemented. */ + * \return null if the interpolation is not implemented. + */ blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); } - + /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray, const AttributeDomain from_domain, @@ -137,17 +160,19 @@ class GeometryComponent { .template typed<T>(); } - /* Returns true when the attribute has been deleted. */ + /** Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id); - /* Returns true when the attribute has been created. */ + /** Returns true when the attribute has been created. */ bool attribute_try_create(const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type, const AttributeInit &initializer); - /* Try to create the builtin attribute with the given name. No data type or domain has to be - * provided, because those are fixed for builtin attributes. */ + /** + * Try to create the builtin attribute with the given name. No data type or domain has to be + * provided, because those are fixed for builtin attributes. + */ bool attribute_try_create_builtin(const blender::StringRef attribute_name, const AttributeInit &initializer); @@ -160,34 +185,41 @@ class GeometryComponent { virtual bool is_empty() const; - /* Get a virtual array to read the data of an attribute on the given domain and data type. - * Returns null when the attribute does not exist or cannot be converted to the requested domain - * and data type. */ + /** + * Get a virtual array that refers to the data of an attribute, interpolated to the given domain + * and converted to the data type. Returns null when the attribute does not exist or cannot be + * interpolated or converted. + */ blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type) const; - /* Get a virtual array to read the data of an attribute on the given domain. The data type is - * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the - * requested domain. */ + /** + * Get a virtual array that refers to the data of an attribute, interpolated to the given domain. + * The data type is left unchanged. Returns null when the attribute does not exist or cannot be + * interpolated. + */ blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const; - /* Get a virtual array to read data of an attribute with the given data type. The domain is - * left unchanged. Returns null when the attribute does not exist or cannot be converted to the - * requested data type. */ + /** + * Get a virtual array that refers to the data of an attribute converted to the given data type. + * The attribute's domain is left unchanged. Returns null when the attribute does not exist or + * cannot be converted. + */ blender::bke::ReadAttributeLookup attribute_try_get_for_read( const blender::bke::AttributeIDRef &attribute_id, const CustomDataType data_type) const; - /* Get a virtual array to read the data of an attribute. If that is not possible, the returned - * virtual array will contain a default value. This never returns null. */ + /** + * Get a virtual array that refers to the data of an attribute, interpolated to the given domain + * and converted to the data type. If that is not possible, the returned virtual array will + * contain a default value. This never returns null. + */ blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type, const void *default_value = nullptr) const; - - /* Should be used instead of the method above when the requested data type is known at compile - * time for better type safety. */ + /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain, @@ -214,16 +246,7 @@ class GeometryComponent { const AttributeDomain domain, const CustomDataType data_type, const void *default_value = nullptr); - - /* Same as attribute_try_get_for_output, but should be used when the original values in the - * attributes are not read, i.e. the attribute is used only for output. Since values are not read - * from this attribute, no default value is necessary. */ - blender::bke::OutputAttribute attribute_try_get_for_output_only( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type); - - /* Statically typed method corresponding to the equally named generic one. */ + /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output( const blender::bke::AttributeIDRef &attribute_id, @@ -235,7 +258,17 @@ class GeometryComponent { return this->attribute_try_get_for_output(attribute_id, domain, data_type, &default_value); } - /* Statically typed method corresponding to the equally named generic one. */ + /** + * Same as #attribute_try_get_for_output, but should be used when the original values in the + * attributes are not read, i.e. the attribute is used only for output. The can be faster because + * it can avoid interpolation and conversion of existing values. Since values are not read from + * this attribute, no default value is necessary. + */ + blender::bke::OutputAttribute attribute_try_get_for_output_only( + const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type); + /* Use instead of the method above when the type is known at compile time for type safety. */ template<typename T> blender::bke::OutputAttribute_Typed<T> attribute_try_get_for_output_only( const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) @@ -339,7 +372,7 @@ struct GeometrySet { */ blender::Vector<const GeometryComponent *> get_components_for_read() const; - void compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const; + bool compute_boundbox_without_instances(blender::float3 *r_min, blender::float3 *r_max) const; friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set); @@ -889,6 +922,12 @@ class InstancesComponent : public GeometryComponent { int instances_amount() const; int references_amount() const; + /** + * Remove the indices that are not contained in the mask input, and remove unused instance + * references afterwards. + */ + void remove_instances(const blender::IndexMask mask); + blender::Span<int> almost_unique_ids() const; blender::bke::CustomDataAttributes &attributes(); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 4db6da4b3ea..0709d05c0d1 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -36,6 +36,7 @@ struct ImageFormatData; struct ImagePool; struct ImageTile; struct ImbFormatOptions; +struct ListBase; struct Main; struct Object; struct RenderResult; @@ -284,6 +285,10 @@ void BKE_image_ensure_viewer_views(const struct RenderData *rd, void BKE_image_user_frame_calc(struct Image *ima, struct ImageUser *iuser, int cfra); int BKE_image_user_frame_get(const struct ImageUser *iuser, int cfra, bool *r_is_in_range); void BKE_image_user_file_path(struct ImageUser *iuser, struct Image *ima, char *path); +void BKE_image_user_file_path_ex(struct ImageUser *iuser, + struct Image *ima, + char *path, + bool resolve_udim); void BKE_image_editors_update_frame(const struct Main *bmain, int cfra); /** @@ -397,6 +402,18 @@ void BKE_image_get_tile_label(struct Image *ima, char *label, int len_label); +/** + * Checks whether the given filepath refers to a UDIM tiled texture. + * If yes, the range from the lowest to the highest tile is returned. + * + * `filepath` may be modified to ensure a UDIM token is present. + * `tiles` may be filled even if the result ultimately is false! + */ +bool BKE_image_get_tile_info(char *filepath, + struct ListBase *tiles, + int *tile_start, + int *tile_range); + struct ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label); bool BKE_image_remove_tile(struct Image *ima, struct ImageTile *tile); void BKE_image_reassign_tile(struct Image *ima, struct ImageTile *tile, int new_tile_number); @@ -411,6 +428,40 @@ bool BKE_image_fill_tile(struct Image *ima, int planes, bool is_float); +typedef enum { + UDIM_TILE_FORMAT_NONE = 0, + UDIM_TILE_FORMAT_UDIM = 1, + UDIM_TILE_FORMAT_UVTILE = 2 +} eUDIM_TILE_FORMAT; + +/** + * Ensures that `filename` contains a UDIM token if we find a supported format pattern. + */ +void BKE_image_ensure_tile_token(char *filename); + +/** + * When provided with an absolute virtual filepath, check to see if at least + * one concrete file exists. + * Note: This function requires directory traversal and may be inefficient in time-critical, + * or iterative, code paths. + */ +bool BKE_image_tile_filepath_exists(const char *filepath); + +/** + * Retrieves the UDIM token format and returns the pattern from the provided `filepath`. + * The returned pattern is typically passed to either `BKE_image_get_tile_number_from_filepath` or + * `BKE_image_set_filepath_from_tile_number`. + */ +char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format); +bool BKE_image_get_tile_number_from_filepath(const char *filepath, + const char *pattern, + eUDIM_TILE_FORMAT tile_format, + int *r_tile_number); +void BKE_image_set_filepath_from_tile_number(char *filepath, + const char *pattern, + eUDIM_TILE_FORMAT tile_format, + int tile_number); + struct ImageTile *BKE_image_get_tile(struct Image *ima, int tile_number); struct ImageTile *BKE_image_get_tile_from_iuser(struct Image *ima, const struct ImageUser *iuser); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index c39583d234a..2ccd317e3e4 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -867,15 +867,12 @@ void BKE_mesh_calc_relative_deform(const struct MPoly *mpoly, bool BKE_mesh_validate(struct Mesh *me, const bool do_verbose, const bool cddata_check_mask); /** * Checks if a Mesh is valid without any modification. This is always verbose. - * - * \see #DM_is_valid to call on derived meshes - * - * \returns is_valid. + * \returns True if the mesh is valid. */ bool BKE_mesh_is_valid(struct Mesh *me); /** * Check all material indices of polygons are valid, invalid ones are set to 0. - * \returns is_valid. + * \returns True if the material indices are valid. */ bool BKE_mesh_validate_material_indices(struct Mesh *me); diff --git a/source/blender/blenkernel/BKE_mesh_wrapper.h b/source/blender/blenkernel/BKE_mesh_wrapper.h index 2fe264fd0f7..12e8fd71503 100644 --- a/source/blender/blenkernel/BKE_mesh_wrapper.h +++ b/source/blender/blenkernel/BKE_mesh_wrapper.h @@ -22,6 +22,7 @@ struct BMEditMesh; struct CustomData_MeshMasks; struct Mesh; +struct Object; #ifdef __cplusplus extern "C" { @@ -51,6 +52,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const struct Mesh *me, int vert_coords_len, const float mat[4][4]); +struct Mesh *BKE_mesh_wrapper_ensure_subdivision(const struct Object *ob, struct Mesh *me); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index a2959556810..56b44994985 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -34,6 +34,7 @@ #include "RNA_types.h" #ifdef __cplusplus +# include "BLI_map.hh" # include "BLI_string_ref.hh" #endif @@ -413,7 +414,6 @@ typedef struct bNodeTreeType { /* calls allowing threaded composite */ void (*localize)(struct bNodeTree *localtree, struct bNodeTree *ntree); - void (*local_sync)(struct bNodeTree *localtree, struct bNodeTree *ntree); void (*local_merge)(struct Main *bmain, struct bNodeTree *localtree, struct bNodeTree *ntree); /* Tree update. Overrides `nodetype->updatetreefunc` ! */ @@ -501,16 +501,13 @@ void ntreeFreeLocalTree(struct bNodeTree *ntree); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); -void ntreeUpdateTree(struct Main *main, struct bNodeTree *ntree); void ntreeUpdateAllNew(struct Main *main); -/** - * \param tree_update_flag: #eNodeTreeUpdate enum. - */ -void ntreeUpdateAllUsers(struct Main *main, struct ID *id, int tree_update_flag); +void ntreeUpdateAllUsers(struct Main *main, struct ID *id); void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist, int *r_deplist_len); +void ntreeUpdateNodeLevels(struct bNodeTree *ntree); /** * XXX: old trees handle output flags automatically based on special output @@ -521,21 +518,12 @@ void ntreeSetOutput(struct bNodeTree *ntree); void ntreeFreeCache(struct bNodeTree *ntree); -bool ntreeNodeExists(const struct bNodeTree *ntree, const struct bNode *testnode); -bool ntreeOutputExists(const struct bNode *node, const struct bNodeSocket *testsock); void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable); /** * Returns localized tree for execution in threads. */ struct bNodeTree *ntreeLocalize(struct bNodeTree *ntree); /** - * Sync local composite with real tree. - * The local tree is supposed to be running, be careful moving previews! - * - * Is called by jobs manager, outside threads, so it doesn't happen during draw. - */ -void ntreeLocalSync(struct bNodeTree *localtree, struct bNodeTree *ntree); -/** * Merge local tree results back, and free local tree. * * We have to assume the editor already changed completely. @@ -700,31 +688,28 @@ void nodeRemoveNode(struct Main *bmain, struct bNode *node, bool do_id_user); -/** - * \param ntree: is the target tree. - * - * \note keep socket list order identical, for copying links. - * \note `unique_name` needs to be true. It's only disabled for speed when doing GPUnodetrees. - */ -struct bNode *BKE_node_copy_ex(struct bNodeTree *ntree, - const struct bNode *node_src, - const int flag, - const bool unique_name); +#ifdef __cplusplus + +namespace blender::bke { /** - * Same as #BKE_node_copy_ex but stores pointers to a new node and its sockets in the source node. - * - * NOTE: DANGER ZONE! - * - * TODO(sergey): Maybe it's better to make BKE_node_copy_ex() return a mapping from old node and - * sockets to new one. + * \note keeps socket list order identical, for copying links. + * \note `unique_name` should usually be true, unless the \a dst_tree is temporary, + * or the names can already be assumed valid. */ -struct bNode *BKE_node_copy_store_new_pointers(struct bNodeTree *ntree, - struct bNode *node_src, - const int flag); -struct bNodeTree *ntreeCopyTree_ex_new_pointers(const struct bNodeTree *ntree, - struct Main *bmain, - const bool do_id_user); +bNode *node_copy_with_mapping(bNodeTree *dst_tree, + const bNode &node_src, + int flag, + bool unique_name, + Map<const bNodeSocket *, bNodeSocket *> &new_socket_map); + +bNode *node_copy(bNodeTree *dst_tree, const bNode &src_node, int flag, bool unique_name); + +} // namespace blender::bke + +#endif + +bNode *BKE_node_copy(bNodeTree *dst_tree, const bNode *src_node, int flag, bool unique_name); /** * Also used via RNA API, so we check for proper input output direction. @@ -833,12 +818,7 @@ void nodeClearActive(struct bNodeTree *ntree); void nodeClearActiveID(struct bNodeTree *ntree, short idtype); struct bNode *nodeGetActiveTexture(struct bNodeTree *ntree); -void nodeUpdate(struct bNodeTree *ntree, struct bNode *node); -bool nodeUpdateID(struct bNodeTree *ntree, struct ID *id); -void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node); - int nodeSocketIsHidden(const struct bNodeSocket *sock); -void ntreeTagUsedSockets(struct bNodeTree *ntree); void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available); @@ -960,28 +940,16 @@ bNodePreview *BKE_node_preview_verify( struct bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create); bNodePreview *BKE_node_preview_copy(struct bNodePreview *preview); void BKE_node_preview_free(struct bNodePreview *preview); -void BKE_node_preview_init_tree(struct bNodeTree *ntree, - int xsize, - int ysize, - bool create_previews); +void BKE_node_preview_init_tree(struct bNodeTree *ntree, int xsize, int ysize); void BKE_node_preview_free_tree(struct bNodeTree *ntree); void BKE_node_preview_remove_unused(struct bNodeTree *ntree); void BKE_node_preview_clear(struct bNodePreview *preview); void BKE_node_preview_clear_tree(struct bNodeTree *ntree); -void BKE_node_preview_sync_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree); void BKE_node_preview_merge_tree(struct bNodeTree *to_ntree, struct bNodeTree *from_ntree, bool remove_old); -/** - * Hack warning! this function is only used for shader previews, - * and since it gets called multiple times per pixel for Z-transparency we only add the color once. - * Preview gets cleared before it starts render though. - */ -void BKE_node_preview_set_pixel( - struct bNodePreview *preview, const float col[4], int x, int y, bool do_manage); - /** \} */ /* -------------------------------------------------------------------- */ @@ -1001,9 +969,11 @@ bool nodeGroupPoll(struct bNodeTree *nodetree, /** * Initialize a new node type struct with default values and callbacks. */ -void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass, short flag); -void node_type_base_custom( - struct bNodeType *ntype, const char *idname, const char *name, short nclass, short flag); +void node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); +void node_type_base_custom(struct bNodeType *ntype, + const char *idname, + const char *name, + short nclass); void node_type_socket_templates(struct bNodeType *ntype, struct bNodeSocketTemplate *inputs, struct bNodeSocketTemplate *outputs); @@ -1170,7 +1140,6 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree, #define SH_NODE_SEPRGB 120 #define SH_NODE_COMBRGB 121 #define SH_NODE_HUE_SAT 122 -#define NODE_DYNAMIC 123 #define SH_NODE_OUTPUT_MATERIAL 124 #define SH_NODE_OUTPUT_WORLD 125 @@ -1739,6 +1708,8 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS 1143 #define GEO_NODE_INPUT_MESH_ISLAND 1144 #define GEO_NODE_INPUT_SCENE_TIME 1145 +#define GEO_NODE_ACCUMULATE_FIELD 1146 +#define GEO_NODE_INPUT_MESH_EDGE_ANGLE 1147 /** \} */ diff --git a/source/blender/blenkernel/BKE_node_tree_update.h b/source/blender/blenkernel/BKE_node_tree_update.h new file mode 100644 index 00000000000..d549eec2247 --- /dev/null +++ b/source/blender/blenkernel/BKE_node_tree_update.h @@ -0,0 +1,110 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bke + */ + +struct bNode; +struct bNodeSocket; +struct bNodeTree; +struct bNodeLink; +struct Main; +struct ID; + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Tag tree as changed without providing any more information about what has changed exactly. + * The update process has to assume that everything may have changed. + * + * Using one of the methods below to tag the tree after changes is preffered when possible. + */ +void BKE_ntree_update_tag_all(struct bNodeTree *ntree); + +/** + * More specialized tag functions that may result in a more efficient update. + */ + +void BKE_ntree_update_tag_node_property(struct bNodeTree *ntree, struct bNode *node); +void BKE_ntree_update_tag_node_new(struct bNodeTree *ntree, struct bNode *node); +void BKE_ntree_update_tag_node_removed(struct bNodeTree *ntree); +void BKE_ntree_update_tag_node_mute(struct bNodeTree *ntree, struct bNode *node); +void BKE_ntree_update_tag_node_internal_link(struct bNodeTree *ntree, struct bNode *node); + +void BKE_ntree_update_tag_socket_property(struct bNodeTree *ntree, struct bNodeSocket *socket); +void BKE_ntree_update_tag_socket_new(struct bNodeTree *ntree, struct bNodeSocket *socket); +void BKE_ntree_update_tag_socket_type(struct bNodeTree *ntree, struct bNodeSocket *socket); +void BKE_ntree_update_tag_socket_availability(struct bNodeTree *ntree, struct bNodeSocket *socket); +void BKE_ntree_update_tag_socket_removed(struct bNodeTree *ntree); + +void BKE_ntree_update_tag_link_changed(struct bNodeTree *ntree); +void BKE_ntree_update_tag_link_removed(struct bNodeTree *ntree); +void BKE_ntree_update_tag_link_added(struct bNodeTree *ntree, struct bNodeLink *link); +void BKE_ntree_update_tag_link_mute(struct bNodeTree *ntree, struct bNodeLink *link); + +/** Used after file loading when run-time data on the tree has not been initialized yet. */ +void BKE_ntree_update_tag_missing_runtime_data(struct bNodeTree *ntree); +/** Used when the interface sockets/values have changed. */ +void BKE_ntree_update_tag_interface(struct bNodeTree *ntree); +/** Used when an id data block changed that might be used by nodes that need to be updated. */ +void BKE_ntree_update_tag_id_changed(struct Main *bmain, struct ID *id); + +typedef struct NodeTreeUpdateExtraParams { + /** + * Data passed into the callbacks. + */ + void *user_data; + + /** + * Called for every tree that has been changed during the update. This can be used to send + * notifiers to trigger redraws or depsgraph updates. + */ + void (*tree_changed_fn)(struct ID *, struct bNodeTree *, void *user_data); + + /** + * Called for every tree whose output value may have changed based on the provided update tags. + * This can be used to tag the depsgraph if necessary. + */ + void (*tree_output_changed_fn)(struct ID *, struct bNodeTree *, void *user_data); +} NodeTreeUpdateExtraParams; + +/** + * Updates #bmain based on changes to node trees. + */ +void BKE_ntree_update_main(struct Main *bmain, struct NodeTreeUpdateExtraParams *params); + +/** + * Same as #BKE_ntree_update_main, but will first only look at the provided tree and only looks + * at #bmain when something relevant for other data-blocks changed. This avoids scanning #bmain in + * many cases. + * + * If #bmain is null, only the provided tree is updated. This should only be used in very rare + * cases because it may result it incorrectly synced data in DNA. + * + * If #tree is null, this is the same as calling #BKE_ntree_update_main. + */ +void BKE_ntree_update_main_tree(struct Main *bmain, + struct bNodeTree *ntree, + struct NodeTreeUpdateExtraParams *params); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index 03565bd3bda..a7d39598e54 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -48,6 +48,7 @@ struct RegionView3D; struct RigidBodyWorld; struct Scene; struct ShaderFxData; +struct SubsurfModifierData; struct View3D; struct ViewLayer; @@ -512,6 +513,7 @@ bool BKE_object_obdata_texspace_get(struct Object *ob, float **r_loc, float **r_size); +struct Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const struct Object *object); /** Get evaluated mesh for given object. */ struct Mesh *BKE_object_get_evaluated_mesh(const struct Object *object); /** @@ -712,6 +714,15 @@ void BKE_object_modifiers_lib_link_common(void *userData, struct ID **idpoin, int cb_flag); +/** + * Return the last subsurf modifier of an object, this does not check whether modifiers on top of + * it are disabled. Return NULL if no such modifier is found. + * + * This does not check if the modifier is enabled as it is assumed that the caller verified that it + * is enabled for its evaluation mode. + */ +struct SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const struct Object *ob); + void BKE_object_replace_data_on_shallow_copy(struct Object *ob, struct ID *new_data); struct PartEff; diff --git a/source/blender/blenkernel/BKE_pointcloud.h b/source/blender/blenkernel/BKE_pointcloud.h index af8a6ed293d..57b0127088c 100644 --- a/source/blender/blenkernel/BKE_pointcloud.h +++ b/source/blender/blenkernel/BKE_pointcloud.h @@ -41,7 +41,7 @@ void *BKE_pointcloud_add_default(struct Main *bmain, const char *name); struct PointCloud *BKE_pointcloud_new_nomain(const int totpoint); struct BoundBox *BKE_pointcloud_boundbox_get(struct Object *ob); -void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]); +bool BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]); void BKE_pointcloud_update_customdata_pointers(struct PointCloud *pointcloud); bool BKE_pointcloud_customdata_required(struct PointCloud *pointcloud, diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 77cf250471f..4792921fec7 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -22,6 +22,8 @@ * \ingroup bke */ +#include "BLI_sys_types.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index fd0682ee8f0..3d8b48e5192 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -465,20 +465,20 @@ void BKE_region_callback_refresh_tag_gizmomap_set(void (*callback)(struct wmGizm */ struct ARegion *BKE_area_find_region_type(const struct ScrArea *area, int type); struct ARegion *BKE_area_find_region_active_win(struct ScrArea *area); -struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, const int regiontype, int x, int y); +struct ARegion *BKE_area_find_region_xy(struct ScrArea *area, + const int regiontype, + const int xy[2]) ATTR_NONNULL(3); /** * \note This is only for screen level regions (typically menus/popups). */ struct ARegion *BKE_screen_find_region_xy(struct bScreen *screen, const int regiontype, - int x, - int y) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); + const int xy[2]) ATTR_WARN_UNUSED_RESULT + ATTR_NONNULL(1, 3); struct ARegion *BKE_screen_find_main_region_at_xy(struct bScreen *screen, const int space_type, - const int x, - const int y); - + const int xy[2]) ATTR_NONNULL(1, 3); /** * \note Ideally we can get the area from the context, * there are a few places however where this isn't practical. @@ -495,9 +495,10 @@ struct ScrArea *BKE_screen_find_big_area(struct bScreen *screen, const short min); struct ScrArea *BKE_screen_area_map_find_area_xy(const struct ScrAreaMap *areamap, const int spacetype, - int x, - int y); -struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, const int spacetype, int x, int y); + const int xy[2]) ATTR_NONNULL(1, 3); +struct ScrArea *BKE_screen_find_area_xy(struct bScreen *screen, + const int spacetype, + const int xy[2]) ATTR_NONNULL(1, 3); void BKE_screen_gizmo_tag_refresh(struct bScreen *screen); diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index ebdc4a0ca0b..3413bdbfa69 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -330,17 +330,6 @@ class BezierSpline final : public Spline { int resolution() const; void set_resolution(const int value); - /** - * \warning Call #reallocate on the spline's attributes after adding all points. - */ - void add_point(const blender::float3 position, - const HandleType handle_type_left, - const blender::float3 handle_position_left, - const HandleType handle_type_right, - const blender::float3 handle_position_right, - const float radius, - const float tilt); - void resize(const int size) final; blender::MutableSpan<blender::float3> positions() final; blender::Span<blender::float3> positions() const final; @@ -567,14 +556,6 @@ class NURBSpline final : public Spline { uint8_t order() const; void set_order(const uint8_t value); - /** - * \warning Call #reallocate on the spline's attributes after adding all points. - */ - void add_point(const blender::float3 position, - const float radius, - const float tilt, - const float weight); - bool check_valid_size_and_order() const; int knots_size() const; @@ -634,11 +615,6 @@ class PolySpline final : public Spline { int size() const final; - /** - * \warning Call #reallocate on the spline's attributes after adding all points. - */ - void add_point(const blender::float3 position, const float radius, const float tilt); - void resize(const int size) final; blender::MutableSpan<blender::float3> positions() final; blender::Span<blender::float3> positions() const final; @@ -710,7 +686,7 @@ struct CurveEval { void translate(const blender::float3 &translation); void transform(const blender::float4x4 &matrix); - void bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const; + bool bounds_min_max(blender::float3 &min, blender::float3 &max, const bool use_evaluated) const; /** * Return the start indices for each of the curve spline's control points, if they were part diff --git a/source/blender/blenkernel/BKE_subdiv.h b/source/blender/blenkernel/BKE_subdiv.h index 2fb27fad30d..169a4337f6a 100644 --- a/source/blender/blenkernel/BKE_subdiv.h +++ b/source/blender/blenkernel/BKE_subdiv.h @@ -188,7 +188,16 @@ typedef struct Subdiv { /* Cached values, are not supposed to be accessed directly. */ struct { /* Indexed by base face index, element indicates total number of ptex - * faces created for preceding base faces. */ + * faces created for preceding base faces. This also stores the final + * ptex offset (the total number of PTex faces) at the end of the array + * so that algorithms can compute the number of ptex faces for a given + * face by computing the delta with the offset for the next face without + * using a separate data structure, e.g.: + * + * const int num_face_ptex_faces = face_ptex_offset[i + 1] - face_ptex_offset[i]; + * + * In total this array has a size of `num base faces + 1`. + */ int *face_ptex_offset; } cache_; } Subdiv; @@ -257,6 +266,9 @@ void BKE_subdiv_displacement_detach(Subdiv *subdiv); /* ============================ TOPOLOGY HELPERS ============================ */ +/* For each element in the array, this stores the total number of ptex faces up to that element, + * with the total number of ptex faces being the last element in the array. The array is of length + * `base face count + 1`. */ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv); /* =========================== PTEX FACES AND GRIDS ========================= */ diff --git a/source/blender/blenkernel/BKE_subdiv_eval.h b/source/blender/blenkernel/BKE_subdiv_eval.h index 0b61e62c89c..177d5f386a8 100644 --- a/source/blender/blenkernel/BKE_subdiv_eval.h +++ b/source/blender/blenkernel/BKE_subdiv_eval.h @@ -31,15 +31,25 @@ extern "C" { struct Mesh; struct Subdiv; +struct OpenSubdiv_EvaluatorCache; + +typedef enum eSubdivEvaluatorType { + SUBDIV_EVALUATOR_TYPE_CPU, + SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, +} eSubdivEvaluatorType; /* Returns true if evaluator is ready for use. */ -bool BKE_subdiv_eval_begin(struct Subdiv *subdiv); +bool BKE_subdiv_eval_begin(struct Subdiv *subdiv, + eSubdivEvaluatorType evaluator_type, + struct OpenSubdiv_EvaluatorCache *evaluator_cache); /* coarse_vertex_cos is an optional argument which allows to override coordinates of the coarse * mesh. */ bool BKE_subdiv_eval_begin_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh, - const float (*coarse_vertex_cos)[3]); + const float (*coarse_vertex_cos)[3], + eSubdivEvaluatorType evaluator_type, + struct OpenSubdiv_EvaluatorCache *evaluator_cache); bool BKE_subdiv_eval_refine_from_mesh(struct Subdiv *subdiv, const struct Mesh *mesh, const float (*coarse_vertex_cos)[3]); diff --git a/source/blender/blenkernel/BKE_subdiv_foreach.h b/source/blender/blenkernel/BKE_subdiv_foreach.h index 3f74299455d..f63e23917ef 100644 --- a/source/blender/blenkernel/BKE_subdiv_foreach.h +++ b/source/blender/blenkernel/BKE_subdiv_foreach.h @@ -38,7 +38,8 @@ typedef bool (*SubdivForeachTopologyInformationCb)(const struct SubdivForeachCon const int num_vertices, const int num_edges, const int num_loops, - const int num_polygons); + const int num_polygons, + const int *subdiv_polygon_offset); typedef void (*SubdivForeachVertexFromCornerCb)(const struct SubdivForeachContext *context, void *tls, diff --git a/source/blender/blenkernel/BKE_subdiv_modifier.h b/source/blender/blenkernel/BKE_subdiv_modifier.h new file mode 100644 index 00000000000..94068613101 --- /dev/null +++ b/source/blender/blenkernel/BKE_subdiv_modifier.h @@ -0,0 +1,71 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup bke + */ + +#pragma once + +#include "BLI_sys_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct Mesh; +struct Object; +struct Scene; +struct Subdiv; +struct SubdivSettings; +struct SubsurfModifierData; + +void BKE_subsurf_modifier_subdiv_settings_init(struct SubdivSettings *settings, + const struct SubsurfModifierData *smd, + const bool use_render_params); + +/* If skip_check_is_last is true, we assume that the modifier passed is the last enabled modifier + * in the stack. */ +bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const struct Scene *scene, + const struct Object *ob, + const struct SubsurfModifierData *smd, + int required_mode, + bool skip_check_is_last); + +bool BKE_subsurf_modifier_can_do_gpu_subdiv(const struct Scene *scene, + const struct Object *ob, + const int required_mode); + +extern void (*BKE_subsurf_modifier_free_gpu_cache_cb)(struct Subdiv *subdiv); + +struct Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure( + const struct SubsurfModifierData *smd, + const struct SubdivSettings *subdiv_settings, + const struct Mesh *mesh, + const bool for_draw_code); + +struct SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(struct SubsurfModifierData *smd); + +/* Return the #ModifierMode required for the evaluation of the subsurf modifier, which should be + * used to check if the modifier is enabled. */ +int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_undo_system.h b/source/blender/blenkernel/BKE_undo_system.h index 6e1f9468ce4..44893a6f030 100644 --- a/source/blender/blenkernel/BKE_undo_system.h +++ b/source/blender/blenkernel/BKE_undo_system.h @@ -91,7 +91,7 @@ typedef struct UndoStep { /** When this is true, undo/memfile read code is allowed to re-use old data-blocks for unchanged * IDs, and existing depsgraphes. This has to be forbidden in some cases (like renamed IDs). */ bool use_old_bmain_data; - /** For use by undo systems that accumulate changes (text editor, painting). */ + /** For use by undo systems that accumulate changes (mesh-sculpt & image-painting). */ bool is_applied; /* Over alloc 'type->struct_size'. */ } UndoStep; diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index f6e7f1c2473..3c780a933d3 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -126,7 +126,7 @@ set(SRC intern/curve_eval.cc intern/curve_to_mesh_convert.cc intern/curveprofile.cc - intern/customdata.c + intern/customdata.cc intern/customdata_file.c intern/data_transfer.c intern/deform.c @@ -156,7 +156,7 @@ set(SRC intern/gpencil_curve.c intern/gpencil_geom.cc intern/gpencil_modifier.c - intern/hair.c + intern/hair.cc intern/icons.cc intern/icons_rasterize.c intern/idprop.c @@ -226,6 +226,7 @@ set(SRC intern/multires_versioning.c intern/nla.c intern/node.cc + intern/node_tree_update.cc intern/type_conversions.cc intern/object.cc intern/object_deform.c @@ -274,6 +275,7 @@ set(SRC intern/subdiv_eval.c intern/subdiv_foreach.c intern/subdiv_mesh.c + intern/subdiv_modifier.c intern/subdiv_stats.c intern/subdiv_topology.c intern/subsurf_ccg.c @@ -420,6 +422,7 @@ set(SRC BKE_multires.h BKE_nla.h BKE_node.h + BKE_node_tree_update.h BKE_object.h BKE_object_deform.h BKE_object_facemap.h @@ -451,6 +454,7 @@ set(SRC BKE_subdiv_eval.h BKE_subdiv_foreach.h BKE_subdiv_mesh.h + BKE_subdiv_modifier.h BKE_subdiv_topology.h BKE_subsurf.h BKE_text.h diff --git a/source/blender/blenkernel/intern/DerivedMesh.cc b/source/blender/blenkernel/intern/DerivedMesh.cc index 6c9c5490ca0..4bfd71ba932 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.cc +++ b/source/blender/blenkernel/intern/DerivedMesh.cc @@ -2311,145 +2311,3 @@ static void mesh_init_origspace(Mesh *mesh) BKE_mesh_tessface_clear(mesh); } - -/* derivedmesh info printing function, - * to help track down differences DM output */ - -#ifndef NDEBUG -# include "BLI_dynstr.h" - -static void dm_debug_info_layers(DynStr *dynstr, - DerivedMesh *dm, - CustomData *cd, - void *(*getElemDataArray)(DerivedMesh *, int)) -{ - int type; - - for (type = 0; type < CD_NUMTYPES; type++) { - if (CustomData_has_layer(cd, type)) { - /* NOTE: doesn't account for multiple layers. */ - const char *name = CustomData_layertype_name(type); - const int size = CustomData_sizeof(type); - const void *pt = getElemDataArray(dm, type); - const int pt_size = pt ? (int)(MEM_allocN_len(pt) / size) : 0; - const char *structname; - int structnum; - CustomData_file_write_info(type, &structname, &structnum); - BLI_dynstr_appendf( - dynstr, - " dict(name='%s', struct='%s', type=%d, ptr='%p', elem=%d, length=%d),\n", - name, - structname, - type, - (const void *)pt, - size, - pt_size); - } - } -} - -char *DM_debug_info(DerivedMesh *dm) -{ - DynStr *dynstr = BLI_dynstr_new(); - char *ret; - const char *tstr; - - BLI_dynstr_append(dynstr, "{\n"); - BLI_dynstr_appendf(dynstr, " 'ptr': '%p',\n", (void *)dm); - switch (dm->type) { - case DM_TYPE_CDDM: - tstr = "DM_TYPE_CDDM"; - break; - case DM_TYPE_CCGDM: - tstr = "DM_TYPE_CCGDM"; - break; - default: - tstr = "UNKNOWN"; - break; - } - BLI_dynstr_appendf(dynstr, " 'type': '%s',\n", tstr); - BLI_dynstr_appendf(dynstr, " 'numVertData': %d,\n", dm->numVertData); - BLI_dynstr_appendf(dynstr, " 'numEdgeData': %d,\n", dm->numEdgeData); - BLI_dynstr_appendf(dynstr, " 'numTessFaceData': %d,\n", dm->numTessFaceData); - BLI_dynstr_appendf(dynstr, " 'numPolyData': %d,\n", dm->numPolyData); - BLI_dynstr_appendf(dynstr, " 'deformedOnly': %d,\n", dm->deformedOnly); - - BLI_dynstr_append(dynstr, " 'vertexLayers': (\n"); - dm_debug_info_layers(dynstr, dm, &dm->vertData, dm->getVertDataArray); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'edgeLayers': (\n"); - dm_debug_info_layers(dynstr, dm, &dm->edgeData, dm->getEdgeDataArray); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'loopLayers': (\n"); - dm_debug_info_layers(dynstr, dm, &dm->loopData, dm->getLoopDataArray); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'polyLayers': (\n"); - dm_debug_info_layers(dynstr, dm, &dm->polyData, dm->getPolyDataArray); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, " 'tessFaceLayers': (\n"); - dm_debug_info_layers(dynstr, dm, &dm->faceData, dm->getTessFaceDataArray); - BLI_dynstr_append(dynstr, " ),\n"); - - BLI_dynstr_append(dynstr, "}\n"); - - ret = BLI_dynstr_get_cstring(dynstr); - BLI_dynstr_free(dynstr); - return ret; -} - -void DM_debug_print(DerivedMesh *dm) -{ - char *str = DM_debug_info(dm); - puts(str); - fflush(stdout); - MEM_freeN(str); -} - -bool DM_is_valid(DerivedMesh *dm) -{ - const bool do_verbose = true; - const bool do_fixes = false; - - bool is_valid = true; - bool changed = true; - - is_valid &= BKE_mesh_validate_all_customdata( - dm->getVertDataLayout(dm), - dm->getNumVerts(dm), - dm->getEdgeDataLayout(dm), - dm->getNumEdges(dm), - dm->getLoopDataLayout(dm), - dm->getNumLoops(dm), - dm->getPolyDataLayout(dm), - dm->getNumPolys(dm), - false, /* setting mask here isn't useful, gives false positives */ - do_verbose, - do_fixes, - &changed); - - is_valid &= BKE_mesh_validate_arrays(nullptr, - dm->getVertArray(dm), - dm->getNumVerts(dm), - dm->getEdgeArray(dm), - dm->getNumEdges(dm), - dm->getTessFaceArray(dm), - dm->getNumTessFaces(dm), - dm->getLoopArray(dm), - dm->getNumLoops(dm), - dm->getPolyArray(dm), - dm->getNumPolys(dm), - (MDeformVert *)dm->getVertDataArray(dm, CD_MDEFORMVERT), - do_verbose, - do_fixes, - &changed); - - BLI_assert(changed == false); - - return is_valid; -} - -#endif /* NDEBUG */ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index ddba726ba83..764c043f5ed 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -705,7 +705,12 @@ bool BKE_pose_channels_is_valid(const bPose *pose) #endif -bPoseChannel *BKE_pose_channel_active(Object *ob) +bool BKE_pose_is_layer_visible(const bArmature *arm, const bPoseChannel *pchan) +{ + return (pchan->bone->layer & arm->layer); +} + +bPoseChannel *BKE_pose_channel_active(Object *ob, const bool check_arm_layer) { bArmature *arm = (ob) ? ob->data : NULL; bPoseChannel *pchan; @@ -716,14 +721,21 @@ bPoseChannel *BKE_pose_channel_active(Object *ob) /* find active */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if ((pchan->bone) && (pchan->bone == arm->act_bone) && (pchan->bone->layer & arm->layer)) { - return pchan; + if ((pchan->bone) && (pchan->bone == arm->act_bone)) { + if (!check_arm_layer || BKE_pose_is_layer_visible(arm, pchan)) { + return pchan; + } } } return NULL; } +bPoseChannel *BKE_pose_channel_active_if_layer_visible(struct Object *ob) +{ + return BKE_pose_channel_active(ob, true); +} + bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob) { bArmature *arm = (ob) ? ob->data : NULL; @@ -732,7 +744,7 @@ bPoseChannel *BKE_pose_channel_active_or_first_selected(struct Object *ob) return NULL; } - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && (pchan->bone->flag & BONE_SELECTED) && PBONE_VISIBLE(arm, pchan->bone)) { return pchan; } diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index d93d5c456d8..42b72a7cd66 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -676,41 +676,6 @@ void BKE_animdata_transfer_by_basepath(Main *bmain, ID *srcID, ID *dstID, ListBa } } -char *BKE_animdata_driver_path_hack(bContext *C, - PointerRNA *ptr, - PropertyRNA *prop, - char *base_path) -{ - ID *id = ptr->owner_id; - ScrArea *area = CTX_wm_area(C); - - /* get standard path which may be extended */ - char *basepath = base_path ? base_path : RNA_path_from_ID_to_property(ptr, prop); - char *path = basepath; /* in case no remapping is needed */ - - /* Remapping will only be performed in the Properties Editor, as only this - * restricts the subspace of options to the 'active' data (a manageable state) - */ - /* TODO: watch out for pinned context? */ - if ((area) && (area->spacetype == SPACE_PROPERTIES)) { - Object *ob = CTX_data_active_object(C); - - if (ob && id) { - /* TODO: after material textures were removed, this function serves - * no purpose anymore, but could be used again so was not removed. */ - - /* fix RNA pointer, as we've now changed the ID root by changing the paths */ - if (basepath != path) { - /* rebase provided pointer so that it starts from object... */ - RNA_pointer_create(&ob->id, ptr->type, ptr->data, ptr); - } - } - } - - /* the path should now have been corrected for use */ - return path; -} - /* Path Validation -------------------------------------------- */ /* Check if a given RNA Path is valid, by tracing it from the given ID, diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index aec622bb71f..eee1f6287c3 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -24,7 +24,7 @@ #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" -#include "BLI_fileops.h" +#include "BLI_fileops.hh" #include "BLI_path_util.h" /* For S_ISREG() and S_ISDIR() on Windows. */ @@ -32,6 +32,10 @@ # include "BLI_winstuff.h" #endif +#include "CLG_log.h" + +static CLG_LogRef LOG = {"bke.asset_service"}; + namespace blender::bke { const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt"; @@ -311,6 +315,7 @@ void AssetCatalogService::load_from_disk(const CatalogFilePath &file_or_director BLI_stat_t status; if (BLI_stat(file_or_directory_path.data(), &status) == -1) { /* TODO(@sybren): throw an appropriate exception. */ + CLOG_WARN(&LOG, "path not found: %s", file_or_directory_path.data()); return; } @@ -337,6 +342,7 @@ void AssetCatalogService::load_directory_recursive(const CatalogFilePath &direct if (!BLI_exists(file_path.data())) { /* No file to be loaded is perfectly fine. */ + CLOG_INFO(&LOG, 2, "path not found: %s", file_path.data()); return; } @@ -824,8 +830,12 @@ void AssetCatalogDefinitionFile::parse_catalog_file( const CatalogFilePath &catalog_definition_file_path, AssetCatalogParsedFn catalog_loaded_callback) { - std::fstream infile(catalog_definition_file_path); + fstream infile(catalog_definition_file_path, std::ios::in); + if (!infile.is_open()) { + CLOG_ERROR(&LOG, "%s: unable to open file", catalog_definition_file_path.c_str()); + return; + } bool seen_version_number = false; std::string line; while (std::getline(infile, line)) { @@ -956,7 +966,7 @@ bool AssetCatalogDefinitionFile::write_to_disk_unsafe(const CatalogFilePath &des return false; } - std::ofstream output(dest_file_path); + fstream output(dest_file_path, std::ios::out); /* TODO(@sybren): remember the line ending style that was originally read, then use that to write * the file again. */ diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index ba8f8716823..3ff7831b19a 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -27,6 +27,8 @@ #include "DNA_asset_types.h" #include "DNA_userdef_types.h" +#include "CLG_log.h" + #include "testing/testing.h" namespace blender::bke::tests { @@ -93,6 +95,18 @@ class AssetCatalogTest : public testing::Test { CatalogFilePath asset_library_root_; CatalogFilePath temp_library_path_; + static void SetUpTestSuite() + { + testing::Test::SetUpTestSuite(); + CLG_init(); + } + + static void TearDownTestSuite() + { + CLG_exit(); + testing::Test::TearDownTestSuite(); + } + void SetUp() override { const std::string test_files_dir = blender::tests::flags_test_asset_dir(); @@ -549,6 +563,30 @@ TEST_F(AssetCatalogTest, write_single_file) /* TODO(@sybren): test ordering of catalogs in the file. */ } +TEST_F(AssetCatalogTest, read_write_unicode_filepath) +{ + TestableAssetCatalogService service(asset_library_root_); + const CatalogFilePath load_from_path = asset_library_root_ + "/новый/" + + AssetCatalogService::DEFAULT_CATALOG_FILENAME; + service.load_from_disk(load_from_path); + + const CatalogFilePath save_to_path = use_temp_path() + "новый.cats.txt"; + AssetCatalogDefinitionFile *cdf = service.get_catalog_definition_file(); + ASSERT_NE(nullptr, cdf) << "unable to load " << load_from_path; + EXPECT_TRUE(cdf->write_to_disk(save_to_path)); + + AssetCatalogService loaded_service(save_to_path); + loaded_service.load_from_disk(); + + /* Test that the file was loaded correctly. */ + const bUUID materials_uuid("a2151dff-dead-4f29-b6bc-b2c7d6cccdb4"); + const AssetCatalog *cat = loaded_service.find_catalog(materials_uuid); + ASSERT_NE(nullptr, cat); + EXPECT_EQ(materials_uuid, cat->catalog_id); + EXPECT_EQ(AssetCatalogPath("Материалы"), cat->path); + EXPECT_EQ("Russian Materials", cat->simple_name); +} + TEST_F(AssetCatalogTest, no_writing_empty_files) { const CatalogFilePath temp_lib_root = create_temp_path(); diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c index c265a6e2b7d..23e9e6bfbbb 100644 --- a/source/blender/blenkernel/intern/blendfile_link_append.c +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -440,6 +440,16 @@ static bool object_in_any_collection(Main *bmain, Object *ob) return false; } +static bool collection_instantiated_by_any_object(Main *bmain, Collection *collection) +{ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_EMPTY && ob->instance_collection == collection) { + return true; + } + } + return false; +} + static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context, BlendfileLinkAppendContextItem *item) { @@ -633,12 +643,19 @@ static void loose_data_instantiate_collection_process( * children. */ Collection *collection = (Collection *)id; + /* The collection could be linked/appended together with an Empty object instantiating it, + * better not instantiate the collection in the viewlayer in that case. + * + * Can easily happen when copy/pasting such instantiating empty, see T93839. */ + const bool collection_is_instantiated = collection_instantiated_by_any_object(bmain, + collection); /* Always consider adding collections directly selected by the user. */ - bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0; + bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0 && + !collection_is_instantiated; /* In linking case, do not enforce instantiating non-directly linked collections/objects. * This avoids cluttering the ViewLayers, user can instantiate themselves specific collections * or objects easily from the Outliner if needed. */ - if (!do_add_collection && do_append) { + if (!do_add_collection && do_append && !collection_is_instantiated) { LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { Object *ob = coll_ob->ob; if (!object_in_any_scene(bmain, ob)) { @@ -726,6 +743,8 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i * if you want it do it at the editor level. */ const bool object_set_active = false; + const bool is_linking = (lapp_context->params->flag & FILE_LINK) != 0; + /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used * anywhere. */ LinkNode *itemlink; @@ -736,6 +755,17 @@ static void loose_data_instantiate_object_process(LooseDataInstantiateContext *i continue; } + /* In linking case, never instantiate stray objects that are not directly linked. + * + * While this is not ideal (in theory no object should remain un-owned), in case of indirectly + * linked objects, the other solution would be to add them to a local collection, which would + * make them directly linked. Think for now keeping them indirectly linked is more important. + * Ref. T93757. + */ + if (is_linking && (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) { + continue; + } + Object *ob = (Object *)id; if (object_in_any_collection(bmain, ob)) { diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 85e49774dfd..44ef3ec96ff 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -236,7 +236,8 @@ void BKE_bpath_missing_files_check(Main *bmain, ReportList *reports) BKE_bpath_foreach_path_main(&(BPathForeachPathData){ .bmain = bmain, .callback_function = check_missing_files_foreach_path_cb, - .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED, + .flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_SKIP_PACKED | + BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN, .user_data = reports}); } @@ -384,7 +385,8 @@ void BKE_bpath_missing_files_find(Main *bmain, const bool find_all) { struct BPathFind_Data data = {NULL}; - const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED; + const int flag = BKE_BPATH_FOREACH_PATH_ABSOLUTE | BKE_BPATH_FOREACH_PATH_RELOAD_EDITED | + BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN; data.basedir = BKE_main_blendfile_path(bmain); data.reports = reports; diff --git a/source/blender/blenkernel/intern/bvhutils.cc b/source/blender/blenkernel/intern/bvhutils.cc index a68119fbc1d..09a01d209df 100644 --- a/source/blender/blenkernel/intern/bvhutils.cc +++ b/source/blender/blenkernel/intern/bvhutils.cc @@ -127,7 +127,7 @@ bool bvhcache_has_tree(const BVHCache *bvh_cache, const BVHTree *tree) BVHCache *bvhcache_init() { - BVHCache *cache = (BVHCache *)MEM_callocN(sizeof(BVHCache), __func__); + BVHCache *cache = MEM_cnew<BVHCache>(__func__); BLI_mutex_init(&cache->mutex); return cache; } diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 21a9159004f..e6ce4eb9440 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -186,7 +186,7 @@ static ID *collection_owner_get(Main *bmain, ID *id) Collection *master_collection = (Collection *)id; BLI_assert((master_collection->flag & COLLECTION_IS_MASTER) != 0); - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { if (scene->master_collection == master_collection) { return &scene->id; } @@ -1205,9 +1205,7 @@ static void collection_object_remove_nulls(Collection *collection) { bool changed = false; - for (CollectionObject *cob = collection->gobject.first, *cob_next = NULL; cob; cob = cob_next) { - cob_next = cob->next; - + LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) { if (cob->ob == NULL) { BLI_freelinkN(&collection->gobject, cob); changed = true; @@ -1221,22 +1219,61 @@ static void collection_object_remove_nulls(Collection *collection) void BKE_collections_object_remove_nulls(Main *bmain) { - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { collection_object_remove_nulls(scene->master_collection); } - for (Collection *collection = bmain->collections.first; collection; - collection = collection->id.next) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { collection_object_remove_nulls(collection); } } -static void collection_null_children_remove(Collection *collection) +/* + * Remove all duplicate objects from collections. + * This is used for library remapping, happens when remapping an object to another one already + * present in the collection. Otherwise this should never happen. + */ +static void collection_object_remove_duplicates(Collection *collection) { - for (CollectionChild *child = collection->children.first, *child_next = NULL; child; - child = child_next) { - child_next = child->next; + bool changed = false; + + LISTBASE_FOREACH_MUTABLE (CollectionObject *, cob, &collection->gobject) { + if (cob->ob->runtime.collection_management) { + BLI_freelinkN(&collection->gobject, cob); + changed = true; + continue; + } + cob->ob->runtime.collection_management = true; + } + /* Cleanup. */ + LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { + cob->ob->runtime.collection_management = false; + } + + if (changed) { + BKE_collection_object_cache_free(collection); + } +} + +void BKE_collections_object_remove_duplicates(struct Main *bmain) +{ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + ob->runtime.collection_management = false; + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + collection_object_remove_duplicates(scene->master_collection); + } + + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + collection_object_remove_duplicates(collection); + } +} + +static void collection_null_children_remove(Collection *collection) +{ + LISTBASE_FOREACH_MUTABLE (CollectionChild *, child, &collection->children) { if (child->collection == NULL) { BLI_freelinkN(&collection->children, child); } @@ -1245,9 +1282,7 @@ static void collection_null_children_remove(Collection *collection) static void collection_missing_parents_remove(Collection *collection) { - for (CollectionParent *parent = collection->parents.first, *parent_next; parent != NULL; - parent = parent_next) { - parent_next = parent->next; + LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &collection->parents) { if ((parent->collection == NULL) || !collection_find_child(parent->collection, collection)) { BLI_freelinkN(&collection->parents, parent); } @@ -1267,28 +1302,23 @@ void BKE_collections_child_remove_nulls(Main *bmain, * otherwise we can miss some cases... * Also, master collections are not in bmain, so we also need to loop over scenes. */ - for (child_collection = bmain->collections.first; child_collection != NULL; - child_collection = child_collection->id.next) { - collection_null_children_remove(child_collection); + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + collection_null_children_remove(collection); } - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { collection_null_children_remove(scene->master_collection); } } - for (child_collection = bmain->collections.first; child_collection != NULL; - child_collection = child_collection->id.next) { - collection_missing_parents_remove(child_collection); + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + collection_missing_parents_remove(collection); } - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { collection_missing_parents_remove(scene->master_collection); } } else { - for (CollectionParent *parent = child_collection->parents.first, *parent_next; parent; - parent = parent_next) { - parent_next = parent->next; - + LISTBASE_FOREACH_MUTABLE (CollectionParent *, parent, &child_collection->parents) { collection_null_children_remove(parent->collection); if (!collection_find_child(parent->collection, child_collection)) { @@ -1586,9 +1616,9 @@ static void collection_parents_rebuild_recursive(Collection *collection) BKE_collection_parent_relations_rebuild(collection); collection->tag &= ~COLLECTION_TAG_RELATION_REBUILD; - for (CollectionChild *child = collection->children.first; child != NULL; child = child->next) { + LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { /* See comment above in `BKE_collection_parent_relations_rebuild`. */ - if ((collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) { + if ((child->collection->id.tag & (LIB_TAG_NO_MAIN | LIB_TAG_COPIED_ON_WRITE)) != 0) { continue; } collection_parents_rebuild_recursive(child->collection); @@ -1598,8 +1628,7 @@ static void collection_parents_rebuild_recursive(Collection *collection) void BKE_main_collections_parent_relations_rebuild(Main *bmain) { /* Only collections not in bmain (master ones in scenes) have no parent... */ - for (Collection *collection = bmain->collections.first; collection != NULL; - collection = collection->id.next) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { BLI_freelistN(&collection->parents); collection->tag |= COLLECTION_TAG_RELATION_REBUILD; @@ -1607,7 +1636,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain) /* Scene's master collections will be 'root' parent of most of our collections, so start with * them. */ - for (Scene *scene = bmain->scenes.first; scene != NULL; scene = scene->id.next) { + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { /* This function can be called from readfile.c, when this pointer is not guaranteed to be NULL. */ if (scene->master_collection != NULL) { @@ -1619,8 +1648,7 @@ void BKE_main_collections_parent_relations_rebuild(Main *bmain) /* We may have parent chains outside of scene's master_collection context? At least, readfile's * lib_link_collection_data() seems to assume that, so do the same here. */ - for (Collection *collection = bmain->collections.first; collection != NULL; - collection = collection->id.next) { + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { if (collection->tag & COLLECTION_TAG_RELATION_REBUILD) { /* NOTE: we do not have easy access to 'which collections is root' info in that case, which * means test for cycles in collection relationships may fail here. I don't think that is an diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index d532ed9e4b2..7481d4df351 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -278,13 +278,13 @@ void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const ch token = token.substr(first, (last - first + 1)); if (*token.begin() == '<' && *(--token.end()) == '>') { float encoded_hash = atof(token.substr(1, token.length() - 2).c_str()); - entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry = MEM_cnew<CryptomatteEntry>(__func__); entry->encoded_hash = encoded_hash; } else { const char *name = token.c_str(); int name_len = token.length(); - entry = (CryptomatteEntry *)MEM_callocN(sizeof(CryptomatteEntry), __func__); + entry = MEM_cnew<CryptomatteEntry>(__func__); STRNCPY(entry->name, name); uint32_t hash = BKE_cryptomatte_hash(name, name_len); entry->encoded_hash = BKE_cryptomatte_hash_to_float(hash); diff --git a/source/blender/blenkernel/intern/curve.cc b/source/blender/blenkernel/intern/curve.cc index 50b7c15774d..291927ee398 100644 --- a/source/blender/blenkernel/intern/curve.cc +++ b/source/blender/blenkernel/intern/curve.cc @@ -43,7 +43,7 @@ #include "DNA_defaults.h" #include "DNA_material_types.h" -/* for dereferencing pointers */ +/* For dereferencing pointers. */ #include "DNA_key_types.h" #include "DNA_object_types.h" #include "DNA_vfont_types.h" @@ -1438,7 +1438,7 @@ void BKE_nurb_makeFaces(const Nurb *nu, float *coord_array, int rowstride, int r jstart = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces4"); jend = (int *)MEM_malloc_arrayN(totv, sizeof(float), "makeNurbfaces5"); - /* precalculation of basisv and jstart, jend */ + /* Pre-calculation of `basisv` and `jstart`, `jend`. */ if (nu->flagv & CU_NURB_CYCLIC) { cycl = nu->orderv - 1; } @@ -2104,10 +2104,10 @@ static void tilt_bezpart(const BezTriple *prevbezt, } } -/* make_bevel_list_3D_* funcs, at a minimum these must - * fill in the bezp->quat and bezp->dir values */ +/* `make_bevel_list_3D_*` functions, at a minimum these must + * fill in the #BevPoint.quat and #BevPoint.dir values. */ -/* utility for make_bevel_list_3D_* funcs */ +/** Utility for `make_bevel_list_3D_*` functions. */ static void bevel_list_calc_bisect(BevList *bl) { BevPoint *bevp2, *bevp1, *bevp0; @@ -2329,14 +2329,14 @@ static void make_bevel_list_3D_minimum_twist(BevList *bl) /* Need to correct for the start/end points not matching * do this by calculating the tilt angle difference, then apply - * the rotation gradually over the entire curve + * the rotation gradually over the entire curve. * - * note that the split is between last and second last, rather than first/last as youd expect. + * Note that the split is between last and second last, rather than first/last as you'd expect. * * real order is like this * 0,1,2,3,4 --> 1,2,3,4,0 * - * this is why we compare last with second last + * This is why we compare last with second last. */ float vec_1[3] = {0, 1, 0}, vec_2[3] = {0, 1, 0}, angle, ang_fac, cross_tmp[3]; @@ -2614,14 +2614,13 @@ void BKE_curve_bevelList_free(ListBase *bev) void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_render) { - /* - * - convert all curves to polys, with indication of resol and flags for double-vertices - * - possibly; do a smart vertice removal (in case Nurb) - * - separate in individual blocks with BoundBox - * - AutoHole detection + /* - Convert all curves to polys, with indication of resolution and flags for double-vertices. + * - Possibly; do a smart vertex removal (in case #Nurb). + * - Separate in individual blocks with #BoundBox. + * - Auto-hole detection. */ - /* this function needs an object, because of tflag and upflag */ + /* This function needs an object, because of `tflag` and `upflag`. */ Curve *cu = (Curve *)ob->data; BezTriple *bezt, *prevbezt; BPoint *bp; @@ -2637,7 +2636,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ bool is_editmode = false; ListBase *bev; - /* segbevcount alsp requires seglen. */ + /* segbevcount also requires seglen. */ const bool need_seglen = ELEM( cu->bevfac1_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE) || ELEM(cu->bevfac2_mapping, CU_BEVFAC_MAP_SEGMENT, CU_BEVFAC_MAP_SPLINE); @@ -2695,7 +2694,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ if (nu->type == CU_POLY) { len = nu->pntsu; - BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__); + BevList *bl = MEM_cnew<BevList>(__func__); bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__); @@ -2745,7 +2744,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ /* in case last point is not cyclic */ len = segcount * resolu + 1; - BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__); + BevList *bl = MEM_cnew<BevList>(__func__); bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__); @@ -2805,10 +2804,10 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ } } else { - /* always do all three, to prevent data hanging around */ + /* Always do all three, to prevent data hanging around. */ int j; - /* BevPoint must stay aligned to 4 so sizeof(BevPoint)/sizeof(float) works */ + /* #BevPoint must stay aligned to 4 so `sizeof(BevPoint) / sizeof(float)` works. */ for (j = 0; j < 3; j++) { BKE_curve_forward_diff_bezier(prevbezt->vec[1][j], prevbezt->vec[2][j], @@ -2819,7 +2818,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ sizeof(BevPoint)); } - /* if both arrays are nullptr do nothiong */ + /* If both arrays are `nullptr` do nothing. */ tilt_bezpart(prevbezt, bezt, nu, @@ -2839,7 +2838,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ sizeof(BevPoint)); } - /* seglen */ + /* `seglen`. */ if (seglen != nullptr) { *seglen = 0; *segbevcount = 0; @@ -2847,7 +2846,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ bevp0 = bevp; bevp++; bevp->offset = len_v3v3(bevp0->vec, bevp->vec); - /* match seglen and segbevcount to the cleaned up bevel lists (see STEP 2) */ + /* Match `seglen` and `segbevcount` to the cleaned up bevel lists (see STEP 2). */ if (bevp->offset > threshold) { *seglen += bevp->offset; *segbevcount += 1; @@ -2881,7 +2880,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ if (nu->pntsv == 1) { len = (resolu * segcount); - BevList *bl = (BevList *)MEM_callocN(sizeof(BevList), __func__); + BevList *bl = MEM_cnew<BevList>(__func__); bl->bevpoints = (BevPoint *)MEM_calloc_arrayN(len, sizeof(BevPoint), __func__); if (need_seglen && (nu->flagu & CU_NURB_CYCLIC) == 0) { bl->seglen = (float *)MEM_malloc_arrayN(segcount, sizeof(float), __func__); @@ -2980,7 +2979,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ continue; } - nr = bl->nr - bl->dupe_nr + 1; /* +1 because vectorbezier sets flag too */ + nr = bl->nr - bl->dupe_nr + 1; /* +1 because vector-bezier sets flag too. */ blnew = (BevList *)MEM_mallocN(sizeof(BevList), "makeBevelList4"); memcpy(blnew, bl, sizeof(BevList)); blnew->bevpoints = (BevPoint *)MEM_calloc_arrayN(nr, sizeof(BevPoint), "makeBevelPoints4"); @@ -2992,7 +2991,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ blnew->seglen = bl->seglen; blnew->nr = 0; BLI_remlink(bev, bl); - BLI_insertlinkbefore(bev, bl->next, blnew); /* to make sure bevlist is tuned with nurblist */ + BLI_insertlinkbefore(bev, bl->next, blnew); /* Ensure `bevlist` is tuned with `nurblist`. */ bevp0 = bl->bevpoints; bevp1 = blnew->bevpoints; nr = bl->nr; @@ -3114,7 +3113,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ BevPoint *bevp = bl->bevpoints; unit_qt(bevp->quat); } - else if (bl->nr == 2) { /* 2 pnt, treat separate */ + else if (bl->nr == 2) { /* 2 points, treat separately. */ make_bevel_list_segment_2D(bl); } else { @@ -3129,7 +3128,7 @@ void BKE_curve_bevelList_make(Object *ob, const ListBase *nurbs, const bool for_ BevPoint *bevp = bl->bevpoints; unit_qt(bevp->quat); } - else if (bl->nr == 2) { /* 2 pnt, treat separate */ + else if (bl->nr == 2) { /* 2 points, treat separately. */ make_bevel_list_segment_3D(bl); } else { @@ -3321,13 +3320,13 @@ static void calchandleNurb_intern(BezTriple *bezt, } if (skip_align || - /* when one handle is free, alignming makes no sense, see: T35952 */ + /* When one handle is free, aligning makes no sense, see: T35952 */ ELEM(HD_FREE, bezt->h1, bezt->h2) || - /* also when no handles are aligned, skip this step */ + /* Also when no handles are aligned, skip this step. */ (!ELEM(HD_ALIGN, bezt->h1, bezt->h2) && !ELEM(HD_ALIGN_DOUBLESIDE, bezt->h1, bezt->h2))) { - /* handles need to be updated during animation and applying stuff like hooks, + /* Handles need to be updated during animation and applying stuff like hooks, * but in such situations it's quite difficult to distinguish in which order - * align handles should be aligned so skip them for now */ + * align handles should be aligned so skip them for now. */ return; } @@ -3996,8 +3995,8 @@ void BKE_nurb_handle_smooth_fcurve(BezTriple *bezt, int total, bool cyclic) } } - /* Find continuous subsequences of free auto handles and smooth them, starting at - * search_base. In cyclic mode these subsequences can span the cycle boundary. */ + /* Find continuous sub-sequences of free auto handles and smooth them, starting at search_base. + * In cyclic mode these sub-sequences can span the cycle boundary. */ int start = search_base, count = 1; for (int i = 1, j = start + 1; i < total; i++, j++) { @@ -4189,13 +4188,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag) /* left handle: */ if (flag == 0 || (bezt1->f1 & flag)) { bezt1->h1 = HD_FREE; - /* distance too short: vectorhandle */ + /* Distance too short: vector-handle. */ if (len_squared_v3v3(bezt1->vec[1], bezt0->vec[1]) < eps_sq) { bezt1->h1 = HD_VECT; leftsmall = true; } else { - /* aligned handle? */ + /* Aligned handle? */ if (dist_squared_to_line_v3(bezt1->vec[1], bezt1->vec[0], bezt1->vec[2]) < eps_sq) { align = true; bezt1->h1 = HD_ALIGN; @@ -4209,13 +4208,13 @@ void BKE_nurb_handles_autocalc(Nurb *nu, uint8_t flag) /* right handle: */ if (flag == 0 || (bezt1->f3 & flag)) { bezt1->h2 = HD_FREE; - /* distance too short: vectorhandle */ + /* Distance too short: vector-handle. */ if (len_squared_v3v3(bezt1->vec[1], bezt2->vec[1]) < eps_sq) { bezt1->h2 = HD_VECT; rightsmall = true; } else { - /* aligned handle? */ + /* Aligned handle? */ if (align) { bezt1->h2 = HD_ALIGN; } @@ -4860,7 +4859,7 @@ bool BKE_nurb_type_convert(Nurb *nu, int a, c, nr; if (nu->type == CU_POLY) { - if (type == CU_BEZIER) { /* To Bezier with vecthandles. */ + if (type == CU_BEZIER) { /* To Bezier with vector-handles. */ nr = nu->pntsu; bezt = (BezTriple *)MEM_calloc_arrayN(nr, sizeof(BezTriple), "setsplinetype2"); nu->bezt = bezt; diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index 38f736e6907..e2461adaaca 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -100,11 +100,17 @@ void CurveEval::transform(const float4x4 &matrix) } } -void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const +bool CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) const { + bool have_minmax = false; for (const SplinePtr &spline : this->splines()) { - spline->bounds_min_max(min, max, use_evaluated); + if (spline->size()) { + spline->bounds_min_max(min, max, use_evaluated); + have_minmax = true; + } } + + return have_minmax; } float CurveEval::total_length() const diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 5522a84d094..073d9d18a04 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -401,10 +401,8 @@ struct ResultAttributes { }; static ResultAttributes create_result_attributes(const CurveEval &curve, const CurveEval &profile, - Mesh &mesh) + MeshComponent &mesh_component) { - MeshComponent mesh_component; - mesh_component.replace(&mesh, GeometryOwnershipType::Editable); Set<AttributeIDRef> curve_attributes; /* In order to prefer attributes on the main curve input when there are name collisions, first @@ -708,7 +706,11 @@ Mesh *curve_to_mesh_sweep(const CurveEval &curve, const CurveEval &profile, cons mesh->smoothresh = DEG2RADF(180.0f); BKE_mesh_normals_tag_dirty(mesh); - ResultAttributes attributes = create_result_attributes(curve, profile, *mesh); + /* Create the mesh component for retrieving attributes at this scope, since output attributes + * can keep a reference to the component for updating after retrieving write access. */ + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + ResultAttributes attributes = create_result_attributes(curve, profile, mesh_component); threading::parallel_for(curves.index_range(), 128, [&](IndexRange curves_range) { for (const int i_spline : curves_range) { @@ -760,7 +762,10 @@ static CurveEval get_curve_single_vert() { CurveEval curve; std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); - spline->add_point(float3(0), 0, 0.0f); + spline->resize(1.0f); + spline->positions().fill(float3(0)); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); curve.add_spline(std::move(spline)); return curve; diff --git a/source/blender/blenkernel/intern/curveprofile.cc b/source/blender/blenkernel/intern/curveprofile.cc index 387709fca29..8f387be41d3 100644 --- a/source/blender/blenkernel/intern/curveprofile.cc +++ b/source/blender/blenkernel/intern/curveprofile.cc @@ -46,7 +46,7 @@ struct CurveProfile *BKE_curveprofile_add(eCurveProfilePresets preset) { - CurveProfile *profile = (CurveProfile *)MEM_callocN(sizeof(CurveProfile), __func__); + CurveProfile *profile = MEM_cnew<CurveProfile>(__func__); BKE_curveprofile_set_defaults(profile); profile->preset = preset; diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.cc index 1170f59bee3..f5c5fdcf34a 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.cc @@ -69,7 +69,7 @@ #define CUSTOMDATA_GROW 5 /* ensure typemap size is ok */ -BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)NULL)->typemap) == CD_NUMTYPES, "size mismatch"); +BLI_STATIC_ASSERT(ARRAY_SIZE(((CustomData *)nullptr)->typemap) == CD_NUMTYPES, "size mismatch"); static CLG_LogRef LOG = {"bke.customdata"}; @@ -94,7 +94,7 @@ bool CustomData_MeshMasks_are_matching(const CustomData_MeshMasks *mask_ref, } /********************* Layer type information **********************/ -typedef struct LayerTypeInfo { +struct LayerTypeInfo { int size; /* the memory size of one element of this layer's data */ /** name of the struct used, for file writing */ @@ -105,7 +105,7 @@ typedef struct LayerTypeInfo { /** * default layer name. * - * \note when NULL this is a way to ensure there is only ever one item + * \note when null this is a way to ensure there is only ever one item * see: CustomData_layertype_is_singleton(). */ const char *defaultname; @@ -113,7 +113,7 @@ typedef struct LayerTypeInfo { /** * a function to copy count elements of this layer's data * (deep copy if appropriate) - * if NULL, memcpy is used + * if null, memcpy is used */ cd_copy copy; @@ -128,7 +128,7 @@ typedef struct LayerTypeInfo { /** * a function to interpolate between count source elements of this * layer's data and store the result in dest - * if weights == NULL or sub_weights == NULL, they should default to 1 + * if weights == null or sub_weights == null, they should default to 1 * * weights gives the weight for each element in sources * sub_weights gives the sub-element weights for each element in sources @@ -146,7 +146,7 @@ typedef struct LayerTypeInfo { void (*swap)(void *data, const int *corner_indices); /** - * a function to set a layer's data to default values. if NULL, the + * a function to set a layer's data to default values. if null, the * default is assumed to be all zeros */ void (*set_default)(void *data, int count); @@ -171,9 +171,9 @@ typedef struct LayerTypeInfo { size_t (*filesize)(CDataFile *cdf, const void *data, int count); /** a function to determine max allowed number of layers, - * should be NULL or return -1 if no limit */ - int (*layers_max)(void); -} LayerTypeInfo; + * should be null or return -1 if no limit */ + int (*layers_max)(); +}; static void layerCopy_mdeformvert(const void *source, void *dest, int count) { @@ -182,17 +182,17 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count) memcpy(dest, source, count * size); for (i = 0; i < count; i++) { - MDeformVert *dvert = POINTER_OFFSET(dest, i * size); + MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(dest, i * size)); if (dvert->totweight) { - MDeformWeight *dw = MEM_malloc_arrayN( - dvert->totweight, sizeof(*dw), "layerCopy_mdeformvert dw"); + MDeformWeight *dw = static_cast<MDeformWeight *>( + MEM_malloc_arrayN(dvert->totweight, sizeof(*dw), __func__)); memcpy(dw, dvert->dw, dvert->totweight * sizeof(*dw)); dvert->dw = dw; } else { - dvert->dw = NULL; + dvert->dw = nullptr; } } } @@ -200,11 +200,11 @@ static void layerCopy_mdeformvert(const void *source, void *dest, int count) static void layerFree_mdeformvert(void *data, int count, int size) { for (int i = 0; i < count; i++) { - MDeformVert *dvert = POINTER_OFFSET(data, i * size); + MDeformVert *dvert = static_cast<MDeformVert *>(POINTER_OFFSET(data, i * size)); if (dvert->dw) { MEM_freeN(dvert->dw); - dvert->dw = NULL; + dvert->dw = nullptr; dvert->totweight = 0; } } @@ -216,8 +216,8 @@ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, const int size = sizeof(void *); for (int i = 0; i < count; i++) { - void **ptr = POINTER_OFFSET(dest, i * size); - *ptr = NULL; + void **ptr = (void **)POINTER_OFFSET(dest, i * size); + *ptr = nullptr; } } @@ -231,9 +231,9 @@ void bpy_bm_generic_invalidate(struct BPy_BMGeneric *UNUSED(self)) static void layerFree_bmesh_elem_py_ptr(void *data, int count, int size) { for (int i = 0; i < count; i++) { - void **ptr = POINTER_OFFSET(data, i * size); + void **ptr = (void **)POINTER_OFFSET(data, i * size); if (*ptr) { - bpy_bm_generic_invalidate(*ptr); + bpy_bm_generic_invalidate(static_cast<BPy_BMGeneric *>(*ptr)); } } } @@ -251,14 +251,14 @@ static void layerInterp_mdeformvert(const void **sources, MDeformWeight dw; }; - MDeformVert *dvert = dest; - struct MDeformWeight_Link *dest_dwlink = NULL; + MDeformVert *dvert = static_cast<MDeformVert *>(dest); + struct MDeformWeight_Link *dest_dwlink = nullptr; struct MDeformWeight_Link *node; /* build a list of unique def_nrs for dest */ int totweight = 0; for (int i = 0; i < count; i++) { - const MDeformVert *source = sources[i]; + const MDeformVert *source = static_cast<const MDeformVert *>(sources[i]); float interp_weight = weights[i]; for (int j = 0; j < source->totweight; j++) { @@ -280,7 +280,8 @@ static void layerInterp_mdeformvert(const void **sources, /* if this def_nr is not in the list, add it */ if (!node) { - struct MDeformWeight_Link *tmp_dwlink = alloca(sizeof(*tmp_dwlink)); + struct MDeformWeight_Link *tmp_dwlink = static_cast<MDeformWeight_Link *>( + alloca(sizeof(*tmp_dwlink))); tmp_dwlink->dw.def_nr = dw->def_nr; tmp_dwlink->dw.weight = weight; @@ -305,7 +306,8 @@ static void layerInterp_mdeformvert(const void **sources, } if (totweight) { - dvert->dw = MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__); + dvert->dw = static_cast<MDeformWeight *>( + MEM_malloc_arrayN(totweight, sizeof(*dvert->dw), __func__)); } } @@ -346,7 +348,7 @@ static void layerInterp_normal(const void **sources, static bool layerValidate_normal(void *data, const uint totitems, const bool do_fixes) { static const float no_default[3] = {0.0f, 0.0f, 1.0f}; /* Z-up default normal... */ - float(*no)[3] = data; + float(*no)[3] = (float(*)[3])data; bool has_errors = false; for (int i = 0; i < totitems; i++, no++) { @@ -372,8 +374,8 @@ static void layerCopyValue_normal(const void *source, const int mixmode, const float mixfactor) { - const float *no_src = source; - float *no_dst = dest; + const float *no_src = (const float *)source; + float *no_dst = (float *)dest; float no_tmp[3]; if (ELEM(mixmode, @@ -416,13 +418,13 @@ static void layerCopy_tface(const void *source, void *dest, int count) static void layerInterp_tface( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { - MTFace *tf = dest; + MTFace *tf = static_cast<MTFace *>(dest); float uv[4][2] = {{0.0f}}; const float *sub_weight = sub_weights; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const MTFace *src = sources[i]; + const MTFace *src = static_cast<const MTFace *>(sources[i]); for (int j = 0; j < 4; j++) { if (sub_weights) { @@ -443,7 +445,7 @@ static void layerInterp_tface( static void layerSwap_tface(void *data, const int *corner_indices) { - MTFace *tf = data; + MTFace *tf = static_cast<MTFace *>(data); float uv[4][2]; for (int j = 0; j < 4; j++) { @@ -464,7 +466,7 @@ static void layerDefault_tface(void *data, int count) } } -static int layerMaxNum_tface(void) +static int layerMaxNum_tface() { return MAX_MTFACE; } @@ -491,7 +493,7 @@ static void layerInterp_propFloat(const void **sources, static bool layerValidate_propFloat(void *data, const uint totitems, const bool do_fixes) { - MFloatProperty *fp = data; + MFloatProperty *fp = static_cast<MFloatProperty *>(data); bool has_errors = false; for (int i = 0; i < totitems; i++, fp++) { @@ -529,13 +531,13 @@ static void layerCopy_origspace_face(const void *source, void *dest, int count) static void layerInterp_origspace_face( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { - OrigSpaceFace *osf = dest; + OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(dest); float uv[4][2] = {{0.0f}}; const float *sub_weight = sub_weights; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const OrigSpaceFace *src = sources[i]; + const OrigSpaceFace *src = static_cast<const OrigSpaceFace *>(sources[i]); for (int j = 0; j < 4; j++) { if (sub_weights) { @@ -555,7 +557,7 @@ static void layerInterp_origspace_face( static void layerSwap_origspace_face(void *data, const int *corner_indices) { - OrigSpaceFace *osf = data; + OrigSpaceFace *osf = static_cast<OrigSpaceFace *>(data); float uv[4][2]; for (int j = 0; j < 4; j++) { @@ -576,7 +578,7 @@ static void layerDefault_origspace_face(void *data, int count) static void layerSwap_mdisps(void *data, const int *ci) { - MDisps *s = data; + MDisps *s = static_cast<MDisps *>(data); if (s->disps) { int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */ @@ -589,11 +591,11 @@ static void layerSwap_mdisps(void *data, const int *ci) MEM_freeN(s->disps); s->totdisp = (s->totdisp / corners) * nverts; - s->disps = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap"); + s->disps = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisp swap"); return; } - float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); + float(*d)[3] = (float(*)[3])MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); for (int S = 0; S < corners; S++) { memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize); @@ -606,17 +608,17 @@ static void layerSwap_mdisps(void *data, const int *ci) static void layerCopy_mdisps(const void *source, void *dest, int count) { - const MDisps *s = source; - MDisps *d = dest; + const MDisps *s = static_cast<const MDisps *>(source); + MDisps *d = static_cast<MDisps *>(dest); for (int i = 0; i < count; i++) { if (s[i].disps) { - d[i].disps = MEM_dupallocN(s[i].disps); - d[i].hidden = MEM_dupallocN(s[i].hidden); + d[i].disps = static_cast<float(*)[3]>(MEM_dupallocN(s[i].disps)); + d[i].hidden = static_cast<unsigned int *>(MEM_dupallocN(s[i].hidden)); } else { - d[i].disps = NULL; - d[i].hidden = NULL; + d[i].disps = nullptr; + d[i].hidden = nullptr; } /* still copy even if not in memory, displacement can be external */ @@ -627,7 +629,7 @@ static void layerCopy_mdisps(const void *source, void *dest, int count) static void layerFree_mdisps(void *data, int count, int UNUSED(size)) { - MDisps *d = data; + MDisps *d = static_cast<MDisps *>(data); for (int i = 0; i < count; i++) { if (d[i].disps) { @@ -636,8 +638,8 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size)) if (d[i].hidden) { MEM_freeN(d[i].hidden); } - d[i].disps = NULL; - d[i].hidden = NULL; + d[i].disps = nullptr; + d[i].hidden = nullptr; d[i].totdisp = 0; d[i].level = 0; } @@ -645,16 +647,16 @@ static void layerFree_mdisps(void *data, int count, int UNUSED(size)) static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) { - MDisps *d = data; + MDisps *d = static_cast<MDisps *>(data); for (int i = 0; i < count; i++) { if (!d[i].disps) { - d[i].disps = MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read"); + d[i].disps = (float(*)[3])MEM_calloc_arrayN(d[i].totdisp, sizeof(float[3]), "mdisps read"); } if (!cdf_read_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) { CLOG_ERROR(&LOG, "failed to read multires displacement %d/%d %d", i, count, d[i].totdisp); - return 0; + return false; } } @@ -663,12 +665,12 @@ static bool layerRead_mdisps(CDataFile *cdf, void *data, int count) static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) { - const MDisps *d = data; + const MDisps *d = static_cast<const MDisps *>(data); for (int i = 0; i < count; i++) { if (!cdf_write_data(cdf, sizeof(float[3]) * d[i].totdisp, d[i].disps)) { CLOG_ERROR(&LOG, "failed to write multires displacement %d/%d %d", i, count, d[i].totdisp); - return 0; + return false; } } @@ -677,7 +679,7 @@ static bool layerWrite_mdisps(CDataFile *cdf, const void *data, int count) static size_t layerFilesize_mdisps(CDataFile *UNUSED(cdf), const void *data, int count) { - const MDisps *d = data; + const MDisps *d = static_cast<const MDisps *>(data); size_t size = 0; for (int i = 0; i < count; i++) { @@ -695,7 +697,7 @@ static void layerInterp_paint_mask(const void **sources, float mask = 0.0f; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const float *src = sources[i]; + const float *src = static_cast<const float *>(sources[i]); mask += (*src) * interp_weight; } *(float *)dest = mask; @@ -703,16 +705,16 @@ static void layerInterp_paint_mask(const void **sources, static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) { - const GridPaintMask *s = source; - GridPaintMask *d = dest; + const GridPaintMask *s = static_cast<const GridPaintMask *>(source); + GridPaintMask *d = static_cast<GridPaintMask *>(dest); for (int i = 0; i < count; i++) { if (s[i].data) { - d[i].data = MEM_dupallocN(s[i].data); + d[i].data = static_cast<float *>(MEM_dupallocN(s[i].data)); d[i].level = s[i].level; } else { - d[i].data = NULL; + d[i].data = nullptr; d[i].level = 0; } } @@ -720,7 +722,7 @@ static void layerCopy_grid_paint_mask(const void *source, void *dest, int count) static void layerFree_grid_paint_mask(void *data, int count, int UNUSED(size)) { - GridPaintMask *gpm = data; + GridPaintMask *gpm = static_cast<GridPaintMask *>(data); for (int i = 0; i < count; i++) { MEM_SAFE_FREE(gpm[i].data); @@ -734,8 +736,8 @@ static void layerCopyValue_mloopcol(const void *source, const int mixmode, const float mixfactor) { - const MLoopCol *m1 = source; - MLoopCol *m2 = dest; + const MLoopCol *m1 = static_cast<const MLoopCol *>(source); + MLoopCol *m2 = static_cast<MLoopCol *>(dest); unsigned char tmp_col[4]; if (ELEM(mixmode, @@ -789,7 +791,8 @@ static void layerCopyValue_mloopcol(const void *source, static bool layerEqual_mloopcol(const void *data1, const void *data2) { - const MLoopCol *m1 = data1, *m2 = data2; + const MLoopCol *m1 = static_cast<const MLoopCol *>(data1); + const MLoopCol *m2 = static_cast<const MLoopCol *>(data2); float r, g, b, a; r = m1->r - m2->r; @@ -802,7 +805,7 @@ static bool layerEqual_mloopcol(const void *data1, const void *data2) static void layerMultiply_mloopcol(void *data, float fac) { - MLoopCol *m = data; + MLoopCol *m = static_cast<MLoopCol *>(data); m->r = (float)m->r * fac; m->g = (float)m->g * fac; @@ -812,8 +815,8 @@ static void layerMultiply_mloopcol(void *data, float fac) static void layerAdd_mloopcol(void *data1, const void *data2) { - MLoopCol *m = data1; - const MLoopCol *m2 = data2; + MLoopCol *m = static_cast<MLoopCol *>(data1); + const MLoopCol *m2 = static_cast<const MLoopCol *>(data2); m->r += m2->r; m->g += m2->g; @@ -823,8 +826,9 @@ static void layerAdd_mloopcol(void *data1, const void *data2) static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax) { - const MLoopCol *m = data; - MLoopCol *min = vmin, *max = vmax; + const MLoopCol *m = static_cast<const MLoopCol *>(data); + MLoopCol *min = static_cast<MLoopCol *>(vmin); + MLoopCol *max = static_cast<MLoopCol *>(vmax); if (m->r < min->r) { min->r = m->r; @@ -854,7 +858,8 @@ static void layerDoMinMax_mloopcol(const void *data, void *vmin, void *vmax) static void layerInitMinMax_mloopcol(void *vmin, void *vmax) { - MLoopCol *min = vmin, *max = vmax; + MLoopCol *min = static_cast<MLoopCol *>(vmin); + MLoopCol *max = static_cast<MLoopCol *>(vmax); min->r = 255; min->g = 255; @@ -882,7 +887,7 @@ static void layerInterp_mloopcol(const void **sources, int count, void *dest) { - MLoopCol *mc = dest; + MLoopCol *mc = static_cast<MLoopCol *>(dest); struct { float a; float r; @@ -892,7 +897,7 @@ static void layerInterp_mloopcol(const void **sources, for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const MLoopCol *src = sources[i]; + const MLoopCol *src = static_cast<const MLoopCol *>(sources[i]); col.r += src->r * interp_weight; col.g += src->g * interp_weight; col.b += src->b * interp_weight; @@ -909,7 +914,7 @@ static void layerInterp_mloopcol(const void **sources, mc->a = round_fl_to_uchar_clamp(col.a); } -static int layerMaxNum_mloopcol(void) +static int layerMaxNum_mloopcol() { return MAX_MCOL; } @@ -919,8 +924,8 @@ static void layerCopyValue_mloopuv(const void *source, const int mixmode, const float mixfactor) { - const MLoopUV *luv1 = source; - MLoopUV *luv2 = dest; + const MLoopUV *luv1 = static_cast<const MLoopUV *>(source); + MLoopUV *luv2 = static_cast<MLoopUV *>(dest); /* We only support a limited subset of advanced mixing here - * namely the mixfactor interpolation. */ @@ -935,37 +940,40 @@ static void layerCopyValue_mloopuv(const void *source, static bool layerEqual_mloopuv(const void *data1, const void *data2) { - const MLoopUV *luv1 = data1, *luv2 = data2; + const MLoopUV *luv1 = static_cast<const MLoopUV *>(data1); + const MLoopUV *luv2 = static_cast<const MLoopUV *>(data2); return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } static void layerMultiply_mloopuv(void *data, float fac) { - MLoopUV *luv = data; + MLoopUV *luv = static_cast<MLoopUV *>(data); mul_v2_fl(luv->uv, fac); } static void layerInitMinMax_mloopuv(void *vmin, void *vmax) { - MLoopUV *min = vmin, *max = vmax; + MLoopUV *min = static_cast<MLoopUV *>(vmin); + MLoopUV *max = static_cast<MLoopUV *>(vmax); INIT_MINMAX2(min->uv, max->uv); } static void layerDoMinMax_mloopuv(const void *data, void *vmin, void *vmax) { - const MLoopUV *luv = data; - MLoopUV *min = vmin, *max = vmax; + const MLoopUV *luv = static_cast<const MLoopUV *>(data); + MLoopUV *min = static_cast<MLoopUV *>(vmin); + MLoopUV *max = static_cast<MLoopUV *>(vmax); minmax_v2v2_v2(min->uv, max->uv, luv->uv); } static void layerAdd_mloopuv(void *data1, const void *data2) { - MLoopUV *l1 = data1; - const MLoopUV *l2 = data2; + MLoopUV *l1 = static_cast<MLoopUV *>(data1); + const MLoopUV *l2 = static_cast<const MLoopUV *>(data2); add_v2_v2(l1->uv, l2->uv); } @@ -983,7 +991,7 @@ static void layerInterp_mloopuv(const void **sources, for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const MLoopUV *src = sources[i]; + const MLoopUV *src = static_cast<const MLoopUV *>(sources[i]); madd_v2_v2fl(uv, src->uv, interp_weight); if (interp_weight > 0.0f) { flag |= src->flag; @@ -997,7 +1005,7 @@ static void layerInterp_mloopuv(const void **sources, static bool layerValidate_mloopuv(void *data, const uint totitems, const bool do_fixes) { - MLoopUV *uv = data; + MLoopUV *uv = static_cast<MLoopUV *>(data); bool has_errors = false; for (int i = 0; i < totitems; i++, uv++) { @@ -1018,45 +1026,48 @@ static void layerCopyValue_mloop_origspace(const void *source, const int UNUSED(mixmode), const float UNUSED(mixfactor)) { - const OrigSpaceLoop *luv1 = source; - OrigSpaceLoop *luv2 = dest; + const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(source); + OrigSpaceLoop *luv2 = static_cast<OrigSpaceLoop *>(dest); copy_v2_v2(luv2->uv, luv1->uv); } static bool layerEqual_mloop_origspace(const void *data1, const void *data2) { - const OrigSpaceLoop *luv1 = data1, *luv2 = data2; + const OrigSpaceLoop *luv1 = static_cast<const OrigSpaceLoop *>(data1); + const OrigSpaceLoop *luv2 = static_cast<const OrigSpaceLoop *>(data2); return len_squared_v2v2(luv1->uv, luv2->uv) < 0.00001f; } static void layerMultiply_mloop_origspace(void *data, float fac) { - OrigSpaceLoop *luv = data; + OrigSpaceLoop *luv = static_cast<OrigSpaceLoop *>(data); mul_v2_fl(luv->uv, fac); } static void layerInitMinMax_mloop_origspace(void *vmin, void *vmax) { - OrigSpaceLoop *min = vmin, *max = vmax; + OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin); + OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax); INIT_MINMAX2(min->uv, max->uv); } static void layerDoMinMax_mloop_origspace(const void *data, void *vmin, void *vmax) { - const OrigSpaceLoop *luv = data; - OrigSpaceLoop *min = vmin, *max = vmax; + const OrigSpaceLoop *luv = static_cast<const OrigSpaceLoop *>(data); + OrigSpaceLoop *min = static_cast<OrigSpaceLoop *>(vmin); + OrigSpaceLoop *max = static_cast<OrigSpaceLoop *>(vmax); minmax_v2v2_v2(min->uv, max->uv, luv->uv); } static void layerAdd_mloop_origspace(void *data1, const void *data2) { - OrigSpaceLoop *l1 = data1; - const OrigSpaceLoop *l2 = data2; + OrigSpaceLoop *l1 = static_cast<OrigSpaceLoop *>(data1); + const OrigSpaceLoop *l2 = static_cast<const OrigSpaceLoop *>(data2); add_v2_v2(l1->uv, l2->uv); } @@ -1072,7 +1083,7 @@ static void layerInterp_mloop_origspace(const void **sources, for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const OrigSpaceLoop *src = sources[i]; + const OrigSpaceLoop *src = static_cast<const OrigSpaceLoop *>(sources[i]); madd_v2_v2fl(uv, src->uv, interp_weight); } @@ -1084,7 +1095,7 @@ static void layerInterp_mloop_origspace(const void **sources, static void layerInterp_mcol( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { - MCol *mc = dest; + MCol *mc = static_cast<MCol *>(dest); struct { float a; float r; @@ -1098,7 +1109,7 @@ static void layerInterp_mcol( for (int j = 0; j < 4; j++) { if (sub_weights) { - const MCol *src = sources[i]; + const MCol *src = static_cast<const MCol *>(sources[i]); for (int k = 0; k < 4; k++, sub_weight++, src++) { const float w = (*sub_weight) * interp_weight; col[j].a += src->a * w; @@ -1108,7 +1119,7 @@ static void layerInterp_mcol( } } else { - const MCol *src = sources[i]; + const MCol *src = static_cast<const MCol *>(sources[i]); col[j].a += src[j].a * interp_weight; col[j].r += src[j].r * interp_weight; col[j].g += src[j].g * interp_weight; @@ -1131,7 +1142,7 @@ static void layerInterp_mcol( static void layerSwap_mcol(void *data, const int *corner_indices) { - MCol *mcol = data; + MCol *mcol = static_cast<MCol *>(data); MCol col[4]; for (int j = 0; j < 4; j++) { @@ -1205,7 +1216,7 @@ static void layerInterp_shapekey(const void **sources, static void layerDefault_mvert_skin(void *data, int count) { - MVertSkin *vs = data; + MVertSkin *vs = static_cast<MVertSkin *>(data); for (int i = 0; i < count; i++) { copy_v3_fl(vs[i].radius, 0.25f); @@ -1229,20 +1240,20 @@ static void layerInterp_mvert_skin(const void **sources, for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const MVertSkin *vs_src = sources[i]; + const MVertSkin *vs_src = static_cast<const MVertSkin *>(sources[i]); madd_v3_v3fl(radius, vs_src->radius, interp_weight); } /* Delay writing to the destination in case dest is in sources. */ - MVertSkin *vs_dst = dest; + MVertSkin *vs_dst = static_cast<MVertSkin *>(dest); copy_v3_v3(vs_dst->radius, radius); vs_dst->flag &= ~MVERT_SKIN_ROOT; } static void layerSwap_flnor(void *data, const int *corner_indices) { - short(*flnors)[4][3] = data; + short(*flnors)[4][3] = static_cast<short(*)[4][3]>(data); short nors[4][3]; int i = 4; @@ -1266,8 +1277,8 @@ static void layerCopyValue_propcol(const void *source, const int mixmode, const float mixfactor) { - const MPropCol *m1 = source; - MPropCol *m2 = dest; + const MPropCol *m1 = static_cast<const MPropCol *>(source); + MPropCol *m2 = static_cast<MPropCol *>(dest); float tmp_col[4]; if (ELEM(mixmode, @@ -1311,7 +1322,8 @@ static void layerCopyValue_propcol(const void *source, static bool layerEqual_propcol(const void *data1, const void *data2) { - const MPropCol *m1 = data1, *m2 = data2; + const MPropCol *m1 = static_cast<const MPropCol *>(data1); + const MPropCol *m2 = static_cast<const MPropCol *>(data2); float tot = 0; for (int i = 0; i < 4; i++) { @@ -1324,27 +1336,29 @@ static bool layerEqual_propcol(const void *data1, const void *data2) static void layerMultiply_propcol(void *data, float fac) { - MPropCol *m = data; + MPropCol *m = static_cast<MPropCol *>(data); mul_v4_fl(m->color, fac); } static void layerAdd_propcol(void *data1, const void *data2) { - MPropCol *m = data1; - const MPropCol *m2 = data2; + MPropCol *m = static_cast<MPropCol *>(data1); + const MPropCol *m2 = static_cast<const MPropCol *>(data2); add_v4_v4(m->color, m2->color); } static void layerDoMinMax_propcol(const void *data, void *vmin, void *vmax) { - const MPropCol *m = data; - MPropCol *min = vmin, *max = vmax; + const MPropCol *m = static_cast<const MPropCol *>(data); + MPropCol *min = static_cast<MPropCol *>(vmin); + MPropCol *max = static_cast<MPropCol *>(vmax); minmax_v4v4_v4(min->color, max->color, m->color); } static void layerInitMinMax_propcol(void *vmin, void *vmax) { - MPropCol *min = vmin, *max = vmax; + MPropCol *min = static_cast<MPropCol *>(vmin); + MPropCol *max = static_cast<MPropCol *>(vmax); copy_v4_fl(min->color, FLT_MAX); copy_v4_fl(max->color, FLT_MIN); @@ -1366,17 +1380,17 @@ static void layerInterp_propcol(const void **sources, int count, void *dest) { - MPropCol *mc = dest; + MPropCol *mc = static_cast<MPropCol *>(dest); float col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const MPropCol *src = sources[i]; + const MPropCol *src = static_cast<const MPropCol *>(sources[i]); madd_v4_v4fl(col, src->color, interp_weight); } copy_v4_v4(mc->color, col); } -static int layerMaxNum_propcol(void) +static int layerMaxNum_propcol() { return MAX_MCOL; } @@ -1390,7 +1404,7 @@ static void layerInterp_propfloat3(const void **sources, vec3f result = {0.0f, 0.0f, 0.0f}; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const vec3f *src = sources[i]; + const vec3f *src = static_cast<const vec3f *>(sources[i]); madd_v3_v3fl(&result.x, &src->x, interp_weight); } copy_v3_v3((float *)dest, &result.x); @@ -1398,7 +1412,7 @@ static void layerInterp_propfloat3(const void **sources, static void layerMultiply_propfloat3(void *data, float fac) { - vec3f *vec = data; + vec3f *vec = static_cast<vec3f *>(data); vec->x *= fac; vec->y *= fac; vec->z *= fac; @@ -1406,8 +1420,8 @@ static void layerMultiply_propfloat3(void *data, float fac) static void layerAdd_propfloat3(void *data1, const void *data2) { - vec3f *vec1 = data1; - const vec3f *vec2 = data2; + vec3f *vec1 = static_cast<vec3f *>(data1); + const vec3f *vec2 = static_cast<const vec3f *>(data2); vec1->x += vec2->x; vec1->y += vec2->y; vec1->z += vec2->z; @@ -1415,7 +1429,7 @@ static void layerAdd_propfloat3(void *data1, const void *data2) static bool layerValidate_propfloat3(void *data, const uint totitems, const bool do_fixes) { - float *values = data; + float *values = static_cast<float *>(data); bool has_errors = false; for (int i = 0; i < totitems * 3; i++) { if (!isfinite(values[i])) { @@ -1437,7 +1451,7 @@ static void layerInterp_propfloat2(const void **sources, vec2f result = {0.0f, 0.0f}; for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; - const vec2f *src = sources[i]; + const vec2f *src = static_cast<const vec2f *>(sources[i]); madd_v2_v2fl(&result.x, &src->x, interp_weight); } copy_v2_v2((float *)dest, &result.x); @@ -1445,22 +1459,22 @@ static void layerInterp_propfloat2(const void **sources, static void layerMultiply_propfloat2(void *data, float fac) { - vec2f *vec = data; + vec2f *vec = static_cast<vec2f *>(data); vec->x *= fac; vec->y *= fac; } static void layerAdd_propfloat2(void *data1, const void *data2) { - vec2f *vec1 = data1; - const vec2f *vec2 = data2; + vec2f *vec1 = static_cast<vec2f *>(data1); + const vec2f *vec2 = static_cast<const vec2f *>(data2); vec1->x += vec2->x; vec1->y += vec2->y; } static bool layerValidate_propfloat2(void *data, const uint totitems, const bool do_fixes) { - float *values = data; + float *values = static_cast<float *>(data); bool has_errors = false; for (int i = 0; i < totitems * 2; i++) { if (!isfinite(values[i])) { @@ -1475,136 +1489,130 @@ static bool layerValidate_propfloat2(void *data, const uint totitems, const bool static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { /* 0: CD_MVERT */ - {sizeof(MVert), "MVert", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MVert), "MVert", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 1: CD_MSTICKY */ /* DEPRECATED */ - {sizeof(float[2]), "", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[2]), "", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 2: CD_MDEFORMVERT */ {sizeof(MDeformVert), "MDeformVert", 1, - NULL, + nullptr, layerCopy_mdeformvert, layerFree_mdeformvert, layerInterp_mdeformvert, - NULL, - NULL}, + nullptr, + nullptr}, /* 3: CD_MEDGE */ - {sizeof(MEdge), "MEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MEdge), "MEdge", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 4: CD_MFACE */ - {sizeof(MFace), "MFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MFace), "MFace", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 5: CD_MTFACE */ - {sizeof(MTFace), - "MTFace", - 1, - N_("UVMap"), - layerCopy_tface, - NULL, - layerInterp_tface, - layerSwap_tface, - layerDefault_tface, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - layerMaxNum_tface}, + {sizeof(MTFace), "MTFace", 1, + N_("UVMap"), layerCopy_tface, nullptr, + layerInterp_tface, layerSwap_tface, layerDefault_tface, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, nullptr, nullptr, + nullptr, layerMaxNum_tface}, /* 6: CD_MCOL */ /* 4 MCol structs per face */ {sizeof(MCol[4]), "MCol", 4, N_("Col"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, layerMaxNum_mloopcol}, /* 7: CD_ORIGINDEX */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_origindex}, + {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_origindex}, /* 8: CD_NORMAL */ /* 3 floats per normal vector */ {sizeof(float[3]), "vec3f", 1, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, layerInterp_normal, - NULL, - NULL, + nullptr, + nullptr, layerValidate_normal, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, layerCopyValue_normal}, /* 9: CD_FACEMAP */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, layerDefault_fmap, NULL}, + {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, layerDefault_fmap, nullptr}, /* 10: CD_PROP_FLOAT */ {sizeof(MFloatProperty), "MFloatProperty", 1, N_("Float"), layerCopy_propFloat, - NULL, + nullptr, layerInterp_propFloat, - NULL, - NULL, + nullptr, + nullptr, layerValidate_propFloat}, /* 11: CD_PROP_INT32 */ - {sizeof(MIntProperty), "MIntProperty", 1, N_("Int"), layerCopy_propInt, NULL, NULL, NULL}, + {sizeof(MIntProperty), + "MIntProperty", + 1, + N_("Int"), + layerCopy_propInt, + nullptr, + nullptr, + nullptr}, /* 12: CD_PROP_STRING */ {sizeof(MStringProperty), "MStringProperty", 1, N_("String"), layerCopy_propString, - NULL, - NULL, - NULL}, + nullptr, + nullptr, + nullptr}, /* 13: CD_ORIGSPACE */ {sizeof(OrigSpaceFace), "OrigSpaceFace", 1, N_("UVMap"), layerCopy_origspace_face, - NULL, + nullptr, layerInterp_origspace_face, layerSwap_origspace_face, layerDefault_origspace_face}, /* 14: CD_ORCO */ - {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 15: CD_MTEXPOLY */ /* DEPRECATED */ /* NOTE: when we expose the UV Map / TexFace split to the user, * change this back to face Texture. */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 16: CD_MLOOPUV */ {sizeof(MLoopUV), "MLoopUV", 1, N_("UVMap"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mloopuv, - NULL, - NULL, + nullptr, + nullptr, layerValidate_mloopuv, layerEqual_mloopuv, layerMultiply_mloopuv, @@ -1612,50 +1620,50 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { layerAdd_mloopuv, layerDoMinMax_mloopuv, layerCopyValue_mloopuv, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, layerMaxNum_tface}, /* 17: CD_MLOOPCOL */ {sizeof(MLoopCol), "MLoopCol", 1, N_("Col"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mloopcol, - NULL, + nullptr, layerDefault_mloopcol, - NULL, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, layerAdd_mloopcol, layerDoMinMax_mloopcol, layerCopyValue_mloopcol, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, layerMaxNum_mloopcol}, /* 18: CD_TANGENT */ - {sizeof(float[4][4]), "", 0, N_("Tangent"), NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[4][4]), "", 0, N_("Tangent"), nullptr, nullptr, nullptr, nullptr, nullptr}, /* 19: CD_MDISPS */ {sizeof(MDisps), "MDisps", 1, - NULL, + nullptr, layerCopy_mdisps, layerFree_mdisps, - NULL, + nullptr, layerSwap_mdisps, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, layerRead_mdisps, layerWrite_mdisps, layerFilesize_mdisps}, @@ -1664,52 +1672,58 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { "MCol", 4, N_("PreviewCol"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, /* 21: CD_ID_MCOL */ /* DEPRECATED */ - {sizeof(MCol[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(MCol[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 22: CD_TEXTURE_MCOL */ {sizeof(MCol[4]), "MCol", 4, N_("TexturedCol"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mcol, layerSwap_mcol, layerDefault_mcol}, /* 23: CD_CLOTH_ORCO */ - {sizeof(float[3]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[3]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 24: CD_RECAST */ - {sizeof(MRecast), "MRecast", 1, N_("Recast"), NULL, NULL, NULL, NULL}, - - /* BMESH ONLY */ + {sizeof(MRecast), "MRecast", 1, N_("Recast"), nullptr, nullptr, nullptr, nullptr}, /* 25: CD_MPOLY */ - {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), NULL, NULL, NULL, NULL, NULL}, + {sizeof(MPoly), "MPoly", 1, N_("NGon Face"), nullptr, nullptr, nullptr, nullptr, nullptr}, /* 26: CD_MLOOP */ - {sizeof(MLoop), "MLoop", 1, N_("NGon Face-Vertex"), NULL, NULL, NULL, NULL, NULL}, + {sizeof(MLoop), + "MLoop", + 1, + N_("NGon Face-Vertex"), + nullptr, + nullptr, + nullptr, + nullptr, + nullptr}, /* 27: CD_SHAPE_KEYINDEX */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 28: CD_SHAPEKEY */ - {sizeof(float[3]), "", 0, N_("ShapeKey"), NULL, NULL, layerInterp_shapekey}, + {sizeof(float[3]), "", 0, N_("ShapeKey"), nullptr, nullptr, layerInterp_shapekey}, /* 29: CD_BWEIGHT */ - {sizeof(float), "", 0, N_("BevelWeight"), NULL, NULL, layerInterp_bweight}, + {sizeof(float), "", 0, N_("BevelWeight"), nullptr, nullptr, layerInterp_bweight}, /* 30: CD_CREASE */ - {sizeof(float), "", 0, N_("SubSurfCrease"), NULL, NULL, layerInterp_bweight}, + {sizeof(float), "", 0, N_("SubSurfCrease"), nullptr, nullptr, layerInterp_bweight}, /* 31: CD_ORIGSPACE_MLOOP */ {sizeof(OrigSpaceLoop), "OrigSpaceLoop", 1, N_("OS Loop"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mloop_origspace, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, layerEqual_mloop_origspace, layerMultiply_mloop_origspace, layerInitMinMax_mloop_origspace, @@ -1721,12 +1735,12 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { "MLoopCol", 1, N_("PreviewLoopCol"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_mloopcol, - NULL, + nullptr, layerDefault_mloopcol, - NULL, + nullptr, layerEqual_mloopcol, layerMultiply_mloopcol, layerInitMinMax_mloopcol, @@ -1737,125 +1751,138 @@ static const LayerTypeInfo LAYERTYPEINFO[CD_NUMTYPES] = { {sizeof(void *), "", 1, - NULL, + nullptr, layerCopy_bmesh_elem_py_ptr, layerFree_bmesh_elem_py_ptr, - NULL, - NULL, - NULL}, - - /* END BMESH ONLY */ - + nullptr, + nullptr, + nullptr}, /* 34: CD_PAINT_MASK */ - {sizeof(float), "", 0, NULL, NULL, NULL, layerInterp_paint_mask, NULL, NULL}, + {sizeof(float), "", 0, nullptr, nullptr, nullptr, layerInterp_paint_mask, nullptr, nullptr}, /* 35: CD_GRID_PAINT_MASK */ {sizeof(GridPaintMask), "GridPaintMask", 1, - NULL, + nullptr, layerCopy_grid_paint_mask, layerFree_grid_paint_mask, - NULL, - NULL, - NULL}, + nullptr, + nullptr, + nullptr}, /* 36: CD_MVERT_SKIN */ {sizeof(MVertSkin), "MVertSkin", 1, - NULL, + nullptr, layerCopy_mvert_skin, - NULL, + nullptr, layerInterp_mvert_skin, - NULL, + nullptr, layerDefault_mvert_skin}, /* 37: CD_FREESTYLE_EDGE */ - {sizeof(FreestyleEdge), "FreestyleEdge", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(FreestyleEdge), + "FreestyleEdge", + 1, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr}, /* 38: CD_FREESTYLE_FACE */ - {sizeof(FreestyleFace), "FreestyleFace", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(FreestyleFace), + "FreestyleFace", + 1, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr}, /* 39: CD_MLOOPTANGENT */ - {sizeof(float[4]), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[4]), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 40: CD_TESSLOOPNORMAL */ - {sizeof(short[4][3]), "", 0, NULL, NULL, NULL, NULL, layerSwap_flnor, NULL}, + {sizeof(short[4][3]), "", 0, nullptr, nullptr, nullptr, nullptr, layerSwap_flnor, nullptr}, /* 41: CD_CUSTOMLOOPNORMAL */ - {sizeof(short[2]), "vec2s", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(short[2]), "vec2s", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 42: CD_SCULPT_FACE_SETS */ - {sizeof(int), "", 0, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(int), "", 0, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 43: CD_LOCATION */ - {sizeof(float[3]), "vec3f", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float[3]), "vec3f", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 44: CD_RADIUS */ - {sizeof(float), "MFloatProperty", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float), "MFloatProperty", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 45: CD_HAIRCURVE */ - {sizeof(HairCurve), "HairCurve", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(HairCurve), "HairCurve", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 46: CD_HAIRMAPPING */ - {sizeof(HairMapping), "HairMapping", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(HairMapping), "HairMapping", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, /* 47: CD_PROP_COLOR */ {sizeof(MPropCol), "MPropCol", 1, N_("Color"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_propcol, - NULL, + nullptr, layerDefault_propcol, - NULL, + nullptr, layerEqual_propcol, layerMultiply_propcol, layerInitMinMax_propcol, layerAdd_propcol, layerDoMinMax_propcol, layerCopyValue_propcol, - NULL, - NULL, - NULL, + nullptr, + nullptr, + nullptr, layerMaxNum_propcol}, /* 48: CD_PROP_FLOAT3 */ {sizeof(float[3]), "vec3f", 1, N_("Float3"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_propfloat3, - NULL, - NULL, + nullptr, + nullptr, layerValidate_propfloat3, - NULL, + nullptr, layerMultiply_propfloat3, - NULL, + nullptr, layerAdd_propfloat3}, /* 49: CD_PROP_FLOAT2 */ {sizeof(float[2]), "vec2f", 1, N_("Float2"), - NULL, - NULL, + nullptr, + nullptr, layerInterp_propfloat2, - NULL, - NULL, + nullptr, + nullptr, layerValidate_propfloat2, - NULL, + nullptr, layerMultiply_propfloat2, - NULL, + nullptr, layerAdd_propfloat2}, /* 50: CD_PROP_BOOL */ {sizeof(bool), "bool", 1, N_("Boolean"), - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL, - NULL}, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr}, /* 51: CD_HAIRLENGTH */ - {sizeof(float), "float", 1, NULL, NULL, NULL, NULL, NULL, NULL}, + {sizeof(float), "float", 1, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr}, }; static const char *LAYERTYPENAMES[CD_NUMTYPES] = { @@ -1916,95 +1943,106 @@ static const char *LAYERTYPENAMES[CD_NUMTYPES] = { }; const CustomData_MeshMasks CD_MASK_BAREMESH = { - .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT, - .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT, - .fmask = 0, - .lmask = CD_MASK_MLOOP, - .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP, + /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT, + /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT, + /* fmask */ 0, + /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP, + /* lmask */ CD_MASK_MLOOP, }; const CustomData_MeshMasks CD_MASK_BAREMESH_ORIGINDEX = { - .vmask = CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX, - .emask = CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX, - .fmask = 0, - .lmask = CD_MASK_MLOOP, - .pmask = CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX, + /* vmask */ CD_MASK_MVERT | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX, + /* emask */ CD_MASK_MEDGE | CD_MASK_BWEIGHT | CD_MASK_ORIGINDEX, + /* fmask */ 0, + /* pmask */ CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_ORIGINDEX, + /* lmask */ CD_MASK_MLOOP, }; const CustomData_MeshMasks CD_MASK_MESH = { - .vmask = (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK | - CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), - .fmask = 0, - .lmask = (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | - CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), - .pmask = (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | - CD_MASK_SCULPT_FACE_SETS), + /* vmask */ (CD_MASK_MVERT | CD_MASK_MDEFORMVERT | CD_MASK_MVERT_SKIN | CD_MASK_PAINT_MASK | + CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + /* emask */ (CD_MASK_MEDGE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), + /* fmask */ 0, + /* pmask */ + (CD_MASK_MPOLY | CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | + CD_MASK_SCULPT_FACE_SETS), + /* lmask */ + (CD_MASK_MLOOP | CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | + CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), }; const CustomData_MeshMasks CD_MASK_EDITMESH = { - .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_PROP_ALL), - .fmask = 0, - .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), - .pmask = (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), + /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_PAINT_MASK | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + /* emask */ (CD_MASK_PROP_ALL), + /* fmask */ 0, + /* pmask */ (CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), + /* lmask */ + (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | + CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), }; const CustomData_MeshMasks CD_MASK_DERIVEDMESH = { - .vmask = (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN | - CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL | - CD_MASK_PROP_COLOR), - .emask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), - .fmask = (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT), - .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | - CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */ - .pmask = (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | - CD_MASK_SCULPT_FACE_SETS), + /* vmask */ (CD_MASK_ORIGINDEX | CD_MASK_MDEFORMVERT | CD_MASK_SHAPEKEY | CD_MASK_MVERT_SKIN | + CD_MASK_PAINT_MASK | CD_MASK_ORCO | CD_MASK_CLOTH_ORCO | CD_MASK_PROP_ALL | + CD_MASK_PROP_COLOR), + /* emask */ (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), + /* fmask */ (CD_MASK_ORIGINDEX | CD_MASK_ORIGSPACE | CD_MASK_PREVIEW_MCOL | CD_MASK_TANGENT), + /* pmask */ + (CD_MASK_ORIGINDEX | CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | + CD_MASK_SCULPT_FACE_SETS), + /* lmask */ + (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_PREVIEW_MLOOPCOL | + CD_MASK_ORIGSPACE_MLOOP | CD_MASK_PROP_ALL), /* XXX MISSING CD_MASK_MLOOPTANGENT ? */ }; const CustomData_MeshMasks CD_MASK_BMESH = { - .vmask = (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | - CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), - .fmask = 0, - .lmask = (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), - .pmask = (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | - CD_MASK_SCULPT_FACE_SETS), + /* vmask */ (CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_SHAPEKEY | + CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | + CD_MASK_PROP_COLOR), + /* emask */ (CD_MASK_BWEIGHT | CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), + /* fmask */ 0, + /* pmask */ + (CD_MASK_FREESTYLE_FACE | CD_MASK_FACEMAP | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), + /* lmask */ + (CD_MASK_MDISPS | CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | + CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), }; /** * cover values copied by #mesh_loops_to_tessdata */ const CustomData_MeshMasks CD_MASK_FACECORNERS = { - .vmask = 0, - .emask = 0, - .fmask = (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE | - CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT), - .lmask = (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | - CD_MASK_ORIGSPACE_MLOOP | CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT), - .pmask = 0, + /* vmask */ 0, + /* emask */ 0, + /* fmask */ + (CD_MASK_MTFACE | CD_MASK_MCOL | CD_MASK_PREVIEW_MCOL | CD_MASK_ORIGSPACE | + CD_MASK_TESSLOOPNORMAL | CD_MASK_TANGENT), + /* pmask */ 0, + /* lmask */ + (CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | + CD_MASK_NORMAL | CD_MASK_MLOOPTANGENT), }; const CustomData_MeshMasks CD_MASK_EVERYTHING = { - .vmask = (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | - CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | - CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | CD_MASK_PAINT_MASK | - CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), - .emask = (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | - CD_MASK_CREASE | CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), - .fmask = (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL | - CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL | - CD_MASK_PROP_ALL), - .lmask = (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | - CD_MASK_MLOOPUV | CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | - CD_MASK_MLOOPTANGENT | CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | - CD_MASK_GRID_PAINT_MASK | CD_MASK_PROP_ALL), - .pmask = (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | - CD_MASK_FACEMAP | CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | - CD_MASK_SCULPT_FACE_SETS), + /* vmask */ (CD_MASK_MVERT | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | + CD_MASK_MDEFORMVERT | CD_MASK_BWEIGHT | CD_MASK_MVERT_SKIN | CD_MASK_ORCO | + CD_MASK_CLOTH_ORCO | CD_MASK_SHAPEKEY | CD_MASK_SHAPE_KEYINDEX | + CD_MASK_PAINT_MASK | CD_MASK_PROP_ALL | CD_MASK_PROP_COLOR), + /* emask */ + (CD_MASK_MEDGE | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_BWEIGHT | CD_MASK_CREASE | + CD_MASK_FREESTYLE_EDGE | CD_MASK_PROP_ALL), + /* fmask */ + (CD_MASK_MFACE | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_MTFACE | CD_MASK_MCOL | + CD_MASK_ORIGSPACE | CD_MASK_TANGENT | CD_MASK_TESSLOOPNORMAL | CD_MASK_PREVIEW_MCOL | + CD_MASK_PROP_ALL), + /* pmask */ + (CD_MASK_MPOLY | CD_MASK_BM_ELEM_PYPTR | CD_MASK_ORIGINDEX | CD_MASK_NORMAL | CD_MASK_FACEMAP | + CD_MASK_FREESTYLE_FACE | CD_MASK_PROP_ALL | CD_MASK_SCULPT_FACE_SETS), + /* lmask */ + (CD_MASK_MLOOP | CD_MASK_BM_ELEM_PYPTR | CD_MASK_MDISPS | CD_MASK_NORMAL | CD_MASK_MLOOPUV | + CD_MASK_MLOOPCOL | CD_MASK_CUSTOMLOOPNORMAL | CD_MASK_MLOOPTANGENT | + CD_MASK_PREVIEW_MLOOPCOL | CD_MASK_ORIGSPACE_MLOOP | CD_MASK_GRID_PAINT_MASK | + CD_MASK_PROP_ALL), }; static const LayerTypeInfo *layerType_getInfo(int type) { if (type < 0 || type >= CD_NUMTYPES) { - return NULL; + return nullptr; } return &LAYERTYPEINFO[type]; @@ -2013,7 +2051,7 @@ static const LayerTypeInfo *layerType_getInfo(int type) static const char *layerType_getName(int type) { if (type < 0 || type >= CD_NUMTYPES) { - return NULL; + return nullptr; } return LAYERTYPENAMES[type]; @@ -2147,7 +2185,7 @@ bool CustomData_merge(const struct CustomData *source, data = layer->data; break; default: - data = NULL; + data = nullptr; break; } @@ -2169,7 +2207,7 @@ bool CustomData_merge(const struct CustomData *source, newlayer->flag |= flag & (CD_FLAG_EXTERNAL | CD_FLAG_IN_MEMORY); changed = true; - if (layer->anonymous_id != NULL) { + if (layer->anonymous_id != nullptr) { BKE_anonymous_attribute_id_increment_weak(layer->anonymous_id); newlayer->anonymous_id = layer->anonymous_id; } @@ -2202,7 +2240,7 @@ void CustomData_copy(const struct CustomData *source, CustomData_reset(dest); if (source->external) { - dest->external = MEM_dupallocN(source->external); + dest->external = static_cast<CustomDataExternal *>(MEM_dupallocN(source->external)); } CustomData_merge(source, dest, mask, alloctype, totelem); @@ -2212,9 +2250,9 @@ static void customData_free_layer__internal(CustomDataLayer *layer, int totelem) { const LayerTypeInfo *typeInfo; - if (layer->anonymous_id != NULL) { + if (layer->anonymous_id != nullptr) { BKE_anonymous_attribute_id_decrement_weak(layer->anonymous_id); - layer->anonymous_id = NULL; + layer->anonymous_id = nullptr; } if (!(layer->flag & CD_FLAG_NOFREE) && layer->data) { typeInfo = layerType_getInfo(layer->type); @@ -2233,7 +2271,7 @@ static void CustomData_external_free(CustomData *data) { if (data->external) { MEM_freeN(data->external); - data->external = NULL; + data->external = nullptr; } } @@ -2506,8 +2544,8 @@ void CustomData_clear_layer_flag(struct CustomData *data, int type, int flag) static bool customData_resize(CustomData *data, int amount) { - CustomDataLayer *tmp = MEM_calloc_arrayN( - (data->maxlayer + amount), sizeof(*tmp), "CustomData->layers"); + CustomDataLayer *tmp = static_cast<CustomDataLayer *>( + MEM_calloc_arrayN((data->maxlayer + amount), sizeof(*tmp), __func__)); if (!tmp) { return false; } @@ -2531,7 +2569,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, { const LayerTypeInfo *typeInfo = layerType_getInfo(type); int flag = 0, index = data->totlayer; - void *newlayerdata = NULL; + void *newlayerdata = nullptr; /* Passing a layer-data to copy from with an alloctype that won't copy is * most likely a bug */ @@ -2553,7 +2591,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, } if (!newlayerdata) { - return NULL; + return nullptr; } } @@ -2581,7 +2619,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, if (newlayerdata != layerdata) { MEM_freeN(newlayerdata); } - return NULL; + return nullptr; } } @@ -2647,7 +2685,7 @@ void *CustomData_add_layer( return layer->data; } - return NULL; + return nullptr; } void *CustomData_add_layer_named(CustomData *data, @@ -2665,7 +2703,7 @@ void *CustomData_add_layer_named(CustomData *data, return layer->data; } - return NULL; + return nullptr; } void *CustomData_add_layer_anonymous(struct CustomData *data, @@ -2680,8 +2718,8 @@ void *CustomData_add_layer_anonymous(struct CustomData *data, data, type, alloctype, layerdata, totelem, name); CustomData_update_typemap(data); - if (layer == NULL) { - return NULL; + if (layer == nullptr) { + return nullptr; } BKE_anonymous_attribute_id_increment_weak(anonymous_id); @@ -2794,7 +2832,7 @@ static void *customData_duplicate_referenced_layer_index(CustomData *data, const int totelem) { if (layer_index == -1) { - return NULL; + return nullptr; } CustomDataLayer *layer = &data->layers[layer_index]; @@ -2863,7 +2901,7 @@ void *CustomData_duplicate_referenced_layer_anonymous(CustomData *data, } } BLI_assert_unreachable(); - return NULL; + return nullptr; } void CustomData_duplicate_referenced_layers(CustomData *data, int totelem) @@ -2959,7 +2997,7 @@ void CustomData_copy_data_layer(const CustomData *source, const size_t dst_offset = (size_t)dst_index * typeInfo->size; if (!count || !src_data || !dst_data) { - if (count && !(src_data == NULL && dst_data == NULL)) { + if (count && !(src_data == nullptr && dst_data == nullptr)) { CLOG_WARN(&LOG, "null data for %s type (%p --> %p), skipping", layerType_getName(source->layers[src_layer_index].type), @@ -3086,15 +3124,16 @@ void CustomData_interp(const CustomData *source, /* Slow fallback in case we're interpolating a ridiculous number of elements. */ if (count > SOURCE_BUF_SIZE) { - sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__); + sources = static_cast<const void **>(MEM_malloc_arrayN(count, sizeof(*sources), __func__)); } /* If no weights are given, generate default ones to produce an average result. */ float default_weights_buf[SOURCE_BUF_SIZE]; - float *default_weights = NULL; - if (weights == NULL) { + float *default_weights = nullptr; + if (weights == nullptr) { default_weights = (count > SOURCE_BUF_SIZE) ? - MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) : + static_cast<float *>( + MEM_mallocN(sizeof(*weights) * (size_t)count, __func__)) : default_weights_buf; copy_vn_fl(default_weights, count, 1.0f / count); weights = default_weights; @@ -3146,7 +3185,7 @@ void CustomData_interp(const CustomData *source, if (count > SOURCE_BUF_SIZE) { MEM_freeN((void *)sources); } - if (!ELEM(default_weights, NULL, default_weights_buf)) { + if (!ELEM(default_weights, nullptr, default_weights_buf)) { MEM_freeN(default_weights); } } @@ -3198,7 +3237,7 @@ void *CustomData_get(const CustomData *data, int index, int type) /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { - return NULL; + return nullptr; } /* get the offset of the desired element */ @@ -3214,7 +3253,7 @@ void *CustomData_get_n(const CustomData *data, int type, int index, int n) /* get the layer index of the first layer of type */ int layer_index = data->typemap[type]; if (layer_index == -1) { - return NULL; + return nullptr; } const size_t offset = (size_t)index * layerType_getInfo(type)->size; @@ -3226,7 +3265,7 @@ void *CustomData_get_layer(const CustomData *data, int type) /* get the layer index of the active layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { - return NULL; + return nullptr; } return data->layers[layer_index].data; @@ -3237,7 +3276,7 @@ void *CustomData_get_layer_n(const CustomData *data, int type, int n) /* get the layer index of the active layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { - return NULL; + return nullptr; } return data->layers[layer_index].data; @@ -3247,7 +3286,7 @@ void *CustomData_get_layer_named(const struct CustomData *data, int type, const { int layer_index = CustomData_get_named_layer_index(data, type, name); if (layer_index == -1) { - return NULL; + return nullptr; } return data->layers[layer_index].data; @@ -3293,7 +3332,7 @@ const char *CustomData_get_layer_name(const CustomData *data, int type, int n) { const int layer_index = CustomData_get_layer_index_n(data, type, n); - return (layer_index == -1) ? NULL : data->layers[layer_index].name; + return (layer_index == -1) ? nullptr : data->layers[layer_index].name; } void *CustomData_set_layer(const CustomData *data, int type, void *ptr) @@ -3302,7 +3341,7 @@ void *CustomData_set_layer(const CustomData *data, int type, void *ptr) int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { - return NULL; + return nullptr; } data->layers[layer_index].data = ptr; @@ -3315,7 +3354,7 @@ void *CustomData_set_layer_n(const struct CustomData *data, int type, int n, voi /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index_n(data, type, n); if (layer_index == -1) { - return NULL; + return nullptr; } data->layers[layer_index].data = ptr; @@ -3347,19 +3386,19 @@ void CustomData_to_bmeshpoly(CustomData *fdata, CustomData *ldata, int totloop) for (int i = 0; i < fdata->totlayer; i++) { if (fdata->layers[i].type == CD_MTFACE) { CustomData_add_layer_named( - ldata, CD_MLOOPUV, CD_CALLOC, NULL, totloop, fdata->layers[i].name); + ldata, CD_MLOOPUV, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MCOL) { CustomData_add_layer_named( - ldata, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, fdata->layers[i].name); + ldata, CD_MLOOPCOL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_MDISPS) { CustomData_add_layer_named( - ldata, CD_MDISPS, CD_CALLOC, NULL, totloop, fdata->layers[i].name); + ldata, CD_MDISPS, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); } else if (fdata->layers[i].type == CD_TESSLOOPNORMAL) { CustomData_add_layer_named( - ldata, CD_NORMAL, CD_CALLOC, NULL, totloop, fdata->layers[i].name); + ldata, CD_NORMAL, CD_CALLOC, nullptr, totloop, fdata->layers[i].name); } } } @@ -3371,25 +3410,27 @@ void CustomData_from_bmeshpoly(CustomData *fdata, CustomData *ldata, int total) for (int i = 0; i < ldata->totlayer; i++) { if (ldata->layers[i].type == CD_MLOOPUV) { - CustomData_add_layer_named(fdata, CD_MTFACE, CD_CALLOC, NULL, total, ldata->layers[i].name); + CustomData_add_layer_named( + fdata, CD_MTFACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); } if (ldata->layers[i].type == CD_MLOOPCOL) { - CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name); + CustomData_add_layer_named(fdata, CD_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_PREVIEW_MLOOPCOL) { CustomData_add_layer_named( - fdata, CD_PREVIEW_MCOL, CD_CALLOC, NULL, total, ldata->layers[i].name); + fdata, CD_PREVIEW_MCOL, CD_CALLOC, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_ORIGSPACE_MLOOP) { CustomData_add_layer_named( - fdata, CD_ORIGSPACE, CD_CALLOC, NULL, total, ldata->layers[i].name); + fdata, CD_ORIGSPACE, CD_CALLOC, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_NORMAL) { CustomData_add_layer_named( - fdata, CD_TESSLOOPNORMAL, CD_CALLOC, NULL, total, ldata->layers[i].name); + fdata, CD_TESSLOOPNORMAL, CD_CALLOC, nullptr, total, ldata->layers[i].name); } else if (ldata->layers[i].type == CD_TANGENT) { - CustomData_add_layer_named(fdata, CD_TANGENT, CD_CALLOC, NULL, total, ldata->layers[i].name); + CustomData_add_layer_named( + fdata, CD_TANGENT, CD_CALLOC, nullptr, total, ldata->layers[i].name); } } @@ -3502,7 +3543,7 @@ void CustomData_bmesh_init_pool(CustomData *data, int totelem, const char htype) int chunksize; /* Dispose old pools before calling here to avoid leaks */ - BLI_assert(data->pool == NULL); + BLI_assert(data->pool == nullptr); switch (htype) { case BM_VERT: @@ -3545,7 +3586,7 @@ bool CustomData_bmesh_merge(const CustomData *source, * the new allocation */ CustomData destold = *dest; if (destold.layers) { - destold.layers = MEM_dupallocN(destold.layers); + destold.layers = static_cast<CustomDataLayer *>(MEM_dupallocN(destold.layers)); } if (CustomData_merge(source, dest, mask, alloctype, 0) == false) { @@ -3581,7 +3622,7 @@ bool CustomData_bmesh_merge(const CustomData *source, break; } - dest->pool = NULL; + dest->pool = nullptr; CustomData_bmesh_init_pool(dest, totelem, htype); if (iter_type != BM_LOOPS_OF_FACE) { @@ -3589,7 +3630,7 @@ bool CustomData_bmesh_merge(const CustomData *source, BMIter iter; /* Ensure all current elements follow new customdata layout. */ BM_ITER_MESH (h, &iter, bm, iter_type) { - void *tmp = NULL; + void *tmp = nullptr; CustomData_bmesh_copy_data(&destold, dest, h->data, &tmp); CustomData_bmesh_free_block(&destold, &h->data); h->data = tmp; @@ -3604,7 +3645,7 @@ bool CustomData_bmesh_merge(const CustomData *source, /* Ensure all current elements follow new customdata layout. */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - void *tmp = NULL; + void *tmp = nullptr; CustomData_bmesh_copy_data(&destold, dest, l->head.data, &tmp); CustomData_bmesh_free_block(&destold, &l->head.data); l->head.data = tmp; @@ -3623,7 +3664,7 @@ bool CustomData_bmesh_merge(const CustomData *source, void CustomData_bmesh_free_block(CustomData *data, void **block) { - if (*block == NULL) { + if (*block == nullptr) { return; } @@ -3642,12 +3683,12 @@ void CustomData_bmesh_free_block(CustomData *data, void **block) BLI_mempool_free(data->pool, *block); } - *block = NULL; + *block = nullptr; } void CustomData_bmesh_free_block_data(CustomData *data, void *block) { - if (block == NULL) { + if (block == nullptr) { return; } for (int i = 0; i < data->totlayer; i++) { @@ -3674,7 +3715,7 @@ static void CustomData_bmesh_alloc_block(CustomData *data, void **block) *block = BLI_mempool_alloc(data->pool); } else { - *block = NULL; + *block = nullptr; } } @@ -3682,7 +3723,7 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, void *block, const CustomDataMask mask_exclude) { - if (block == NULL) { + if (block == nullptr) { return; } for (int i = 0; i < data->totlayer; i++) { @@ -3714,7 +3755,7 @@ static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n void CustomData_bmesh_set_default(CustomData *data, void **block) { - if (*block == NULL) { + if (*block == nullptr) { CustomData_bmesh_alloc_block(data, block); } @@ -3733,7 +3774,7 @@ void CustomData_bmesh_copy_data_exclude_by_type(const CustomData *source, * would cause too much duplicate code, so add a check instead. */ const bool no_mask = (mask_exclude == 0); - if (*dest_block == NULL) { + if (*dest_block == nullptr) { CustomData_bmesh_alloc_block(dest, dest_block); if (*dest_block) { memset(*dest_block, 0, dest->totsize); @@ -3799,7 +3840,7 @@ void *CustomData_bmesh_get(const CustomData *data, void *block, int type) /* get the layer index of the first layer of type */ int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { - return NULL; + return nullptr; } return POINTER_OFFSET(block, data->layers[layer_index].offset); @@ -3810,7 +3851,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int /* get the layer index of the first layer of type */ int layer_index = CustomData_get_layer_index(data, type); if (layer_index == -1) { - return NULL; + return nullptr; } return POINTER_OFFSET(block, data->layers[layer_index + n].offset); @@ -3819,7 +3860,7 @@ void *CustomData_bmesh_get_n(const CustomData *data, void *block, int type, int void *CustomData_bmesh_get_layer_n(const CustomData *data, void *block, int n) { if (n < 0 || n >= data->totlayer) { - return NULL; + return nullptr; } return POINTER_OFFSET(block, data->layers[n].offset); @@ -4035,7 +4076,7 @@ void CustomData_bmesh_interp_n(CustomData *data, void *dst_block_ofs, int n) { - BLI_assert(weights != NULL); + BLI_assert(weights != nullptr); BLI_assert(count > 0); CustomDataLayer *layer = &data->layers[n]; @@ -4060,15 +4101,15 @@ void CustomData_bmesh_interp(CustomData *data, /* Slow fallback in case we're interpolating a ridiculous number of elements. */ if (count > SOURCE_BUF_SIZE) { - sources = MEM_malloc_arrayN(count, sizeof(*sources), __func__); + sources = (const void **)MEM_malloc_arrayN(count, sizeof(*sources), __func__); } /* If no weights are given, generate default ones to produce an average result. */ float default_weights_buf[SOURCE_BUF_SIZE]; - float *default_weights = NULL; - if (weights == NULL) { + float *default_weights = nullptr; + if (weights == nullptr) { default_weights = (count > SOURCE_BUF_SIZE) ? - MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) : + (float *)MEM_mallocN(sizeof(*weights) * (size_t)count, __func__) : default_weights_buf; copy_vn_fl(default_weights, count, 1.0f / count); weights = default_weights; @@ -4090,7 +4131,7 @@ void CustomData_bmesh_interp(CustomData *data, if (count > SOURCE_BUF_SIZE) { MEM_freeN((void *)sources); } - if (!ELEM(default_weights, NULL, default_weights_buf)) { + if (!ELEM(default_weights, nullptr, default_weights_buf)) { MEM_freeN(default_weights); } } @@ -4101,7 +4142,7 @@ void CustomData_to_bmesh_block(const CustomData *source, void **dest_block, bool use_default_init) { - if (*dest_block == NULL) { + if (*dest_block == nullptr) { CustomData_bmesh_alloc_block(dest, dest_block); } @@ -4223,22 +4264,22 @@ void CustomData_blend_write_prepare(CustomData *data, for (i = 0, j = 0; i < totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; /* Layers with this flag set are not written to file. */ - if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != NULL) { + if ((layer->flag & CD_FLAG_NOCOPY) || layer->anonymous_id != nullptr) { data->totlayer--; // CLOG_WARN(&LOG, "skipping layer %p (%s)", layer, layer->name); } else { if (UNLIKELY((size_t)j >= write_layers_size)) { if (write_layers == write_layers_buff) { - write_layers = MEM_malloc_arrayN( + write_layers = (CustomDataLayer *)MEM_malloc_arrayN( (write_layers_size + chunk_size), sizeof(*write_layers), __func__); if (write_layers_buff) { memcpy(write_layers, write_layers_buff, sizeof(*write_layers) * write_layers_size); } } else { - write_layers = MEM_reallocN(write_layers, - sizeof(*write_layers) * (write_layers_size + chunk_size)); + write_layers = (CustomDataLayer *)MEM_reallocN( + write_layers, sizeof(*write_layers) * (write_layers_size + chunk_size)); } write_layers_size += chunk_size; } @@ -4265,14 +4306,14 @@ const char *CustomData_layertype_name(int type) bool CustomData_layertype_is_singleton(int type) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - return typeInfo->defaultname == NULL; + return typeInfo->defaultname == nullptr; } bool CustomData_layertype_is_dynamic(int type) { const LayerTypeInfo *typeInfo = layerType_getInfo(type); - return (typeInfo->free != NULL); + return (typeInfo->free != nullptr); } int CustomData_layertype_layers_max(const int type) @@ -4280,10 +4321,10 @@ int CustomData_layertype_layers_max(const int type) const LayerTypeInfo *typeInfo = layerType_getInfo(type); /* Same test as for singleton above. */ - if (typeInfo->defaultname == NULL) { + if (typeInfo->defaultname == nullptr) { return 1; } - if (typeInfo->layers_max == NULL) { + if (typeInfo->layers_max == nullptr) { return -1; } @@ -4313,13 +4354,15 @@ static bool cd_layer_find_dupe(CustomData *data, const char *name, int type, int return false; } +struct CustomDataUniqueCheckData { + CustomData *data; + int type; + int index; +}; + static bool customdata_unique_check(void *arg, const char *name) { - struct { - CustomData *data; - int type; - int index; - } *data_arg = arg; + CustomDataUniqueCheckData *data_arg = static_cast<CustomDataUniqueCheckData *>(arg); return cd_layer_find_dupe(data_arg->data, name, data_arg->type, data_arg->index); } @@ -4328,14 +4371,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index) CustomDataLayer *nlayer = &data->layers[index]; const LayerTypeInfo *typeInfo = layerType_getInfo(nlayer->type); - struct { - CustomData *data; - int type; - int index; - } data_arg; - data_arg.data = data; - data_arg.type = nlayer->type; - data_arg.index = index; + CustomDataUniqueCheckData data_arg{data, nlayer->type, index}; if (!typeInfo->defaultname) { return; @@ -4348,7 +4384,7 @@ void CustomData_set_layer_unique_name(CustomData *data, int index) } BLI_uniquename_cb( - customdata_unique_check, &data_arg, NULL, '.', nlayer->name, sizeof(nlayer->name)); + customdata_unique_check, &data_arg, nullptr, '.', nlayer->name, sizeof(nlayer->name)); } void CustomData_validate_layer_name(const CustomData *data, @@ -4420,7 +4456,7 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons { const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); - if (typeInfo->validate != NULL) { + if (typeInfo->validate != nullptr) { return typeInfo->validate(layer->data, totitems, do_fixes); } @@ -4672,7 +4708,7 @@ void CustomData_external_add( } if (!external) { - external = MEM_callocN(sizeof(CustomDataExternal), "CustomDataExternal"); + external = MEM_cnew<CustomDataExternal>(__func__); data->external = external; } BLI_strncpy(external->filename, filename, sizeof(external->filename)); @@ -4771,7 +4807,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye const int count, const float mix_factor) { - BLI_assert(weights != NULL); + BLI_assert(weights != nullptr); BLI_assert(count > 0); /* Fake interpolation, we actually copy highest weighted source to dest. @@ -4786,8 +4822,8 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye size_t data_size; const uint64_t data_flag = laymap->data_flag; - cd_interp interp_cd = NULL; - cd_copy copy_cd = NULL; + cd_interp interp_cd = nullptr; + cd_copy copy_cd = nullptr; if (!sources) { /* Not supported here, abort. */ @@ -4841,7 +4877,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye BLI_assert(best_src_idx >= 0); if (interp_cd) { - interp_cd(sources, weights, NULL, count, tmp_dst); + interp_cd(sources, weights, nullptr, count, tmp_dst); } else if (data_flag) { copy_bit_flag(tmp_dst, sources[best_src_idx], data_size, data_flag); @@ -4886,13 +4922,13 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye const int count, const float mix_factor) { - BLI_assert(weights != NULL); + BLI_assert(weights != nullptr); BLI_assert(count > 0); const int data_type = laymap->data_type; const int mix_mode = laymap->mix_mode; - SpaceTransform *space_transform = laymap->interp_data; + SpaceTransform *space_transform = static_cast<SpaceTransform *>(laymap->interp_data); const LayerTypeInfo *type_info = layerType_getInfo(data_type); cd_interp interp_cd = type_info->interp; @@ -4906,7 +4942,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye return; } - interp_cd(sources, weights, NULL, count, tmp_dst); + interp_cd(sources, weights, nullptr, count, tmp_dst); if (space_transform) { /* tmp_dst is in source space so far, bring it back in destination space. */ BLI_space_transform_invert_normal(space_transform, tmp_dst); @@ -4929,18 +4965,19 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, size_t data_size; size_t data_offset; - cd_datatransfer_interp interp = NULL; + cd_datatransfer_interp interp = nullptr; size_t tmp_buff_size = 32; - const void **tmp_data_src = NULL; + const void **tmp_data_src = nullptr; - /* NOTE: NULL data_src may happen and be valid (see vgroups...). */ + /* NOTE: null data_src may happen and be valid (see vgroups...). */ if (!data_dst) { return; } if (data_src) { - tmp_data_src = MEM_malloc_arrayN(tmp_buff_size, sizeof(*tmp_data_src), __func__); + tmp_data_src = (const void **)MEM_malloc_arrayN( + tmp_buff_size, sizeof(*tmp_data_src), __func__); } if (data_type & CD_FAKE) { @@ -4972,7 +5009,8 @@ void CustomData_data_transfer(const MeshPairRemap *me_remap, if (tmp_data_src) { if (UNLIKELY(sources_num > tmp_buff_size)) { tmp_buff_size = (size_t)sources_num; - tmp_data_src = MEM_reallocN((void *)tmp_data_src, sizeof(*tmp_data_src) * tmp_buff_size); + tmp_data_src = (const void **)MEM_reallocN((void *)tmp_data_src, + sizeof(*tmp_data_src) * tmp_buff_size); } for (int j = 0; j < sources_num; j++) { @@ -5044,28 +5082,29 @@ void CustomData_blend_write(BlendWriter *writer, if (layer->type == CD_MDEFORMVERT) { /* layer types that allocate own memory need special handling */ - BKE_defvert_blend_write(writer, count, layer->data); + BKE_defvert_blend_write(writer, count, static_cast<struct MDeformVert *>(layer->data)); } else if (layer->type == CD_MDISPS) { - write_mdisps(writer, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); + write_mdisps( + writer, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL); } else if (layer->type == CD_PAINT_MASK) { - const float *layer_data = layer->data; + const float *layer_data = static_cast<const float *>(layer->data); BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else if (layer->type == CD_SCULPT_FACE_SETS) { - const float *layer_data = layer->data; + const float *layer_data = static_cast<const float *>(layer->data); BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else if (layer->type == CD_GRID_PAINT_MASK) { - write_grid_paint_mask(writer, count, layer->data); + write_grid_paint_mask(writer, count, static_cast<GridPaintMask *>(layer->data)); } else if (layer->type == CD_FACEMAP) { - const int *layer_data = layer->data; + const int *layer_data = static_cast<const int *>(layer->data); BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else if (layer->type == CD_PROP_BOOL) { - const bool *layer_data = layer->data; + const bool *layer_data = static_cast<const bool *>(layer->data); BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } else { @@ -5138,7 +5177,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) /* Annoying workaround for bug T31079 loading legacy files with * no polygons _but_ have stale custom-data. */ - if (UNLIKELY(count == 0 && data->layers == NULL && data->totlayer != 0)) { + if (UNLIKELY(count == 0 && data->layers == nullptr && data->totlayer != 0)) { CustomData_reset(data); return; } @@ -5157,7 +5196,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); - if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) { + if (layer->data == nullptr && count > 0 && layer->type == CD_PROP_BOOL) { /* Usually this should never happen, except when a custom data layer has not been written * to a file correctly. */ CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly."); @@ -5168,10 +5207,11 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) } } if (layer->type == CD_MDISPS) { - blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); + blend_read_mdisps( + reader, count, static_cast<MDisps *>(layer->data), layer->flag & CD_FLAG_EXTERNAL); } else if (layer->type == CD_GRID_PAINT_MASK) { - blend_read_paint_mask(reader, count, layer->data); + blend_read_paint_mask(reader, count, static_cast<GridPaintMask *>(layer->data)); } i++; } diff --git a/source/blender/blenkernel/intern/data_transfer_intern.h b/source/blender/blenkernel/intern/data_transfer_intern.h index e40b4946f52..5510f699197 100644 --- a/source/blender/blenkernel/intern/data_transfer_intern.h +++ b/source/blender/blenkernel/intern/data_transfer_intern.h @@ -25,6 +25,10 @@ #include "BKE_customdata.h" /* For cd_datatransfer_interp */ +#ifdef __cplusplus +extern "C" { +#endif + struct CustomData; struct CustomDataTransferLayerMap; struct ListBase; @@ -78,3 +82,7 @@ void customdata_data_transfer_interp_normal_normals(const CustomDataTransferLaye const float *weights, const int count, const float mix_factor); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/intern/displist.cc b/source/blender/blenkernel/intern/displist.cc index edf043de63f..48bf24a0825 100644 --- a/source/blender/blenkernel/intern/displist.cc +++ b/source/blender/blenkernel/intern/displist.cc @@ -316,7 +316,7 @@ static void curve_to_displist(const Curve *cu, * and resolution > 1. */ const bool use_cyclic_sample = is_cyclic && (samples_len != 2); - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); /* Add one to the length because of 'BKE_curve_forward_diff_bezier'. */ dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * (samples_len + 1), __func__); BLI_addtail(r_dispbase, dl); @@ -371,7 +371,7 @@ static void curve_to_displist(const Curve *cu, } else if (nu->type == CU_NURBS) { const int len = (resolution * SEGMENTSU(nu)); - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__); BLI_addtail(r_dispbase, dl); dl->parts = 1; @@ -384,7 +384,7 @@ static void curve_to_displist(const Curve *cu, } else if (nu->type == CU_POLY) { const int len = nu->pntsu; - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__); BLI_addtail(r_dispbase, dl); dl->parts = 1; @@ -475,7 +475,7 @@ void BKE_displist_fill(const ListBase *dispbase, const int triangles_len = BLI_scanfill_calc_ex(&sf_ctx, scanfill_flag, normal_proj); if (totvert != 0 && triangles_len != 0) { - DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dlnew = MEM_cnew<DispList>(__func__); dlnew->type = DL_INDEX3; dlnew->flag = (dl_flag_accum & (DL_BACK_CURVE | DL_FRONT_CURVE)); dlnew->rt = (dl_rt_accum & CU_SMOOTH); @@ -530,7 +530,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase) if (dl->type == DL_SURF) { if ((dl->flag & DL_CYCL_V) && (dl->flag & DL_CYCL_U) == 0) { if ((cu->flag & CU_BACK) && (dl->flag & DL_BACK_CURVE)) { - DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dlnew = MEM_cnew<DispList>(__func__); BLI_addtail(&front, dlnew); dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__); dlnew->nr = dl->parts; @@ -549,7 +549,7 @@ static void bevels_to_filledpoly(const Curve *cu, ListBase *dispbase) } } if ((cu->flag & CU_FRONT) && (dl->flag & DL_FRONT_CURVE)) { - DispList *dlnew = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dlnew = MEM_cnew<DispList>(__func__); BLI_addtail(&back, dlnew); dlnew->verts = (float *)MEM_mallocN(sizeof(float[3]) * dl->parts, __func__); dlnew->nr = dl->parts; @@ -665,7 +665,7 @@ void BKE_displist_make_mball(Depsgraph *depsgraph, Scene *scene, Object *ob) BKE_displist_free(&(ob->runtime.curve_cache->disp)); } else { - ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__); + ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__); } BKE_mball_polygonize(depsgraph, scene, ob, &ob->runtime.curve_cache->disp); @@ -996,7 +996,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph, if (nu->pntsv == 1) { const int len = SEGMENTSU(nu) * resolu; - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__); BLI_addtail(r_dispbase, dl); @@ -1019,7 +1019,7 @@ static void evaluate_surface_object(Depsgraph *depsgraph, else { const int len = (nu->pntsu * resolu) * (nu->pntsv * resolv); - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = (float *)MEM_mallocN(len * sizeof(float[3]), __func__); BLI_addtail(r_dispbase, dl); @@ -1122,7 +1122,7 @@ static void fillBevelCap(const Nurb *nu, const float *prev_fp, ListBase *dispbase) { - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr, __func__); memcpy(dl->verts, prev_fp, sizeof(float[3]) * dlb->nr); @@ -1321,7 +1321,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph, /* exception handling; curve without bevel or extrude, with width correction */ if (BLI_listbase_is_empty(&dlbev)) { - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), "makeDispListbev"); + DispList *dl = MEM_cnew<DispList>("makeDispListbev"); dl->verts = (float *)MEM_mallocN(sizeof(float[3]) * bl->nr, "dlverts"); BLI_addtail(r_dispbase, dl); @@ -1371,7 +1371,7 @@ static GeometrySet evaluate_curve_type_object(Depsgraph *depsgraph, LISTBASE_FOREACH (DispList *, dlb, &dlbev) { /* for each part of the bevel use a separate displblock */ - DispList *dl = (DispList *)MEM_callocN(sizeof(DispList), __func__); + DispList *dl = MEM_cnew<DispList>(__func__); dl->verts = data = (float *)MEM_mallocN(sizeof(float[3]) * dlb->nr * steps, __func__); BLI_addtail(r_dispbase, dl); @@ -1495,7 +1495,7 @@ void BKE_displist_make_curveTypes(Depsgraph *depsgraph, BKE_object_free_derived_caches(ob); cow_curve.curve_eval = nullptr; - ob->runtime.curve_cache = (CurveCache *)MEM_callocN(sizeof(CurveCache), __func__); + ob->runtime.curve_cache = MEM_cnew<CurveCache>(__func__); ListBase *dispbase = &ob->runtime.curve_cache->disp; if (ob->type == OB_SURF) { diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 5bbfc0913a1..f7a547543af 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -412,7 +412,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, char *path = NULL; if (!adt && C) { - path = BKE_animdata_driver_path_hack(C, &tptr, prop, NULL); + path = RNA_path_from_ID_to_property(&tptr, prop); adt = BKE_animdata_from_id(tptr.owner_id); step--; } @@ -463,7 +463,7 @@ FCurve *BKE_fcurve_find_by_rna_context_ui(bContext *C, } if (step) { - char *tpath = BKE_animdata_driver_path_hack(C, &tptr, prop, path); + char *tpath = path ? path : RNA_path_from_ID_to_property(&tptr, prop); if (tpath && tpath != path) { MEM_freeN(path); path = tpath; diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index 5496519e53b..ce30f80ba65 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -29,6 +29,7 @@ #include "BLI_alloca.h" #include "BLI_expr_pylike_eval.h" +#include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_string_utils.h" #include "BLI_threads.h" @@ -864,6 +865,12 @@ void driver_variable_name_validate(DriverVar *dvar) } } +void driver_variable_unique_name(DriverVar *dvar) +{ + ListBase variables = BLI_listbase_from_link((Link *)dvar); + BLI_uniquename(&variables, dvar, dvar->name, '_', offsetof(DriverVar, name), sizeof(dvar->name)); +} + DriverVar *driver_add_new_variable(ChannelDriver *driver) { DriverVar *dvar; diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 93a7646fed0..b411c793298 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -17,6 +17,7 @@ #include <mutex> #include "BLI_float4x4.hh" +#include "BLI_index_mask.hh" #include "BLI_map.hh" #include "BLI_rand.hh" #include "BLI_set.hh" @@ -26,6 +27,8 @@ #include "DNA_collection_types.h" +#include "BKE_attribute_access.hh" +#include "BKE_attribute_math.hh" #include "BKE_geometry_set.hh" #include "BKE_geometry_set_instances.hh" @@ -34,6 +37,7 @@ #include "FN_cpp_type_make.hh" using blender::float4x4; +using blender::IndexMask; using blender::Map; using blender::MutableSpan; using blender::Set; @@ -132,6 +136,62 @@ blender::Span<InstanceReference> InstancesComponent::references() const return references_; } +template<typename T> +static void copy_data_based_on_mask(Span<T> src, MutableSpan<T> dst, IndexMask mask) +{ + BLI_assert(src.data() != dst.data()); + using namespace blender; + threading::parallel_for(mask.index_range(), 1024, [&](IndexRange range) { + for (const int i : range) { + dst[i] = src[mask[i]]; + } + }); +} + +void InstancesComponent::remove_instances(const IndexMask mask) +{ + using namespace blender; + if (mask.is_range() && mask.as_range().start() == 0) { + /* Deleting from the end of the array can be much faster since no data has to be shifted. */ + this->resize(mask.size()); + this->remove_unused_references(); + return; + } + + Vector<int> new_handles(mask.size()); + copy_data_based_on_mask<int>(this->instance_reference_handles(), new_handles, mask); + instance_reference_handles_ = std::move(new_handles); + Vector<float4x4> new_transforms(mask.size()); + copy_data_based_on_mask<float4x4>(this->instance_transforms(), new_transforms, mask); + instance_transforms_ = std::move(new_transforms); + + const bke::CustomDataAttributes &src_attributes = attributes_; + + bke::CustomDataAttributes dst_attributes; + dst_attributes.reallocate(mask.size()); + + src_attributes.foreach_attribute( + [&](const bke::AttributeIDRef &id, const AttributeMetaData &meta_data) { + if (!id.should_be_kept()) { + return true; + } + + GSpan src = *src_attributes.get_for_read(id); + dst_attributes.create(id, meta_data.data_type); + fn::GMutableSpan dst = *dst_attributes.get_for_write(id); + + attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { + using T = decltype(dummy); + copy_data_based_on_mask<T>(src.typed<T>(), dst.typed<T>(), mask); + }); + return true; + }, + ATTR_DOMAIN_INSTANCE); + + attributes_ = std::move(dst_attributes); + this->remove_unused_references(); +} + void InstancesComponent::remove_unused_references() { using namespace blender; diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index ef5609ec9a8..06e0e78745b 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -183,25 +183,27 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const return components; } -void GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const +bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const { + bool have_minmax = false; const PointCloud *pointcloud = this->get_pointcloud_for_read(); if (pointcloud != nullptr) { - BKE_pointcloud_minmax(pointcloud, *r_min, *r_max); + have_minmax |= BKE_pointcloud_minmax(pointcloud, *r_min, *r_max); } const Mesh *mesh = this->get_mesh_for_read(); if (mesh != nullptr) { - BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max); + have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max); } const Volume *volume = this->get_volume_for_read(); if (volume != nullptr) { - BKE_volume_min_max(volume, *r_min, *r_max); + have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max); } const CurveEval *curve = this->get_curve_for_read(); if (curve != nullptr) { /* Using the evaluated positions is somewhat arbitrary, but it is probably expected. */ - curve->bounds_min_max(*r_min, *r_max, true); + have_minmax |= curve->bounds_min_max(*r_min, *r_max, true); } + return have_minmax; } std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set) diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 4d84d5d899d..42d2211c360 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -69,9 +69,18 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) } /* Otherwise, construct a new geometry set with the component based on the object type. */ - GeometrySet geometry_set; if (object.type == OB_MESH) { + GeometrySet geometry_set; add_final_mesh_as_geometry_component(object, geometry_set); + return geometry_set; + } + if (object.type == OB_EMPTY && object.instance_collection != nullptr) { + GeometrySet geometry_set; + Collection &collection = *object.instance_collection; + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + const int handle = instances.add_reference(collection); + instances.add_instance(handle, float4x4::identity()); + return geometry_set; } /* TODO: Cover the case of point clouds without modifiers-- they may not be covered by the @@ -80,7 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) /* TODO: Add volume support. */ /* Return by value since there is not always an existing geometry set owned elsewhere to use. */ - return geometry_set; + return {}; } static void geometry_set_collect_recursive_collection_instance( @@ -98,13 +107,6 @@ static void geometry_set_collect_recursive_object(const Object &object, { GeometrySet instance_geometry_set = object_get_evaluated_geometry_set(object); geometry_set_collect_recursive(instance_geometry_set, transform, r_sets); - - if (object.type == OB_EMPTY) { - const Collection *collection_instance = object.instance_collection; - if (collection_instance != nullptr) { - geometry_set_collect_recursive_collection_instance(*collection_instance, transform, r_sets); - } - } } static void geometry_set_collect_recursive_collection(const Collection &collection, diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index b5190f598c6..f8681647a77 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -145,7 +145,7 @@ void BKE_gpencil_stroke_boundingbox_calc(bGPDstroke *gps) static void boundbox_gpencil(Object *ob) { if (ob->runtime.bb == nullptr) { - ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); + ob->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox"); } BoundBox *bb = ob->runtime.bb; @@ -182,7 +182,7 @@ BoundBox *BKE_gpencil_boundbox_get(Object *ob) * to keep both values synchronized. */ if (!ELEM(ob_orig, nullptr, ob)) { if (ob_orig->runtime.bb == nullptr) { - ob_orig->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "GPencil boundbox"); + ob_orig->runtime.bb = MEM_cnew<BoundBox>("GPencil boundbox"); } for (int i = 0; i < 8; i++) { copy_v3_v3(ob_orig->runtime.bb->vec[i], ob->runtime.bb->vec[i]); @@ -364,7 +364,7 @@ static void stroke_defvert_create_nr_list(MDeformVert *dv_list, } } if (!found) { - ld = (LinkData *)MEM_callocN(sizeof(LinkData), "def_nr_item"); + ld = MEM_cnew<LinkData>("def_nr_item"); ld->data = POINTER_FROM_INT(dw->def_nr); BLI_addtail(result, ld); tw++; @@ -3482,7 +3482,7 @@ struct tSampleEdge { /* Helper: creates a tSamplePoint from a bGPDspoint and (optionally) a MDeformVert. */ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const MDeformVert *dvert) { - tSamplePoint *new_pt = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); + tSamplePoint *new_pt = MEM_cnew<tSamplePoint>(__func__); copy_v3_v3(&new_pt->x, &pt->x); new_pt->pressure = pt->pressure; new_pt->strength = pt->strength; @@ -3505,7 +3505,7 @@ static tSamplePoint *new_sample_point_from_gp_point(const bGPDspoint *pt, const * the edge. */ static tSampleEdge *new_sample_edge_from_sample_points(tSamplePoint *from, tSamplePoint *to) { - tSampleEdge *new_edge = (tSampleEdge *)MEM_callocN(sizeof(tSampleEdge), __func__); + tSampleEdge *new_edge = MEM_cnew<tSampleEdge>(__func__); new_edge->from = from; new_edge->to = to; new_edge->length_sq = len_squared_v3v3(&from->x, &to->x); @@ -3561,7 +3561,7 @@ void BKE_gpencil_stroke_uniform_subdivide(bGPdata *gpd, tSamplePoint *sp_next = se->to; /* Subdivide the edge. */ - tSamplePoint *new_sp = (tSamplePoint *)MEM_callocN(sizeof(tSamplePoint), __func__); + tSamplePoint *new_sp = MEM_cnew<tSamplePoint>(__func__); interp_v3_v3v3(&new_sp->x, &sp->x, &sp_next->x, 0.5f); new_sp->pressure = interpf(sp->pressure, sp_next->pressure, 0.5f); new_sp->strength = interpf(sp->strength, sp_next->strength, 0.5f); @@ -3687,7 +3687,7 @@ struct tPerimeterPoint { static tPerimeterPoint *new_perimeter_point(const float pt[3]) { - tPerimeterPoint *new_pt = (tPerimeterPoint *)MEM_callocN(sizeof(tPerimeterPoint), __func__); + tPerimeterPoint *new_pt = MEM_cnew<tPerimeterPoint>(__func__); copy_v3_v3(&new_pt->x, pt); return new_pt; } @@ -3856,8 +3856,8 @@ static ListBase *gpencil_stroke_perimeter_ex(const bGPdata *gpd, float defaultpixsize = 1000.0f / gpd->pixfactor; float stroke_radius = ((gps->thickness + gpl->line_change) / defaultpixsize) / 2.0f; - ListBase *perimeter_right_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); - ListBase *perimeter_left_side = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); + ListBase *perimeter_right_side = MEM_cnew<ListBase>(__func__); + ListBase *perimeter_left_side = MEM_cnew<ListBase>(__func__); int num_perimeter_points = 0; bGPDspoint *first = &gps->points[0]; diff --git a/source/blender/blenkernel/intern/hair.c b/source/blender/blenkernel/intern/hair.cc index f2a5146422e..c5b154c9a4b 100644 --- a/source/blender/blenkernel/intern/hair.c +++ b/source/blender/blenkernel/intern/hair.cc @@ -18,6 +18,9 @@ * \ingroup bke */ +#include <cmath> +#include <cstring> + #include "MEM_guardedalloc.h" #include "DNA_defaults.h" @@ -25,8 +28,9 @@ #include "DNA_material_types.h" #include "DNA_object_types.h" +#include "BLI_float3.hh" #include "BLI_listbase.h" -#include "BLI_math.h" +#include "BLI_math_base.h" #include "BLI_rand.h" #include "BLI_string.h" #include "BLI_utildefines.h" @@ -49,6 +53,8 @@ #include "BLO_read_write.h" +using blender::float3; + static const char *HAIR_ATTR_POSITION = "position"; static const char *HAIR_ATTR_RADIUS = "radius"; @@ -67,10 +73,10 @@ static void hair_init_data(ID *id) CustomData_reset(&hair->cdata); CustomData_add_layer_named( - &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_POSITION); + &hair->pdata, CD_PROP_FLOAT3, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_POSITION); CustomData_add_layer_named( - &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, NULL, hair->totpoint, HAIR_ATTR_RADIUS); - CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, NULL, hair->totcurve); + &hair->pdata, CD_PROP_FLOAT, CD_CALLOC, nullptr, hair->totpoint, HAIR_ATTR_RADIUS); + CustomData_add_layer(&hair->cdata, CD_HAIRCURVE, CD_CALLOC, nullptr, hair->totcurve); BKE_hair_update_customdata_pointers(hair); hair_random(hair); @@ -80,14 +86,14 @@ static void hair_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, co { Hair *hair_dst = (Hair *)id_dst; const Hair *hair_src = (const Hair *)id_src; - hair_dst->mat = MEM_dupallocN(hair_src->mat); + hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat)); const eCDAllocType alloc_type = (flag & LIB_ID_COPY_CD_REFERENCE) ? CD_REFERENCE : CD_DUPLICATE; CustomData_copy(&hair_src->pdata, &hair_dst->pdata, CD_MASK_ALL, alloc_type, hair_dst->totpoint); CustomData_copy(&hair_src->cdata, &hair_dst->cdata, CD_MASK_ALL, alloc_type, hair_dst->totcurve); BKE_hair_update_customdata_pointers(hair_dst); - hair_dst->batch_cache = NULL; + hair_dst->batch_cache = nullptr; } static void hair_free_data(ID *id) @@ -115,8 +121,8 @@ static void hair_blend_write(BlendWriter *writer, ID *id, const void *id_address { Hair *hair = (Hair *)id; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *clayers = NULL, clayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *clayers = nullptr, clayers_buff[CD_TEMP_CHUNK_SIZE]; CustomData_blend_write_prepare(&hair->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); CustomData_blend_write_prepare(&hair->cdata, &clayers, clayers_buff, ARRAY_SIZE(clayers_buff)); @@ -174,33 +180,33 @@ static void hair_blend_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_HA = { - .id_code = ID_HA, - .id_filter = FILTER_ID_HA, - .main_listbase_index = INDEX_ID_HA, - .struct_size = sizeof(Hair), - .name = "Hair", - .name_plural = "hairs", - .translation_context = BLT_I18NCONTEXT_ID_HAIR, - .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, - .asset_type_info = NULL, - - .init_data = hair_init_data, - .copy_data = hair_copy_data, - .free_data = hair_free_data, - .make_local = NULL, - .foreach_id = hair_foreach_id, - .foreach_cache = NULL, - .foreach_path = NULL, - .owner_get = NULL, - - .blend_write = hair_blend_write, - .blend_read_data = hair_blend_read_data, - .blend_read_lib = hair_blend_read_lib, - .blend_read_expand = hair_blend_read_expand, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + /*id_code */ ID_HA, + /*id_filter */ FILTER_ID_HA, + /*main_listbase_index */ INDEX_ID_HA, + /*struct_size */ sizeof(Hair), + /*name */ "Hair", + /*name_plural */ "hairs", + /*translation_context */ BLT_I18NCONTEXT_ID_HAIR, + /*flags */ IDTYPE_FLAGS_APPEND_IS_REUSABLE, + /*asset_type_info */ nullptr, + + /*init_data */ hair_init_data, + /*copy_data */ hair_copy_data, + /*free_data */ hair_free_data, + /*make_local */ nullptr, + /*foreach_id */ hair_foreach_id, + /*foreach_cache */ nullptr, + /*foreach_path */ nullptr, + /*owner_get */ nullptr, + + /*blend_write */ hair_blend_write, + /*blend_read_data */ hair_blend_read_data, + /*blend_read_lib */ hair_blend_read_lib, + /*blend_read_expand */ hair_blend_read_expand, + + /*blend_read_undo_preserve */ nullptr, + + /*lib_override_apply_post */ nullptr, }; static void hair_random(Hair *hair) @@ -250,7 +256,7 @@ static void hair_random(Hair *hair) void *BKE_hair_add(Main *bmain, const char *name) { - Hair *hair = BKE_id_new(bmain, ID_HA, name); + Hair *hair = static_cast<Hair *>(BKE_id_new(bmain, ID_HA, name)); return hair; } @@ -258,14 +264,14 @@ void *BKE_hair_add(Main *bmain, const char *name) BoundBox *BKE_hair_boundbox_get(Object *ob) { BLI_assert(ob->type == OB_HAIR); - Hair *hair = ob->data; + Hair *hair = static_cast<Hair *>(ob->data); - if (ob->runtime.bb != NULL && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { + if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { return ob->runtime.bb; } - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_callocN(sizeof(BoundBox), "hair boundbox"); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); float min[3], max[3]; INIT_MINMAX(min, max); @@ -289,10 +295,12 @@ BoundBox *BKE_hair_boundbox_get(Object *ob) void BKE_hair_update_customdata_pointers(Hair *hair) { - hair->co = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION); - hair->radius = CustomData_get_layer_named(&hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS); - hair->curves = CustomData_get_layer(&hair->cdata, CD_HAIRCURVE); - hair->mapping = CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING); + hair->co = (float(*)[3])CustomData_get_layer_named( + &hair->pdata, CD_PROP_FLOAT3, HAIR_ATTR_POSITION); + hair->radius = (float *)CustomData_get_layer_named( + &hair->pdata, CD_PROP_FLOAT, HAIR_ATTR_RADIUS); + hair->curves = (HairCurve *)CustomData_get_layer(&hair->cdata, CD_HAIRCURVE); + hair->mapping = (HairMaping *)CustomData_get_layer(&hair->cdata, CD_HAIRMAPPING); } bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer) @@ -304,10 +312,10 @@ bool BKE_hair_customdata_required(Hair *UNUSED(hair), CustomDataLayer *layer) Hair *BKE_hair_new_for_eval(const Hair *hair_src, int totpoint, int totcurve) { - Hair *hair_dst = BKE_id_new_nomain(ID_HA, NULL); + Hair *hair_dst = static_cast<Hair *>(BKE_id_new_nomain(ID_HA, nullptr)); STRNCPY(hair_dst->id.name, hair_src->id.name); - hair_dst->mat = MEM_dupallocN(hair_src->mat); + hair_dst->mat = static_cast<Material **>(MEM_dupallocN(hair_src->mat)); hair_dst->totcol = hair_src->totcol; hair_dst->totpoint = totpoint; @@ -327,7 +335,7 @@ Hair *BKE_hair_copy_for_eval(Hair *hair_src, bool reference) flags |= LIB_ID_COPY_CD_REFERENCE; } - Hair *result = (Hair *)BKE_id_copy_ex(NULL, &hair_src->id, NULL, flags); + Hair *result = (Hair *)BKE_id_copy_ex(nullptr, &hair_src->id, nullptr, flags); return result; } @@ -351,7 +359,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph, /* Evaluate modifiers. */ for (; md; md = md->next) { - const ModifierTypeInfo *mti = BKE_modifier_get_info(md->type); + const ModifierTypeInfo *mti = BKE_modifier_get_info(static_cast<ModifierType>(md->type)); if (!BKE_modifier_is_enabled(scene, md, required_mode)) { continue; @@ -370,7 +378,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph, BKE_hair_update_customdata_pointers(hair); /* Created deformed coordinates array on demand. */ - mti->deformVerts(md, &mectx, NULL, hair->co, hair->totpoint); + mti->deformVerts(md, &mectx, nullptr, hair->co, hair->totpoint); } else if (mti->modifyHair) { /* Ensure we are not modifying the input. */ @@ -383,7 +391,7 @@ static Hair *hair_evaluate_modifiers(struct Depsgraph *depsgraph, if (hair_next && hair_next != hair) { /* If the modifier returned a new hair, release the old one. */ if (hair != hair_input) { - BKE_id_free(NULL, hair); + BKE_id_free(nullptr, hair); } hair = hair_next; } @@ -399,7 +407,7 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje BKE_object_free_derived_caches(object); /* Evaluate modifiers. */ - Hair *hair = object->data; + Hair *hair = static_cast<Hair *>(object->data); Hair *hair_eval = hair_evaluate_modifiers(depsgraph, scene, object, hair); /* Assign evaluated object. */ @@ -409,8 +417,8 @@ void BKE_hair_data_update(struct Depsgraph *depsgraph, struct Scene *scene, Obje /* Draw Cache */ -void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = NULL; -void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = NULL; +void (*BKE_hair_batch_cache_dirty_tag_cb)(Hair *hair, int mode) = nullptr; +void (*BKE_hair_batch_cache_free_cb)(Hair *hair) = nullptr; void BKE_hair_batch_cache_dirty_tag(Hair *hair, int mode) { diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index f43cf00a310..2d4366846aa 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -21,6 +21,7 @@ * \ingroup bke */ +#include <ctype.h> #include <fcntl.h> #include <math.h> #include <stdio.h> @@ -84,6 +85,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_packedFile.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -97,6 +99,7 @@ #include "SEQ_utils.h" /* SEQ_get_topmost_sequence() */ +#include "GPU_material.h" #include "GPU_texture.h" #include "BLI_sys_types.h" /* for intptr_t support */ @@ -270,7 +273,33 @@ static void image_foreach_path(ID *id, BPathForeachPathData *bpath_data) return; } - if (BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath)) { + /* If this is a tiled image, and we're asked to resolve the tokens in the virtual + * filepath, use the first tile to generate a concrete path for use during processing. */ + bool result = false; + if (ima->source == IMA_SRC_TILED && (flag & BKE_BPATH_FOREACH_PATH_RESOLVE_TOKEN) != 0) { + char temp_path[FILE_MAX], orig_file[FILE_MAXFILE]; + BLI_strncpy(temp_path, ima->filepath, sizeof(temp_path)); + BLI_split_file_part(temp_path, orig_file, sizeof(orig_file)); + + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(temp_path, &tile_format); + BKE_image_set_filepath_from_tile_number( + temp_path, udim_pattern, tile_format, ((ImageTile *)ima->tiles.first)->tile_number); + MEM_SAFE_FREE(udim_pattern); + + result = BKE_bpath_foreach_path_fixed_process(bpath_data, temp_path); + if (result) { + /* Put the filepath back together using the new directory and the original file name. */ + char new_dir[FILE_MAXDIR]; + BLI_split_dir_part(temp_path, new_dir, sizeof(new_dir)); + BLI_join_dirfile(ima->filepath, sizeof(ima->filepath), new_dir, orig_file); + } + } + else { + result = BKE_bpath_foreach_path_fixed_process(bpath_data, ima->filepath); + } + + if (result) { if (flag & BKE_BPATH_FOREACH_PATH_RELOAD_EDITED) { if (!BKE_image_has_packedfile(ima) && /* Image may have been painted onto (and not saved, T44543). */ @@ -886,9 +915,13 @@ Image *BKE_image_load(Main *bmain, const char *filepath) /* exists? */ file = BLI_open(str, O_BINARY | O_RDONLY, 0); if (file == -1) { - return NULL; + if (!BKE_image_tile_filepath_exists(str)) { + return NULL; + } + } + else { + close(file); } - close(file); ima = image_alloc(bmain, BLI_path_basename(filepath), IMA_SRC_FILE, IMA_TYPE_IMAGE); STRNCPY(ima->filepath, filepath); @@ -3363,6 +3396,23 @@ static void image_walk_ntree_all_users( } } +static void image_walk_gpu_materials( + ID *id, + ListBase *gpu_materials, + void *customdata, + void callback(Image *ima, ID *iuser_id, ImageUser *iuser, void *customdata)) +{ + LISTBASE_FOREACH (LinkData *, link, gpu_materials) { + GPUMaterial *gpu_material = (GPUMaterial *)link->data; + ListBase textures = GPU_material_textures(gpu_material); + LISTBASE_FOREACH (GPUMaterialTexture *, gpu_material_texture, &textures) { + if (gpu_material_texture->iuser_available) { + callback(gpu_material_texture->ima, id, &gpu_material_texture->iuser, customdata); + } + } + } +} + static void image_walk_id_all_users( ID *id, bool skip_nested_nodes, @@ -3382,6 +3432,7 @@ static void image_walk_id_all_users( if (ma->nodetree && ma->use_nodes && !skip_nested_nodes) { image_walk_ntree_all_users(ma->nodetree, &ma->id, customdata, callback); } + image_walk_gpu_materials(id, &ma->gpumaterial, customdata, callback); break; } case ID_LA: { @@ -3396,6 +3447,7 @@ static void image_walk_id_all_users( if (world->nodetree && world->use_nodes && !skip_nested_nodes) { image_walk_ntree_all_users(world->nodetree, &world->id, customdata, callback); } + image_walk_gpu_materials(id, &world->gpumaterial, customdata, callback); break; } case ID_TE: { @@ -3678,6 +3730,43 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) BKE_image_free_buffers(ima); } + if (ima->source == IMA_SRC_TILED) { + ListBase new_tiles = {NULL, NULL}; + int new_start, new_range; + + char filepath[FILE_MAX]; + BLI_strncpy(filepath, ima->filepath, sizeof(filepath)); + BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); + bool result = BKE_image_get_tile_info(filepath, &new_tiles, &new_start, &new_range); + if (result) { + /* Because the prior and new list of tiles are both sparse sequences, we need to be sure + * to account for how the two sets might or might not overlap. To be complete, we start + * the refresh process by clearing all existing tiles, stopping when there's only 1 tile + * left. */ + while (BKE_image_remove_tile(ima, ima->tiles.last)) { + ; + } + + int remaining_tile_number = ((ImageTile *)ima->tiles.first)->tile_number; + bool needs_final_cleanup = true; + + /* Add in all the new tiles. */ + LISTBASE_FOREACH (LinkData *, new_tile, &new_tiles) { + int new_tile_number = POINTER_AS_INT(new_tile->data); + BKE_image_add_tile(ima, new_tile_number, NULL); + if (new_tile_number == remaining_tile_number) { + needs_final_cleanup = false; + } + } + + /* Final cleanup if the prior remaining tile was never encountered in the new list. */ + if (needs_final_cleanup) { + BKE_image_remove_tile(ima, BKE_image_get_tile(ima, remaining_tile_number)); + } + } + BLI_freelistN(&new_tiles); + } + if (iuser) { image_tag_reload(ima, NULL, iuser, ima); } @@ -3699,16 +3788,8 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) BLI_mutex_unlock(ima->runtime.cache_mutex); - /* don't use notifiers because they are not 100% sure to succeeded - * this also makes sure all scenes are accounted for. */ - { - Scene *scene; - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->nodetree) { - nodeUpdateID(scene->nodetree, &ima->id); - } - } - } + BKE_ntree_update_tag_id_changed(bmain, &ima->id); + BKE_ntree_update_main(bmain, NULL); } /* return renderpass for a given pass index and active view */ @@ -3769,6 +3850,57 @@ void BKE_image_get_tile_label(Image *ima, ImageTile *tile, char *label, int len_ } } +bool BKE_image_get_tile_info(char *filepath, + ListBase *udim_tiles, + int *udim_start, + int *udim_range) +{ + char filename[FILE_MAXFILE], dirname[FILE_MAXDIR]; + BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); + + BKE_image_ensure_tile_token(filename); + + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(filename, &tile_format); + + bool is_udim = true; + int min_udim = IMA_UDIM_MAX + 1; + int max_udim = 0; + int id; + + struct direntry *dir; + uint totfile = BLI_filelist_dir_contents(dirname, &dir); + for (int i = 0; i < totfile; i++) { + if (!(dir[i].type & S_IFREG)) { + continue; + } + + if (!BKE_image_get_tile_number_from_filepath(dir[i].relname, udim_pattern, tile_format, &id)) { + continue; + } + + if (id < 1001 || id > IMA_UDIM_MAX) { + is_udim = false; + break; + } + + BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id))); + min_udim = min_ii(min_udim, id); + max_udim = max_ii(max_udim, id); + } + BLI_filelist_free(dir, totfile); + MEM_SAFE_FREE(udim_pattern); + + if (is_udim && min_udim <= IMA_UDIM_MAX) { + BLI_join_dirfile(filepath, FILE_MAX, dirname, filename); + + *udim_start = min_udim; + *udim_range = max_udim - min_udim + 1; + return true; + } + return false; +} + ImageTile *BKE_image_add_tile(struct Image *ima, int tile_number, const char *label) { if (ima->source != IMA_SRC_TILED) { @@ -3928,6 +4060,185 @@ bool BKE_image_fill_tile(struct Image *ima, return false; } +void BKE_image_ensure_tile_token(char *filename) +{ + if (filename == NULL) { + return; + } + + /* Is there a '<' character in the filename? Assume tokens already present. */ + if (strstr(filename, "<") != NULL) { + return; + } + + /* Is there a sequence of digits in the filename? */ + ushort digits; + char head[FILE_MAX], tail[FILE_MAX]; + BLI_path_sequence_decode(filename, head, tail, &digits); + if (digits == 4) { + sprintf(filename, "%s<UDIM>%s", head, tail); + return; + } + + /* Is there a sequence like u##_v#### in the filename? */ + uint cur = 0; + uint name_end = strlen(filename); + uint u_digits = 0; + uint v_digits = 0; + uint u_start = (uint)-1; + bool u_found = false; + bool v_found = false; + bool sep_found = false; + while (cur < name_end) { + if (filename[cur] == 'u') { + u_found = true; + u_digits = 0; + u_start = cur; + } + else if (filename[cur] == 'v') { + v_found = true; + v_digits = 0; + } + else if (u_found && !v_found) { + if (isdigit(filename[cur]) && u_digits < 2) { + u_digits++; + } + else if (filename[cur] == '_') { + sep_found = true; + } + else { + u_found = false; + } + } + else if (u_found && u_digits > 0 && v_found) { + if (isdigit(filename[cur])) { + if (v_digits < 4) { + v_digits++; + } + else { + u_found = false; + v_found = false; + } + } + else if (v_digits > 0) { + break; + } + } + + cur++; + } + + if (u_found && sep_found && v_found && (u_digits + v_digits > 1)) { + const char *token = "<UVTILE>"; + const size_t token_length = strlen(token); + memmove(filename + u_start + token_length, filename + cur, name_end - cur); + memcpy(filename + u_start, token, token_length); + filename[u_start + token_length + (name_end - cur)] = '\0'; + } +} + +bool BKE_image_tile_filepath_exists(const char *filepath) +{ + BLI_assert(!BLI_path_is_rel(filepath)); + + char dirname[FILE_MAXDIR]; + BLI_split_dir_part(filepath, dirname, sizeof(dirname)); + + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format); + + bool found = false; + struct direntry *dir; + uint totfile = BLI_filelist_dir_contents(dirname, &dir); + for (int i = 0; i < totfile; i++) { + if (!(dir[i].type & S_IFREG)) { + continue; + } + + int id; + if (!BKE_image_get_tile_number_from_filepath(dir[i].path, udim_pattern, tile_format, &id)) { + continue; + } + + if (id < 1001 || id > IMA_UDIM_MAX) { + continue; + } + + found = true; + break; + } + BLI_filelist_free(dir, totfile); + MEM_SAFE_FREE(udim_pattern); + + return found; +} + +char *BKE_image_get_tile_strformat(const char *filepath, eUDIM_TILE_FORMAT *r_tile_format) +{ + if (filepath == NULL || r_tile_format == NULL) { + return NULL; + } + + if (strstr(filepath, "<UDIM>") != NULL) { + *r_tile_format = UDIM_TILE_FORMAT_UDIM; + return BLI_str_replaceN(filepath, "<UDIM>", "%d"); + } + if (strstr(filepath, "<UVTILE>") != NULL) { + *r_tile_format = UDIM_TILE_FORMAT_UVTILE; + return BLI_str_replaceN(filepath, "<UVTILE>", "u%d_v%d"); + } + + *r_tile_format = UDIM_TILE_FORMAT_NONE; + return NULL; +} + +bool BKE_image_get_tile_number_from_filepath(const char *filepath, + const char *pattern, + eUDIM_TILE_FORMAT tile_format, + int *r_tile_number) +{ + if (filepath == NULL || pattern == NULL || r_tile_number == NULL) { + return false; + } + + int u, v; + bool result = false; + + if (tile_format == UDIM_TILE_FORMAT_UDIM) { + if (sscanf(filepath, pattern, &u) == 1) { + *r_tile_number = u; + result = true; + } + } + else if (tile_format == UDIM_TILE_FORMAT_UVTILE) { + if (sscanf(filepath, pattern, &u, &v) == 2) { + *r_tile_number = 1001 + (u - 1) + ((v - 1) * 10); + result = true; + } + } + + return result; +} + +void BKE_image_set_filepath_from_tile_number(char *filepath, + const char *pattern, + eUDIM_TILE_FORMAT tile_format, + int tile_number) +{ + if (filepath == NULL || pattern == NULL) { + return; + } + + if (tile_format == UDIM_TILE_FORMAT_UDIM) { + sprintf(filepath, pattern, tile_number); + } + else if (tile_format == UDIM_TILE_FORMAT_UVTILE) { + int u = ((tile_number - 1001) % 10); + int v = ((tile_number - 1001) / 10); + sprintf(filepath, pattern, u + 1, v + 1); + } +} + /* if layer or pass changes, we need an index for the imbufs list */ /* note it is called for rendered results, but it doesn't use the index! */ RenderPass *BKE_image_multilayer_index(RenderResult *rr, ImageUser *iuser) @@ -5500,6 +5811,11 @@ void BKE_image_user_id_eval_animation(Depsgraph *depsgraph, ID *id) void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) { + BKE_image_user_file_path_ex(iuser, ima, filepath, true); +} + +void BKE_image_user_file_path_ex(ImageUser *iuser, Image *ima, char *filepath, bool resolve_udim) +{ if (BKE_image_is_multiview(ima)) { ImageView *iv = BLI_findlink(&ima->views, iuser->view); if (iv->filepath[0]) { @@ -5520,13 +5836,17 @@ void BKE_image_user_file_path(ImageUser *iuser, Image *ima, char *filepath) int index; if (ima->source == IMA_SRC_SEQUENCE) { index = iuser ? iuser->framenr : ima->lastframe; + BLI_path_sequence_decode(filepath, head, tail, &numlen); + BLI_path_sequence_encode(filepath, head, tail, numlen, index); } - else { + else if (resolve_udim) { index = image_get_tile_number_from_iuser(ima, iuser); - } - BLI_path_sequence_decode(filepath, head, tail, &numlen); - BLI_path_sequence_encode(filepath, head, tail, numlen, index); + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = BKE_image_get_tile_strformat(filepath, &tile_format); + BKE_image_set_filepath_from_tile_number(filepath, udim_pattern, tile_format, index); + MEM_SAFE_FREE(udim_pattern); + } } BLI_path_abs(filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); diff --git a/source/blender/blenkernel/intern/image_gpu.cc b/source/blender/blenkernel/intern/image_gpu.cc index 4440e4b101a..c82de02e52a 100644 --- a/source/blender/blenkernel/intern/image_gpu.cc +++ b/source/blender/blenkernel/intern/image_gpu.cc @@ -172,7 +172,7 @@ static GPUTexture *gpu_texture_create_tile_array(Image *ima, ImBuf *ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr); if (ibuf) { - PackTile *packtile = (PackTile *)MEM_callocN(sizeof(PackTile), __func__); + PackTile *packtile = MEM_cnew<PackTile>(__func__); packtile->tile = tile; packtile->boxpack.w = ibuf->x; packtile->boxpack.h = ibuf->y; diff --git a/source/blender/blenkernel/intern/image_save.c b/source/blender/blenkernel/intern/image_save.c index f93ede517a9..329bc7b498b 100644 --- a/source/blender/blenkernel/intern/image_save.c +++ b/source/blender/blenkernel/intern/image_save.c @@ -30,6 +30,8 @@ #include "DNA_image_types.h" +#include "MEM_guardedalloc.h" + #include "IMB_colormanagement.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -402,15 +404,17 @@ bool BKE_image_save( bool colorspace_changed = false; + eUDIM_TILE_FORMAT tile_format; + char *udim_pattern = NULL; + if (ima->source == IMA_SRC_TILED) { - /* Verify filepath for tiles images. */ - ImageTile *first_tile = ima->tiles.first; - if (BLI_path_sequence_decode(opts->filepath, NULL, NULL, NULL) != first_tile->tile_number) { + /* Verify filepath for tiled images contains a valid UDIM marker. */ + udim_pattern = BKE_image_get_tile_strformat(opts->filepath, &tile_format); + if (tile_format == UDIM_TILE_FORMAT_NONE) { BKE_reportf(reports, RPT_ERROR, - "When saving a tiled image, the path '%s' must contain the UDIM tile number %d", - opts->filepath, - first_tile->tile_number); + "When saving a tiled image, the path '%s' must contain a valid UDIM marker", + opts->filepath); return false; } @@ -420,36 +424,29 @@ bool BKE_image_save( } } - /* Save image - or, for tiled images, the first tile. */ - bool ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed); - - if (ok && ima->source == IMA_SRC_TILED) { + /* Save images */ + bool ok = false; + if (ima->source != IMA_SRC_TILED) { + ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed); + } + else { char filepath[FILE_MAX]; BLI_strncpy(filepath, opts->filepath, sizeof(filepath)); - char head[FILE_MAX], tail[FILE_MAX]; - unsigned short numlen; - BLI_path_sequence_decode(filepath, head, tail, &numlen); - - /* Save all other tiles. */ - int index; - LISTBASE_FOREACH_INDEX (ImageTile *, tile, &ima->tiles, index) { - /* First tile was already saved before the loop. */ - if (index == 0) { - continue; - } + /* Save all the tiles. */ + LISTBASE_FOREACH (ImageTile *, tile, &ima->tiles) { + BKE_image_set_filepath_from_tile_number( + opts->filepath, udim_pattern, tile_format, tile->tile_number); + iuser->tile = tile->tile_number; + ok = image_save_single(reports, ima, iuser, opts, &colorspace_changed); if (!ok) { - continue; + break; } - - /* Build filepath of the tile. */ - BLI_path_sequence_encode(opts->filepath, head, tail, numlen, tile->tile_number); - - iuser->tile = tile->tile_number; - ok = ok && image_save_single(reports, ima, iuser, opts, &colorspace_changed); } + BLI_strncpy(ima->filepath, filepath, sizeof(ima->filepath)); BLI_strncpy(opts->filepath, filepath, sizeof(opts->filepath)); + MEM_freeN(udim_pattern); } if (colorspace_changed) { diff --git a/source/blender/blenkernel/intern/layer.c b/source/blender/blenkernel/intern/layer.c index 1484d35f28a..c58820b239b 100644 --- a/source/blender/blenkernel/intern/layer.c +++ b/source/blender/blenkernel/intern/layer.c @@ -343,7 +343,7 @@ ViewLayer *BKE_view_layer_find_from_collection(const Scene *scene, LayerCollecti /* Base */ -static void view_layer_bases_hash_create(ViewLayer *view_layer) +static void view_layer_bases_hash_create(ViewLayer *view_layer, const bool do_base_duplicates_fix) { static ThreadMutex hash_lock = BLI_MUTEX_INITIALIZER; @@ -353,15 +353,29 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer) if (view_layer->object_bases_hash == NULL) { GHash *hash = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - LISTBASE_FOREACH (Base *, base, &view_layer->object_bases) { + LISTBASE_FOREACH_MUTABLE (Base *, base, &view_layer->object_bases) { if (base->object) { - /* Some processes, like ID remapping, may lead to having several bases with the same - * object. So just take the first one here, and ignore all others - * (#BKE_layer_collection_sync will clean this up anyway). */ void **val_pp; if (!BLI_ghash_ensure_p(hash, base->object, &val_pp)) { *val_pp = base; } + /* The same object has several bases. + * + * In normal cases this is a serious bug, but this is a common situation when remapping + * an object into another one already present in the same View Layer. While ideally we + * would process this case separately, for performances reasons it makes more sense to + * tackle it here. */ + else if (do_base_duplicates_fix) { + if (view_layer->basact == base) { + view_layer->basact = NULL; + } + BLI_freelinkN(&view_layer->object_bases, base); + } + else { + CLOG_FATAL(&LOG, + "Object '%s' has more than one entry in view layer's object bases listbase", + base->object->id.name + 2); + } } } @@ -376,7 +390,7 @@ static void view_layer_bases_hash_create(ViewLayer *view_layer) Base *BKE_view_layer_base_find(ViewLayer *view_layer, Object *ob) { if (!view_layer->object_bases_hash) { - view_layer_bases_hash_create(view_layer); + view_layer_bases_hash_create(view_layer, false); } return BLI_ghash_lookup(view_layer->object_bases_hash, ob); @@ -1204,7 +1218,7 @@ void BKE_layer_collection_sync(const Scene *scene, ViewLayer *view_layer) /* Create object to base hash if it does not exist yet. */ if (!view_layer->object_bases_hash) { - view_layer_bases_hash_create(view_layer); + view_layer_bases_hash_create(view_layer, false); } /* Clear visible and selectable flags to be reset. */ @@ -1317,6 +1331,11 @@ void BKE_main_collection_sync_remap(const Main *bmain) if (view_layer->object_bases_hash) { BLI_ghash_free(view_layer->object_bases_hash, NULL, NULL); view_layer->object_bases_hash = NULL; + + /* Directly re-create the mapping here, so that we can also deal with duplicates in + * `view_layer->object_bases` list of bases properly. This is the only place where such + * duplicates should be fixed, and not considered as a critical error. */ + view_layer_bases_hash_create(view_layer, true); } } diff --git a/source/blender/blenkernel/intern/lib_id_delete.c b/source/blender/blenkernel/intern/lib_id_delete.c index 1922a54addb..6d2e89187f7 100644 --- a/source/blender/blenkernel/intern/lib_id_delete.c +++ b/source/blender/blenkernel/intern/lib_id_delete.c @@ -350,6 +350,9 @@ static size_t id_delete(Main *bmain, const bool do_tagged_deletion) void BKE_id_delete(Main *bmain, void *idv) { + BLI_assert_msg((((ID *)idv)->tag & LIB_TAG_NO_MAIN) == 0, + "Cannot be used with IDs outside of Main"); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); ((ID *)idv)->tag |= LIB_TAG_DOIT; diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 83ed0ee4c08..81c290589a6 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -470,8 +470,9 @@ static void lib_override_group_tag_data_object_to_collection_init_collection_pro } LinkNodePair **collections_linkedlist_p; - if (!BLI_ghash_ensure_p( - data->linked_object_to_instantiating_collections, ob, &collections_linkedlist_p)) { + if (!BLI_ghash_ensure_p(data->linked_object_to_instantiating_collections, + ob, + (void ***)&collections_linkedlist_p)) { *collections_linkedlist_p = BLI_memarena_calloc(data->mem_arena, sizeof(**collections_linkedlist_p)); } @@ -611,6 +612,42 @@ static void lib_override_linked_group_tag_recursive(LibOverrideGroupTagData *dat } } +static void lib_override_linked_group_tag_clear_boneshapes_objects(LibOverrideGroupTagData *data) +{ + Main *bmain = data->bmain; + + /* Remove (untag) bone shape objects, they shall never need to be to directly/explicitly + * overridden. */ + LISTBASE_FOREACH (Object *, ob, &bmain->objects) { + if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) { + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { + if (pchan->custom != NULL) { + pchan->custom->id.tag &= ~data->tag; + } + } + } + } + + /* Remove (untag) collections if they do not own any tagged object (either themselves, or in + * their children collections). */ + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if ((collection->id.tag & data->tag) == 0) { + continue; + } + bool keep_tagged = false; + const ListBase object_bases = BKE_collection_object_cache_get(collection); + LISTBASE_FOREACH (Base *, base, &object_bases) { + if ((base->object->id.tag & data->tag) != 0) { + keep_tagged = true; + break; + } + } + if (!keep_tagged) { + collection->id.tag &= ~data->tag; + } + } +} + /* This will tag at least all 'boundary' linked IDs for a potential override group. * * Requires existing `Main.relations`. @@ -639,17 +676,8 @@ static void lib_override_linked_group_tag(LibOverrideGroupTagData *data) /* Tag all collections and objects. */ lib_override_linked_group_tag_recursive(data); - /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly - * override those. */ - LISTBASE_FOREACH (Object *, ob, &bmain->objects) { - if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & data->tag)) { - for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan != NULL; pchan = pchan->next) { - if (pchan->custom != NULL) { - pchan->custom->id.tag &= ~(data->tag | data->missing_tag); - } - } - } - } + /* Do not override objects used as bone shapes, nor their collections if possible. */ + lib_override_linked_group_tag_clear_boneshapes_objects(data); /* For each object tagged for override, ensure we get at least one local or liboverride * collection to host it. Avoids getting a bunch of random object in the scene's master diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4ad0186f9b5..1f20a84098c 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -439,7 +439,7 @@ bool BKE_library_id_can_use_idtype(ID *id_owner, const short id_type_used) case ID_LA: return (ELEM(id_type_used, ID_TE)); case ID_CA: - return ELEM(id_type_used, ID_OB); + return ELEM(id_type_used, ID_OB, ID_IM); case ID_KE: /* Warning! key->from, could be more types in future? */ return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 3cea0de32ee..b8e0eb2c942 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -282,6 +282,11 @@ static void libblock_remap_data_postprocess_object_update(Main *bmain, * to remove the NULL children from collections not used in any scene. */ BKE_collections_object_remove_nulls(bmain); } + else { + /* Remapping may have created duplicates of CollectionObject pointing to the same object within + * the same collection. */ + BKE_collections_object_remove_duplicates(bmain); + } BKE_main_collection_sync_remap(bmain); @@ -319,6 +324,7 @@ static void libblock_remap_data_postprocess_collection_update(Main *bmain, else { /* Temp safe fix, but a "tad" brute force... We should probably be able to use parents from * old_collection instead? */ + /* NOTE: Also takes care of duplicated child collections that remapping may have created. */ BKE_main_collections_parent_relations_rebuild(bmain); } @@ -346,7 +352,7 @@ static void libblock_remap_data_postprocess_obdata_relink(Main *bmain, Object *o static void libblock_remap_data_postprocess_nodetree_update(Main *bmain, ID *new_id) { /* Update all group nodes using a node group. */ - ntreeUpdateAllUsers(bmain, new_id, 0); + ntreeUpdateAllUsers(bmain, new_id); } /** diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index ac0dbcb715d..95f41ab4b39 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -50,6 +50,7 @@ #include "BKE_linestyle.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_texture.h" #include "BLO_read_write.h" @@ -2085,5 +2086,5 @@ void BKE_linestyle_default_shader(const bContext *C, FreestyleLineStyle *linesty tosock = BLI_findlink(&output_linestyle->inputs, 0); /* Color */ nodeAddLink(ntree, input_texure, fromsock, output_linestyle, tosock); - ntreeUpdateTree(CTX_data_main(C), ntree); + BKE_ntree_update_main_tree(CTX_data_main(C), ntree, NULL); } diff --git a/source/blender/blenkernel/intern/mesh.cc b/source/blender/blenkernel/intern/mesh.cc index 05aa9111fa3..12c63ab0523 100644 --- a/source/blender/blenkernel/intern/mesh.cc +++ b/source/blender/blenkernel/intern/mesh.cc @@ -36,13 +36,16 @@ #include "BLI_bitmap.h" #include "BLI_edgehash.h" #include "BLI_endian_switch.h" +#include "BLI_float3.hh" #include "BLI_ghash.h" #include "BLI_hash.h" +#include "BLI_index_range.hh" #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_memarena.h" #include "BLI_string.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "BLT_translation.h" @@ -453,14 +456,14 @@ static int customdata_compare( for (int i = 0; i < c1->totlayer; i++) { l1 = &c1->layers[i]; - if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l1->anonymous_id != nullptr) { + if ((CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr) && l1->anonymous_id == nullptr) { layer_count1++; } } for (int i = 0; i < c2->totlayer; i++) { l2 = &c2->layers[i]; - if (CD_TYPE_AS_MASK(l1->type) & cd_mask_all_attr && l2->anonymous_id != nullptr) { + if ((CD_TYPE_AS_MASK(l2->type) & cd_mask_all_attr) && l2->anonymous_id == nullptr) { layer_count2++; } } @@ -1577,13 +1580,35 @@ void BKE_mesh_looptri_get_real_edges(const Mesh *mesh, const MLoopTri *looptri, bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) { - int i = me->totvert; - MVert *mvert; - for (mvert = me->mvert; i--; mvert++) { - minmax_v3v3_v3(r_min, r_max, mvert->co); + using namespace blender; + if (me->totvert == 0) { + return false; } - return (me->totvert != 0); + struct Result { + float3 min; + float3 max; + }; + + const Result minmax = threading::parallel_reduce( + IndexRange(me->totvert), + 1024, + Result{float3(FLT_MAX), float3(-FLT_MAX)}, + [&](IndexRange range, const Result &init) { + Result result = init; + for (const int i : range) { + float3::min_max(me->mvert[i].co, result.min, result.max); + } + return result; + }, + [](const Result &a, const Result &b) { + return Result{float3::min(a.min, b.min), float3::max(a.max, b.max)}; + }); + + copy_v3_v3(r_min, float3::min(minmax.min, r_min)); + copy_v3_v3(r_max, float3::max(minmax.max, r_max)); + + return true; } void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) diff --git a/source/blender/blenkernel/intern/mesh_convert.cc b/source/blender/blenkernel/intern/mesh_convert.cc index e8054884f26..12fa9d16fd1 100644 --- a/source/blender/blenkernel/intern/mesh_convert.cc +++ b/source/blender/blenkernel/intern/mesh_convert.cc @@ -589,14 +589,14 @@ struct VertLink { static void prependPolyLineVert(ListBase *lb, uint index) { - VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink"); + VertLink *vl = MEM_cnew<VertLink>("VertLink"); vl->index = index; BLI_addhead(lb, vl); } static void appendPolyLineVert(ListBase *lb, uint index) { - VertLink *vl = (VertLink *)MEM_callocN(sizeof(VertLink), "VertLink"); + VertLink *vl = MEM_cnew<VertLink>("VertLink"); vl->index = index; BLI_addtail(lb, vl); } @@ -632,7 +632,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed med = medge; for (i = 0; i < medge_len; i++, med++) { if (edge_users[i] == edge_users_test) { - EdgeLink *edl = (EdgeLink *)MEM_callocN(sizeof(EdgeLink), "EdgeLink"); + EdgeLink *edl = MEM_cnew<EdgeLink>("EdgeLink"); edl->edge = med; BLI_addtail(&edges, edl); @@ -719,7 +719,7 @@ void BKE_mesh_to_curve_nurblist(const Mesh *me, ListBase *nurblist, const int ed VertLink *vl; /* create new 'nurb' within the curve */ - nu = (Nurb *)MEM_callocN(sizeof(Nurb), "MeshNurb"); + nu = MEM_cnew<Nurb>("MeshNurb"); nu->pntsu = totpoly; nu->pntsv = 1; @@ -901,6 +901,20 @@ static Object *object_for_curve_to_mesh_create(const Object *object) return temp_object; } +static void object_for_curve_to_mesh_free(Object *temp_object) +{ + /* Clear edit mode pointers that were explicitly copied to the temporary curve. */ + ID *final_object_data = static_cast<ID *>(temp_object->data); + if (GS(final_object_data->name) == ID_CU) { + Curve &curve = *reinterpret_cast<Curve *>(final_object_data); + curve.editfont = nullptr; + curve.editnurb = nullptr; + } + + BKE_id_free(nullptr, temp_object->data); + BKE_id_free(nullptr, temp_object); +} + /** * Populate `object->runtime.curve_cache` which is then used to create the mesh. */ @@ -917,7 +931,7 @@ static void curve_to_mesh_eval_ensure(Object &object) * will have no modifiers. */ Object bevel_object = {{nullptr}}; if (curve.bevobj != nullptr) { - bevel_object = *curve.bevobj; + memcpy(&bevel_object, curve.bevobj, sizeof(bevel_object)); BLI_listbase_clear(&bevel_object.modifiers); BKE_object_runtime_reset(&bevel_object); curve.bevobj = &bevel_object; @@ -926,7 +940,7 @@ static void curve_to_mesh_eval_ensure(Object &object) /* Same thing for taper. */ Object taper_object = {{nullptr}}; if (curve.taperobj != nullptr) { - taper_object = *curve.taperobj; + memcpy(&taper_object, curve.taperobj, sizeof(taper_object)); BLI_listbase_clear(&taper_object.modifiers); BKE_object_runtime_reset(&taper_object); curve.taperobj = &taper_object; @@ -1003,8 +1017,7 @@ static Mesh *mesh_new_from_curve_type_object(const Object *object) Mesh *mesh = mesh_new_from_evaluated_curve_type_object(temp_object); - BKE_id_free(nullptr, temp_object->data); - BKE_id_free(nullptr, temp_object); + object_for_curve_to_mesh_free(temp_object); return mesh; } @@ -1065,7 +1078,8 @@ static Mesh *mesh_new_from_mesh_object_with_layers(Depsgraph *depsgraph, return nullptr; } - Object object_for_eval = *object; + Object object_for_eval; + memcpy(&object_for_eval, object, sizeof(object_for_eval)); if (object_for_eval.runtime.data_orig != nullptr) { object_for_eval.data = object_for_eval.runtime.data_orig; } @@ -1440,7 +1454,8 @@ void BKE_mesh_nomain_to_mesh(Mesh *mesh_src, /* mesh_src might depend on mesh_dst, so we need to do everything with a local copy */ /* TODO(Sybren): the above claim came from 2.7x derived-mesh code (DM_to_mesh); * check whether it is still true with Mesh */ - Mesh tmp = *mesh_dst; + Mesh tmp; + memcpy(&tmp, mesh_dst, sizeof(tmp)); int totvert, totedge /*, totface */ /* UNUSED */, totloop, totpoly; bool did_shapekeys = false; eCDAllocType alloctype = CD_DUPLICATE; diff --git a/source/blender/blenkernel/intern/mesh_normals.cc b/source/blender/blenkernel/intern/mesh_normals.cc index da5b4ccc764..47ea55be871 100644 --- a/source/blender/blenkernel/intern/mesh_normals.cc +++ b/source/blender/blenkernel/intern/mesh_normals.cc @@ -319,6 +319,7 @@ void BKE_mesh_ensure_normals(Mesh *mesh) void BKE_mesh_ensure_normals_for_display(Mesh *mesh) { switch ((eMeshWrapperType)mesh->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: /* Run code below. */ break; diff --git a/source/blender/blenkernel/intern/mesh_wrapper.c b/source/blender/blenkernel/intern/mesh_wrapper.c index bc1ffeb8cf4..4cc43354a44 100644 --- a/source/blender/blenkernel/intern/mesh_wrapper.c +++ b/source/blender/blenkernel/intern/mesh_wrapper.c @@ -36,6 +36,7 @@ #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" +#include "DNA_modifier_types.h" #include "DNA_object_types.h" #include "BLI_ghash.h" @@ -50,8 +51,14 @@ #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_mesh_wrapper.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_mesh.h" +#include "BKE_subdiv_modifier.h" #include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" Mesh *BKE_mesh_wrapper_from_editmesh_with_coords(BMEditMesh *em, const CustomData_MeshMasks *cd_mask_extra, @@ -106,7 +113,8 @@ static void mesh_wrapper_ensure_mdata_isolated(void *userdata) me->runtime.wrapper_type = ME_WRAPPER_TYPE_MDATA; switch (geom_type_orig) { - case ME_WRAPPER_TYPE_MDATA: { + case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: { break; /* Quiet warning. */ } case ME_WRAPPER_TYPE_BMESH: { @@ -157,6 +165,7 @@ bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3]) case ME_WRAPPER_TYPE_BMESH: return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime.edit_data, min, max); case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: return BKE_mesh_minmax(me, min, max); } BLI_assert_unreachable(); @@ -191,7 +200,8 @@ void BKE_mesh_wrapper_vert_coords_copy(const Mesh *me, } return; } - case ME_WRAPPER_TYPE_MDATA: { + case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: { BLI_assert(vert_coords_len <= me->totvert); const MVert *mvert = me->mvert; for (int i = 0; i < vert_coords_len; i++) { @@ -228,7 +238,8 @@ void BKE_mesh_wrapper_vert_coords_copy_with_mat4(const Mesh *me, } return; } - case ME_WRAPPER_TYPE_MDATA: { + case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: { BLI_assert(vert_coords_len == me->totvert); const MVert *mvert = me->mvert; for (int i = 0; i < vert_coords_len; i++) { @@ -252,6 +263,7 @@ int BKE_mesh_wrapper_vert_len(const Mesh *me) case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totvert; case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: return me->totvert; } BLI_assert_unreachable(); @@ -264,6 +276,7 @@ int BKE_mesh_wrapper_edge_len(const Mesh *me) case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totedge; case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: return me->totedge; } BLI_assert_unreachable(); @@ -276,6 +289,7 @@ int BKE_mesh_wrapper_loop_len(const Mesh *me) case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totloop; case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: return me->totloop; } BLI_assert_unreachable(); @@ -288,6 +302,7 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me) case ME_WRAPPER_TYPE_BMESH: return me->edit_mesh->bm->totface; case ME_WRAPPER_TYPE_MDATA: + case ME_WRAPPER_TYPE_SUBD: return me->totpoly; } BLI_assert_unreachable(); @@ -295,3 +310,70 @@ int BKE_mesh_wrapper_poly_len(const Mesh *me) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name CPU Subdivision Evaluation + * \{ */ + +Mesh *BKE_mesh_wrapper_ensure_subdivision(const Object *ob, Mesh *me) +{ + ThreadMutex *mesh_eval_mutex = (ThreadMutex *)me->runtime.eval_mutex; + BLI_mutex_lock(mesh_eval_mutex); + + if (me->runtime.wrapper_type == ME_WRAPPER_TYPE_SUBD) { + BLI_mutex_unlock(mesh_eval_mutex); + return me->runtime.mesh_eval; + } + + SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob); + if (!smd) { + BLI_mutex_unlock(mesh_eval_mutex); + return me; + } + + const bool apply_render = me->runtime.subsurf_apply_render; + + SubdivSettings subdiv_settings; + BKE_subsurf_modifier_subdiv_settings_init(&subdiv_settings, smd, apply_render); + if (subdiv_settings.level == 0) { + BLI_mutex_unlock(mesh_eval_mutex); + return me; + } + + SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); + + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &subdiv_settings, me, false); + if (subdiv == NULL) { + /* Happens on bad topology, but also on empty input mesh. */ + BLI_mutex_unlock(mesh_eval_mutex); + return me; + } + + SubdivToMeshSettings mesh_settings; + mesh_settings.resolution = me->runtime.subsurf_resolution; + mesh_settings.use_optimal_display = me->runtime.subsurf_use_optimal_display; + + if (mesh_settings.resolution < 3) { + BLI_mutex_unlock(mesh_eval_mutex); + return me; + } + + Mesh *subdiv_mesh = BKE_subdiv_to_mesh(subdiv, &mesh_settings, me); + + if (subdiv != runtime_data->subdiv) { + BKE_subdiv_free(subdiv); + } + + if (subdiv_mesh != me) { + if (me->runtime.mesh_eval != NULL) { + BKE_id_free(NULL, me->runtime.mesh_eval); + } + me->runtime.mesh_eval = subdiv_mesh; + me->runtime.wrapper_type = ME_WRAPPER_TYPE_SUBD; + } + + BLI_mutex_unlock(mesh_eval_mutex); + return me->runtime.mesh_eval; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index e1d201d7806..f3b6c2544bf 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -970,6 +970,7 @@ static void modwrap_dependsOnNormals(Mesh *me) } break; } + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: BKE_mesh_calc_normals(me); break; diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index fc2e7d0a6a3..b0c93a5614d 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -70,6 +70,7 @@ #include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_tracking.h" #include "IMB_imbuf.h" @@ -1695,17 +1696,7 @@ void BKE_movieclip_reload(Main *bmain, MovieClip *clip) movieclip_calc_length(clip); - /* same as for image update -- don't use notifiers because they are not 100% sure to succeeded - * (node trees which are not currently visible wouldn't be refreshed) - */ - { - Scene *scene; - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { - if (scene->nodetree) { - nodeUpdateID(scene->nodetree, &clip->id); - } - } - } + BKE_ntree_update_tag_id_changed(bmain, &clip->id); } void BKE_movieclip_update_scopes(MovieClip *clip, MovieClipUser *user, MovieClipScopes *scopes) diff --git a/source/blender/blenkernel/intern/multires_reshape_smooth.c b/source/blender/blenkernel/intern/multires_reshape_smooth.c index 3665d01926b..50b4410a28e 100644 --- a/source/blender/blenkernel/intern/multires_reshape_smooth.c +++ b/source/blender/blenkernel/intern/multires_reshape_smooth.c @@ -566,7 +566,8 @@ static bool foreach_topology_info(const SubdivForeachContext *foreach_context, const int num_vertices, const int num_edges, const int num_loops, - const int num_polygons) + const int num_polygons, + const int *UNUSED(subdiv_polygon_offset)) { MultiresReshapeSmoothContext *reshape_smooth_context = foreach_context->user_data; const int max_edges = reshape_smooth_context->smoothing_type == MULTIRES_SUBDIVIDE_LINEAR ? @@ -1037,7 +1038,7 @@ static void reshape_subdiv_create(MultiresReshapeSmoothContext *reshape_smooth_c converter_init(reshape_smooth_context, &converter); Subdiv *reshape_subdiv = BKE_subdiv_new_from_converter(settings, &converter); - BKE_subdiv_eval_begin(reshape_subdiv); + BKE_subdiv_eval_begin(reshape_subdiv, SUBDIV_EVALUATOR_TYPE_CPU, NULL); reshape_smooth_context->reshape_subdiv = reshape_subdiv; diff --git a/source/blender/blenkernel/intern/multires_reshape_util.c b/source/blender/blenkernel/intern/multires_reshape_util.c index b7572204182..07a5d7c4a61 100644 --- a/source/blender/blenkernel/intern/multires_reshape_util.c +++ b/source/blender/blenkernel/intern/multires_reshape_util.c @@ -65,7 +65,7 @@ Subdiv *multires_reshape_create_subdiv(Depsgraph *depsgraph, SubdivSettings subdiv_settings; BKE_multires_subdiv_settings_init(&subdiv_settings, mmd); Subdiv *subdiv = BKE_subdiv_new_from_mesh(&subdiv_settings, base_mesh); - if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) { + if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { BKE_subdiv_free(subdiv); return NULL; } diff --git a/source/blender/blenkernel/intern/multires_reshape_vertcos.c b/source/blender/blenkernel/intern/multires_reshape_vertcos.c index ed2df1ba8c5..c009349ff1b 100644 --- a/source/blender/blenkernel/intern/multires_reshape_vertcos.c +++ b/source/blender/blenkernel/intern/multires_reshape_vertcos.c @@ -114,7 +114,8 @@ static bool multires_reshape_vertcos_foreach_topology_info( const int num_vertices, const int UNUSED(num_edges), const int UNUSED(num_loops), - const int UNUSED(num_polygons)) + const int UNUSED(num_polygons), + const int *UNUSED(subdiv_polygon_offset)) { MultiresReshapeAssignVertcosContext *reshape_vertcos_context = foreach_context->user_data; if (num_vertices != reshape_vertcos_context->num_vert_coords) { diff --git a/source/blender/blenkernel/intern/multires_versioning.c b/source/blender/blenkernel/intern/multires_versioning.c index 4c0d7165cd0..18708c43f26 100644 --- a/source/blender/blenkernel/intern/multires_versioning.c +++ b/source/blender/blenkernel/intern/multires_versioning.c @@ -61,7 +61,7 @@ static Subdiv *subdiv_for_simple_to_catmull_clark(Object *object, MultiresModifi Subdiv *subdiv = BKE_subdiv_new_from_converter(&subdiv_settings, &converter); BKE_subdiv_converter_free(&converter); - if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL)) { + if (!BKE_subdiv_eval_begin_from_mesh(subdiv, base_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { BKE_subdiv_free(subdiv); return NULL; } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index be458ed036e..f32db41f62d 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -65,6 +65,7 @@ #include "BKE_animsys.h" #include "BKE_bpath.h" #include "BKE_colortools.h" +#include "BKE_context.h" #include "BKE_cryptomatte.h" #include "BKE_global.h" #include "BKE_icons.h" @@ -74,6 +75,7 @@ #include "BKE_lib_query.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "RNA_access.h" #include "RNA_define.h" @@ -98,6 +100,7 @@ #define NODE_DEFAULT_MAX_WIDTH 700 using blender::Array; +using blender::Map; using blender::MutableSpan; using blender::Set; using blender::Span; @@ -151,62 +154,42 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c BLI_listbase_clear(&ntree_dst->nodes); BLI_listbase_clear(&ntree_dst->links); - /* Since source nodes and sockets are unique pointers we can put everything in a single map. */ - GHash *new_pointers = BLI_ghash_ptr_new(__func__); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; - LISTBASE_FOREACH (const bNode *, node_src, &ntree_src->nodes) { - bNode *new_node = BKE_node_copy_ex(ntree_dst, node_src, flag_subdata, true); - BLI_ghash_insert(new_pointers, (void *)node_src, new_node); - /* Store mapping to inputs. */ - bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; - const bNodeSocket *input_sock_src = (const bNodeSocket *)node_src->inputs.first; - while (new_input_sock != nullptr) { - BLI_ghash_insert(new_pointers, (void *)input_sock_src, new_input_sock); - new_input_sock = new_input_sock->next; - input_sock_src = input_sock_src->next; - } - /* Store mapping to outputs. */ - bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; - const bNodeSocket *output_sock_src = (const bNodeSocket *)node_src->outputs.first; - while (new_output_sock != nullptr) { - BLI_ghash_insert(new_pointers, (void *)output_sock_src, new_output_sock); - new_output_sock = new_output_sock->next; - output_sock_src = output_sock_src->next; - } + BLI_listbase_clear(&ntree_dst->nodes); + LISTBASE_FOREACH (const bNode *, src_node, &ntree_src->nodes) { + /* Don't find a unique name for every node, since they should have valid names already. */ + bNode *new_node = blender::bke::node_copy_with_mapping( + ntree_dst, *src_node, flag_subdata, false, socket_map); + node_map.add(src_node, new_node); } /* copy links */ - BLI_duplicatelist(&ntree_dst->links, &ntree_src->links); - LISTBASE_FOREACH (bNodeLink *, link_dst, &ntree_dst->links) { - link_dst->fromnode = (bNode *)BLI_ghash_lookup_default( - new_pointers, link_dst->fromnode, nullptr); - link_dst->fromsock = (bNodeSocket *)BLI_ghash_lookup_default( - new_pointers, link_dst->fromsock, nullptr); - link_dst->tonode = (bNode *)BLI_ghash_lookup_default(new_pointers, link_dst->tonode, nullptr); - link_dst->tosock = (bNodeSocket *)BLI_ghash_lookup_default( - new_pointers, link_dst->tosock, nullptr); - /* update the link socket's pointer */ - if (link_dst->tosock) { - link_dst->tosock->link = link_dst; - } + BLI_listbase_clear(&ntree_dst->links); + LISTBASE_FOREACH (const bNodeLink *, src_link, &ntree_src->links) { + bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link); + dst_link->fromnode = node_map.lookup(src_link->fromnode); + dst_link->fromsock = socket_map.lookup(src_link->fromsock); + dst_link->tonode = node_map.lookup(src_link->tonode); + dst_link->tosock = socket_map.lookup(src_link->tosock); + BLI_assert(dst_link->tosock); + dst_link->tosock->link = dst_link; + BLI_addtail(&ntree_dst->links, dst_link); } /* copy interface sockets */ - BLI_duplicatelist(&ntree_dst->inputs, &ntree_src->inputs); - bNodeSocket *sock_dst, *sock_src; - for (sock_dst = (bNodeSocket *)ntree_dst->inputs.first, - sock_src = (bNodeSocket *)ntree_src->inputs.first; - sock_dst != nullptr; - sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { - node_socket_copy(sock_dst, sock_src, flag_subdata); + BLI_listbase_clear(&ntree_dst->inputs); + LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->inputs) { + bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); + node_socket_copy(dst_socket, src_socket, flag_subdata); + BLI_addtail(&ntree_dst->inputs, dst_socket); } - - BLI_duplicatelist(&ntree_dst->outputs, &ntree_src->outputs); - for (sock_dst = (bNodeSocket *)ntree_dst->outputs.first, - sock_src = (bNodeSocket *)ntree_src->outputs.first; - sock_dst != nullptr; - sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { - node_socket_copy(sock_dst, sock_src, flag_subdata); + BLI_listbase_clear(&ntree_dst->outputs); + LISTBASE_FOREACH (const bNodeSocket *, src_socket, &ntree_src->outputs) { + bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); + node_socket_copy(dst_socket, src_socket, flag_subdata); + BLI_addtail(&ntree_dst->outputs, dst_socket); } /* copy preview hash */ @@ -226,18 +209,11 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c } /* update node->parent pointers */ - for (bNode *node_dst = (bNode *)ntree_dst->nodes.first, - *node_src = (bNode *)ntree_src->nodes.first; - node_dst; - node_dst = (bNode *)node_dst->next, node_src = (bNode *)node_src->next) { - if (node_dst->parent) { - node_dst->parent = (bNode *)BLI_ghash_lookup_default( - new_pointers, node_dst->parent, nullptr); + LISTBASE_FOREACH (bNode *, new_node, &ntree_dst->nodes) { + if (new_node->parent) { + new_node->parent = node_map.lookup(new_node->parent); } } - - BLI_ghash_free(new_pointers, nullptr, nullptr); - /* node tree will generate its own interface type */ ntree_dst->interface_type = nullptr; @@ -261,8 +237,7 @@ static void ntree_free_data(ID *id) /* XXX hack! node trees should not store execution graphs at all. * This should be removed when old tree types no longer require it. * Currently the execution data for texture nodes remains in the tree - * after execution, until the node tree is updated or freed. - */ + * after execution, until the node tree is updated or freed. */ if (ntree->execdata) { switch (ntree->type) { case NTREE_SHADER: @@ -278,10 +253,10 @@ static void ntree_free_data(ID *id) /* XXX not nice, but needed to free localized node groups properly */ free_localized_node_groups(ntree); - /* unregister associated RNA types */ + /* Unregister associated RNA types. */ ntreeInterfaceTypeFree(ntree); - BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ + BLI_freelistN(&ntree->links); LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree->nodes) { node_free_node(ntree, node); @@ -522,7 +497,6 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so static void write_node_socket(BlendWriter *writer, bNodeSocket *sock) { - /* actual socket writing */ BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { @@ -533,7 +507,6 @@ static void write_node_socket(BlendWriter *writer, bNodeSocket *sock) } static void write_node_socket_interface(BlendWriter *writer, bNodeSocket *sock) { - /* actual socket writing */ BLO_write_struct(writer, bNodeSocket, sock); if (sock->prop) { @@ -547,8 +520,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) { BKE_id_blend_write(writer, &ntree->id); - /* for link_list() speed, we write per list */ - if (ntree->adt) { BKE_animdata_blend_write(writer, ntree->adt); } @@ -572,7 +543,6 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } if (node->storage) { - /* could be handlerized at some point, now only 1 exception still */ if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY) && ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB, SH_NODE_CURVE_FLOAT)) { BKE_curvemapping_blend_write(writer, (const CurveMapping *)node->storage); @@ -646,13 +616,13 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } if (node->type == CMP_NODE_OUTPUT_FILE) { - /* inputs have own storage data */ + /* Inputs have their own storage data. */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { BLO_write_struct(writer, NodeImageMultiFileSocket, sock->storage); } } if (ELEM(node->type, CMP_NODE_IMAGE, CMP_NODE_R_LAYERS)) { - /* write extra socket info */ + /* Write extra socket info. */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { BLO_write_struct(writer, NodeImageLayer, sock->storage); } @@ -716,6 +686,7 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->execdata = nullptr; ntree->field_inferencing_interface = nullptr; + BKE_ntree_update_tag_missing_runtime_data(ntree); BLO_read_data_address(reader, &ntree->adt); BKE_animdata_blend_read_data(reader, ntree->adt); @@ -748,7 +719,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) } if (node->storage) { - /* could be handlerized at some point */ switch (node->type) { case SH_NODE_CURVE_VEC: case SH_NODE_CURVE_RGB: @@ -859,11 +829,6 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) /* TODO: should be dealt by new generic cache handling of IDs... */ ntree->previews = nullptr; - if (ntree->type == NTREE_GEOMETRY) { - /* Update field referencing for the geometry nodes modifier. */ - ntree->update |= NTREE_UPDATE_FIELD_INFERENCING; - } - BLO_read_data_address(reader, &ntree->preview); BKE_previewimg_blend_read(reader, ntree->preview); @@ -1096,21 +1061,18 @@ static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType return; } bNodeSocketTemplate *sockdef; - /* bNodeSocket *sock; */ /* UNUSED */ if (ntype->inputs) { sockdef = ntype->inputs; while (sockdef->type != -1) { - /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_IN); - + node_add_socket_from_template(ntree, node, sockdef, SOCK_IN); sockdef++; } } if (ntype->outputs) { sockdef = ntype->outputs; while (sockdef->type != -1) { - /* sock = */ node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT); - + node_add_socket_from_template(ntree, node, sockdef, SOCK_OUT); sockdef++; } } @@ -1168,8 +1130,7 @@ static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node) RNA_pointer_create((ID *)ntree, &RNA_Node, node, &ptr); /* XXX Warning: context can be nullptr in case nodes are added in do_versions. - * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. - */ + * Delayed init is not supported for nodes with context-based `initfunc_api` at the moment. */ BLI_assert(C != nullptr); ntype->initfunc_api(C, &ptr); } @@ -1190,6 +1151,7 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) /* Deprecated integer type. */ ntree->type = ntree->typeinfo->type; + BKE_ntree_update_tag_all(ntree); } static void node_set_typeinfo(const struct bContext *C, @@ -1240,6 +1202,7 @@ static void node_socket_set_typeinfo(bNodeTree *ntree, ntree->init &= ~NTREE_TYPE_INIT; } + BKE_ntree_update_tag_socket_type(ntree, sock); } /* Set specific typeinfo pointers in all node trees on register/unregister */ @@ -1383,18 +1346,6 @@ bNodeType *nodeTypeFind(const char *idname) return nullptr; } -static void free_dynamic_typeinfo(bNodeType *ntype) -{ - if (ntype->type == NODE_DYNAMIC) { - if (ntype->inputs) { - MEM_freeN(ntype->inputs); - } - if (ntype->outputs) { - MEM_freeN(ntype->outputs); - } - } -} - /* callback for hash value free function */ static void node_free_type(void *nodetype_v) { @@ -1404,11 +1355,6 @@ static void node_free_type(void *nodetype_v) * or we'd want to update *all* active Mains, which we cannot do anyway currently. */ update_typeinfo(G_MAIN, nullptr, nullptr, nodetype, nullptr, true); - /* XXX deprecated */ - if (nodetype->type == NODE_DYNAMIC) { - free_dynamic_typeinfo(nodetype); - } - delete nodetype->fixed_declaration; nodetype->fixed_declaration = nullptr; @@ -1580,11 +1526,11 @@ static bNodeSocket *make_socket(bNodeTree *ntree, /* if no explicit identifier is given, assign a unique identifier based on the name */ BLI_strncpy(auto_identifier, name, sizeof(auto_identifier)); } - /* make the identifier unique */ + /* Make the identifier unique. */ BLI_uniquename_cb( unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); - bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); + bNodeSocket *sock = MEM_cnew<bNodeSocket>("sock"); sock->in_out = in_out; BLI_strncpy(sock->identifier, auto_identifier, NODE_MAXSTR); @@ -1749,7 +1695,7 @@ bNodeSocket *nodeAddSocket(bNodeTree *ntree, BLI_remlink(lb, sock); /* does nothing for new socket */ BLI_addtail(lb, sock); - node->update |= NODE_UPDATE; + BKE_ntree_update_tag_socket_new(ntree, sock); return sock; } @@ -1768,8 +1714,6 @@ bNodeSocket *nodeInsertSocket(bNodeTree *ntree, BLI_remlink(lb, sock); /* does nothing for new socket */ BLI_insertlinkbefore(lb, next_sock, sock); - node->update |= NODE_UPDATE; - return sock; } @@ -2010,10 +1954,7 @@ bNodeSocket *nodeInsertStaticSocket(bNodeTree *ntree, return sock; } -static void node_socket_free(bNodeTree *UNUSED(ntree), - bNodeSocket *sock, - bNode *UNUSED(node), - const bool do_id_user) +static void node_socket_free(bNodeSocket *sock, const bool do_id_user) { if (sock->prop) { IDP_FreePropertyContent_ex(sock->prop, do_id_user); @@ -2048,10 +1989,10 @@ void nodeRemoveSocketEx(struct bNodeTree *ntree, BLI_remlink(&node->inputs, sock); BLI_remlink(&node->outputs, sock); - node_socket_free(ntree, sock, node, do_id_user); + node_socket_free(sock, do_id_user); MEM_freeN(sock); - node->update |= NODE_UPDATE; + BKE_ntree_update_tag_socket_removed(ntree); } void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) @@ -2063,18 +2004,18 @@ void nodeRemoveAllSockets(bNodeTree *ntree, bNode *node) } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { - node_socket_free(ntree, sock, node, true); + node_socket_free(sock, true); MEM_freeN(sock); } BLI_listbase_clear(&node->inputs); LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) { - node_socket_free(ntree, sock, node, true); + node_socket_free(sock, true); MEM_freeN(sock); } BLI_listbase_clear(&node->outputs); - node->update |= NODE_UPDATE; + BKE_ntree_update_tag_socket_removed(ntree); } bNode *nodeFindNodebyName(bNodeTree *ntree, const char *name) @@ -2220,13 +2161,17 @@ void nodeUniqueName(bNodeTree *ntree, bNode *node) bNode *nodeAddNode(const struct bContext *C, bNodeTree *ntree, const char *idname) { - bNode *node = (bNode *)MEM_callocN(sizeof(bNode), "new node"); + bNode *node = MEM_cnew<bNode>("new node"); BLI_addtail(&ntree->nodes, node); BLI_strncpy(node->idname, idname, sizeof(node->idname)); node_set_typeinfo(C, ntree, node, nodeTypeFind(idname)); - ntree->update |= NTREE_UPDATE_NODES; + BKE_ntree_update_tag_node_new(ntree, node); + + if (node->type == GEO_NODE_INPUT_SCENE_TIME) { + DEG_relations_tag_update(CTX_data_main(C)); + } return node; } @@ -2236,9 +2181,8 @@ bNode *nodeAddStaticNode(const struct bContext *C, bNodeTree *ntree, int type) const char *idname = nullptr; NODE_TYPES_BEGIN (ntype) { - /* do an extra poll here, because some int types are used - * for multiple node types, this helps find the desired type - */ + /* Do an extra poll here, because some int types are used + * for multiple node types, this helps find the desired type. */ const char *disabled_hint; if (ntype->type == type && (!ntype->poll || ntype->poll(ntype, ntree, &disabled_hint))) { idname = ntype->idname; @@ -2268,142 +2212,105 @@ static void node_socket_copy(bNodeSocket *sock_dst, const bNodeSocket *sock_src, } sock_dst->stack_index = 0; - /* XXX some compositor node (e.g. image, render layers) still store - * some persistent buffer data here, need to clear this to avoid dangling pointers. - */ + /* XXX some compositor nodes (e.g. image, render layers) still store + * some persistent buffer data here, need to clear this to avoid dangling pointers. */ sock_dst->cache = nullptr; } -bNode *BKE_node_copy_ex(bNodeTree *ntree, - const bNode *node_src, - const int flag, - const bool unique_name) -{ - bNode *node_dst = (bNode *)MEM_callocN(sizeof(bNode), "dupli node"); - bNodeSocket *sock_dst, *sock_src; - bNodeLink *link_dst, *link_src; +namespace blender::bke { - *node_dst = *node_src; +bNode *node_copy_with_mapping(bNodeTree *dst_tree, + const bNode &node_src, + const int flag, + const bool unique_name, + Map<const bNodeSocket *, bNodeSocket *> &socket_map) +{ + bNode *node_dst = (bNode *)MEM_mallocN(sizeof(bNode), __func__); + *node_dst = node_src; - /* can be called for nodes outside a node tree (e.g. clipboard) */ - if (ntree) { + /* Can be called for nodes outside a node tree (e.g. clipboard). */ + if (dst_tree) { if (unique_name) { - nodeUniqueName(ntree, node_dst); + nodeUniqueName(dst_tree, node_dst); } - - BLI_addtail(&ntree->nodes, node_dst); + BLI_addtail(&dst_tree->nodes, node_dst); } - BLI_duplicatelist(&node_dst->inputs, &node_src->inputs); - for (sock_dst = (bNodeSocket *)node_dst->inputs.first, - sock_src = (bNodeSocket *)node_src->inputs.first; - sock_dst != nullptr; - sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { - node_socket_copy(sock_dst, sock_src, flag); + BLI_listbase_clear(&node_dst->inputs); + LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.inputs) { + bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); + node_socket_copy(dst_socket, src_socket, flag); + BLI_addtail(&node_dst->inputs, dst_socket); + socket_map.add_new(src_socket, dst_socket); } - BLI_duplicatelist(&node_dst->outputs, &node_src->outputs); - for (sock_dst = (bNodeSocket *)node_dst->outputs.first, - sock_src = (bNodeSocket *)node_src->outputs.first; - sock_dst != nullptr; - sock_dst = (bNodeSocket *)sock_dst->next, sock_src = (bNodeSocket *)sock_src->next) { - node_socket_copy(sock_dst, sock_src, flag); + BLI_listbase_clear(&node_dst->outputs); + LISTBASE_FOREACH (const bNodeSocket *, src_socket, &node_src.outputs) { + bNodeSocket *dst_socket = (bNodeSocket *)MEM_dupallocN(src_socket); + node_socket_copy(dst_socket, src_socket, flag); + BLI_addtail(&node_dst->outputs, dst_socket); + socket_map.add_new(src_socket, dst_socket); } - if (node_src->prop) { - node_dst->prop = IDP_CopyProperty_ex(node_src->prop, flag); + if (node_src.prop) { + node_dst->prop = IDP_CopyProperty_ex(node_src.prop, flag); } - BLI_duplicatelist(&node_dst->internal_links, &node_src->internal_links); - for (link_dst = (bNodeLink *)node_dst->internal_links.first, - link_src = (bNodeLink *)node_src->internal_links.first; - link_dst != nullptr; - link_dst = (bNodeLink *)link_dst->next, link_src = (bNodeLink *)link_src->next) { - /* This is a bit annoying to do index lookups in a list, but is likely to be faster than - * trying to create a hash-map. At least for usual nodes, which only have so much sockets - * and internal links. */ - const int from_sock_index = BLI_findindex(&node_src->inputs, link_src->fromsock); - const int to_sock_index = BLI_findindex(&node_src->outputs, link_src->tosock); - BLI_assert(from_sock_index != -1); - BLI_assert(to_sock_index != -1); - link_dst->fromnode = node_dst; - link_dst->tonode = node_dst; - link_dst->fromsock = (bNodeSocket *)BLI_findlink(&node_dst->inputs, from_sock_index); - link_dst->tosock = (bNodeSocket *)BLI_findlink(&node_dst->outputs, to_sock_index); + BLI_listbase_clear(&node_dst->internal_links); + LISTBASE_FOREACH (const bNodeLink *, src_link, &node_src.internal_links) { + bNodeLink *dst_link = (bNodeLink *)MEM_dupallocN(src_link); + dst_link->fromnode = node_dst; + dst_link->tonode = node_dst; + dst_link->fromsock = socket_map.lookup(src_link->fromsock); + dst_link->tosock = socket_map.lookup(src_link->tosock); + BLI_addtail(&node_dst->internal_links, dst_link); } if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { id_us_plus(node_dst->id); } - if (node_src->typeinfo->copyfunc) { - node_src->typeinfo->copyfunc(ntree, node_dst, node_src); + if (node_src.typeinfo->copyfunc) { + node_src.typeinfo->copyfunc(dst_tree, node_dst, &node_src); } - node_dst->new_node = nullptr; - /* Only call copy function when a copy is made for the main database, not * for cases like the dependency graph and localization. */ if (node_dst->typeinfo->copyfunc_api && !(flag & LIB_ID_CREATE_NO_MAIN)) { PointerRNA ptr; - RNA_pointer_create((ID *)ntree, &RNA_Node, node_dst, &ptr); + RNA_pointer_create((ID *)dst_tree, &RNA_Node, node_dst, &ptr); - node_dst->typeinfo->copyfunc_api(&ptr, node_src); + node_dst->typeinfo->copyfunc_api(&ptr, &node_src); } - if (ntree) { - ntree->update |= NTREE_UPDATE_NODES; + if (dst_tree) { + BKE_ntree_update_tag_node_new(dst_tree, node_dst); } /* Reset the declaration of the new node. */ node_dst->declaration = nullptr; - nodeDeclarationEnsure(ntree, node_dst); + nodeDeclarationEnsure(dst_tree, node_dst); return node_dst; } -static void node_set_new_pointers(bNode *node_src, bNode *new_node) +bNode *node_copy(bNodeTree *dst_tree, + const bNode &src_node, + const int flag, + const bool unique_name) { - /* Store mapping to the node itself. */ - node_src->new_node = new_node; - /* Store mapping to inputs. */ - bNodeSocket *new_input_sock = (bNodeSocket *)new_node->inputs.first; - bNodeSocket *input_sock_src = (bNodeSocket *)node_src->inputs.first; - while (new_input_sock != nullptr) { - input_sock_src->new_sock = new_input_sock; - new_input_sock = new_input_sock->next; - input_sock_src = input_sock_src->next; - } - /* Store mapping to outputs. */ - bNodeSocket *new_output_sock = (bNodeSocket *)new_node->outputs.first; - bNodeSocket *output_sock_src = (bNodeSocket *)node_src->outputs.first; - while (new_output_sock != nullptr) { - output_sock_src->new_sock = new_output_sock; - new_output_sock = new_output_sock->next; - output_sock_src = output_sock_src->next; - } + Map<const bNodeSocket *, bNodeSocket *> socket_map; + return node_copy_with_mapping(dst_tree, src_node, flag, unique_name, socket_map); } -bNode *BKE_node_copy_store_new_pointers(bNodeTree *ntree, bNode *node_src, const int flag) -{ - bNode *new_node = BKE_node_copy_ex(ntree, node_src, flag, true); - node_set_new_pointers(node_src, new_node); - return new_node; -} +} // namespace blender::bke -bNodeTree *ntreeCopyTree_ex_new_pointers(const bNodeTree *ntree, - Main *bmain, - const bool do_id_user) +bNode *BKE_node_copy(bNodeTree *dst_tree, + const bNode *src_node, + const int flag, + const bool unique_name) { - bNodeTree *new_ntree = ntreeCopyTree_ex(ntree, bmain, do_id_user); - bNode *new_node = (bNode *)new_ntree->nodes.first; - bNode *node_src = (bNode *)ntree->nodes.first; - while (new_node != nullptr) { - node_set_new_pointers(node_src, new_node); - new_node = new_node->next; - node_src = node_src->next; - } - return new_ntree; + return blender::bke::node_copy(dst_tree, *src_node, flag, unique_name); } static int node_count_links(const bNodeTree *ntree, const bNodeSocket *socket) @@ -2422,12 +2329,12 @@ bNodeLink *nodeAddLink( { bNodeLink *link = nullptr; - /* test valid input */ + /* Test valid input. */ BLI_assert(fromnode); BLI_assert(tonode); if (fromsock->in_out == SOCK_OUT && tosock->in_out == SOCK_IN) { - link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); + link = MEM_cnew<bNodeLink>("link"); if (ntree) { BLI_addtail(&ntree->links, link); } @@ -2438,7 +2345,7 @@ bNodeLink *nodeAddLink( } else if (fromsock->in_out == SOCK_IN && tosock->in_out == SOCK_OUT) { /* OK but flip */ - link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "link"); + link = MEM_cnew<bNodeLink>("link"); if (ntree) { BLI_addtail(&ntree->links, link); } @@ -2449,7 +2356,7 @@ bNodeLink *nodeAddLink( } if (ntree) { - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_added(ntree, link); } if (link != nullptr && link->tosock->flag & SOCK_MULTI_INPUT) { @@ -2461,7 +2368,7 @@ bNodeLink *nodeAddLink( void nodeRemLink(bNodeTree *ntree, bNodeLink *link) { - /* can be called for links outside a node tree (e.g. clipboard) */ + /* Can be called for links outside a node tree (e.g. clipboard). */ if (ntree) { BLI_remlink(&ntree->links, link); } @@ -2472,7 +2379,7 @@ void nodeRemLink(bNodeTree *ntree, bNodeLink *link) MEM_freeN(link); if (ntree) { - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_removed(ntree); } } @@ -2572,7 +2479,7 @@ void nodeMuteLinkToggle(bNodeTree *ntree, bNodeLink *link) } if (ntree) { - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_mute(ntree, link); } } @@ -2583,8 +2490,6 @@ void nodeRemSocketLinks(bNodeTree *ntree, bNodeSocket *sock) nodeRemLink(ntree, link); } } - - ntree->update |= NTREE_UPDATE_LINKS; } bool nodeLinkIsHidden(const bNodeLink *link) @@ -2649,7 +2554,7 @@ void nodeInternalRelink(bNodeTree *ntree, bNode *node) link->flag |= NODE_LINK_MUTED; } - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_changed(ntree); } else { if (link->tosock->flag & SOCK_MULTI_INPUT) { @@ -2843,13 +2748,16 @@ bool BKE_node_preview_used(const bNode *node) return (node->typeinfo->flag & NODE_PREVIEW) != 0; } -bNodePreview *BKE_node_preview_verify( - bNodeInstanceHash *previews, bNodeInstanceKey key, int xsize, int ysize, bool create) +bNodePreview *BKE_node_preview_verify(bNodeInstanceHash *previews, + bNodeInstanceKey key, + const int xsize, + const int ysize, + const bool create) { bNodePreview *preview = (bNodePreview *)BKE_node_instance_hash_lookup(previews, key); if (!preview) { if (create) { - preview = (bNodePreview *)MEM_callocN(sizeof(bNodePreview), "node preview"); + preview = MEM_cnew<bNodePreview>("node preview"); BKE_node_instance_hash_insert(previews, key, preview); } else { @@ -2901,9 +2809,8 @@ void BKE_node_preview_free(bNodePreview *preview) static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, bNodeTree *ntree, bNodeInstanceKey parent_key, - int xsize, - int ysize, - bool create_previews) + const int xsize, + const int ysize) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { bNodeInstanceKey key = BKE_node_instance_key(parent_key, ntree, node); @@ -2912,17 +2819,16 @@ static void node_preview_init_tree_recursive(bNodeInstanceHash *previews, node->preview_xsize = xsize; node->preview_ysize = ysize; - BKE_node_preview_verify(previews, key, xsize, ysize, create_previews); + BKE_node_preview_verify(previews, key, xsize, ysize, false); } if (node->type == NODE_GROUP && node->id) { - node_preview_init_tree_recursive( - previews, (bNodeTree *)node->id, key, xsize, ysize, create_previews); + node_preview_init_tree_recursive(previews, (bNodeTree *)node->id, key, xsize, ysize); } } } -void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool create_previews) +void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize) { if (!ntree) { return; @@ -2932,8 +2838,7 @@ void BKE_node_preview_init_tree(bNodeTree *ntree, int xsize, int ysize, bool cre ntree->previews = BKE_node_instance_hash_new("node previews"); } - node_preview_init_tree_recursive( - ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize, create_previews); + node_preview_init_tree_recursive(ntree->previews, ntree, NODE_INSTANCE_KEY_BASE, xsize, ysize); } static void node_preview_tag_used_recursive(bNodeInstanceHash *previews, @@ -2999,40 +2904,6 @@ void BKE_node_preview_clear_tree(bNodeTree *ntree) } } -static void node_preview_sync(bNodePreview *to, bNodePreview *from) -{ - /* sizes should have been initialized by BKE_node_preview_init_tree */ - BLI_assert(to->xsize == from->xsize && to->ysize == from->ysize); - - /* copy over contents of previews */ - if (to->rect && from->rect) { - int xsize = to->xsize; - int ysize = to->ysize; - memcpy(to->rect, from->rect, xsize * ysize * sizeof(char[4])); - } -} - -void BKE_node_preview_sync_tree(bNodeTree *to_ntree, bNodeTree *from_ntree) -{ - bNodeInstanceHash *from_previews = from_ntree->previews; - bNodeInstanceHash *to_previews = to_ntree->previews; - - if (!from_previews || !to_previews) { - return; - } - - bNodeInstanceHashIterator iter; - NODE_INSTANCE_HASH_ITER (iter, from_previews) { - bNodeInstanceKey key = BKE_node_instance_hash_iterator_get_key(&iter); - bNodePreview *from = (bNodePreview *)BKE_node_instance_hash_iterator_get_value(&iter); - bNodePreview *to = (bNodePreview *)BKE_node_instance_hash_lookup(to_previews, key); - - if (from && to) { - node_preview_sync(to, from); - } - } -} - void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, bool remove_old) { if (remove_old || !to_ntree->previews) { @@ -3069,27 +2940,6 @@ void BKE_node_preview_merge_tree(bNodeTree *to_ntree, bNodeTree *from_ntree, boo } } -void BKE_node_preview_set_pixel( - bNodePreview *preview, const float col[4], int x, int y, bool do_manage) -{ - if (preview) { - if (x >= 0 && y >= 0) { - if (x < preview->xsize && y < preview->ysize) { - unsigned char *tar = preview->rect + 4 * ((preview->xsize * y) + x); - - if (do_manage) { - linearrgb_to_srgb_uchar4(tar, col); - } - else { - rgba_float_to_uchar(tar, col); - } - } - // else printf("prv out bound x y %d %d\n", x, y); - } - // else printf("prv out bound x y %d %d\n", x, y); - } -} - /* ************** Free stuff ********** */ void nodeUnlinkNode(bNodeTree *ntree, bNode *node) @@ -3098,9 +2948,6 @@ void nodeUnlinkNode(bNodeTree *ntree, bNode *node) ListBase *lb; if (link->fromnode == node) { lb = &node->outputs; - if (link->tonode) { - link->tonode->update |= NODE_UPDATE; - } } else if (link->tonode == node) { lb = &node->inputs; @@ -3142,10 +2989,6 @@ static void node_free_node(bNodeTree *ntree, bNode *node) /* can be called for nodes outside a node tree (e.g. clipboard) */ if (ntree) { - /* remove all references to this node */ - nodeUnlinkNode(ntree, node); - node_unlink_attached(ntree, node); - BLI_remlink(&ntree->nodes, node); if (ntree->typeinfo->free_node_cache) { @@ -3165,12 +3008,12 @@ static void node_free_node(bNodeTree *ntree, bNode *node) LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->inputs) { /* Remember, no ID user refcount management here! */ - node_socket_free(ntree, sock, node, false); + node_socket_free(sock, false); MEM_freeN(sock); } LISTBASE_FOREACH_MUTABLE (bNodeSocket *, sock, &node->outputs) { /* Remember, no ID user refcount management here! */ - node_socket_free(ntree, sock, node, false); + node_socket_free(sock, false); MEM_freeN(sock); } @@ -3189,7 +3032,7 @@ static void node_free_node(bNodeTree *ntree, bNode *node) MEM_freeN(node); if (ntree) { - ntree->update |= NTREE_UPDATE_NODES; + BKE_ntree_update_tag_node_removed(ntree); } } @@ -3197,6 +3040,12 @@ void ntreeFreeLocalNode(bNodeTree *ntree, bNode *node) { /* For removing nodes while editing localized node trees. */ BLI_assert((ntree->id.tag & LIB_TAG_LOCALIZED) != 0); + + /* These two lines assume the caller might want to free a single node and maintain + * a valid state in the node tree. */ + nodeUnlinkNode(ntree, node); + node_unlink_attached(ntree, node); + node_free_node(ntree, node); } @@ -3241,6 +3090,9 @@ void nodeRemoveNode(Main *bmain, bNodeTree *ntree, bNode *node, bool do_id_user) } } + nodeUnlinkNode(ntree, node); + node_unlink_attached(ntree, node); + /* Free node itself. */ node_free_node(ntree, node); } @@ -3266,8 +3118,7 @@ static void free_localized_node_groups(bNodeTree *ntree) /* Only localized node trees store a copy for each node group tree. * Each node group tree in a localized node tree can be freed, * since it is a localized copy itself (no risk of accessing free'd - * data in main, see T37939). - */ + * data in main, see T37939). */ if (!(ntree->id.tag & LIB_TAG_LOCALIZED)) { return; } @@ -3412,26 +3263,6 @@ bNodeTree *ntreeFromID(ID *id) return (nodetree != nullptr) ? *nodetree : nullptr; } -bool ntreeNodeExists(const bNodeTree *ntree, const bNode *testnode) -{ - LISTBASE_FOREACH (const bNode *, node, &ntree->nodes) { - if (node == testnode) { - return true; - } - } - return false; -} - -bool ntreeOutputExists(const bNode *node, const bNodeSocket *testsock) -{ - LISTBASE_FOREACH (const bNodeSocket *, sock, &node->outputs) { - if (sock == testsock) { - return true; - } - } - return false; -} - void ntreeNodeFlagSet(const bNodeTree *ntree, const int flag, const bool enable) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -3463,7 +3294,7 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) } } - /* ensures only a single output node is enabled */ + /* Ensures only a single output node is enabled. */ ntreeSetOutput(ntree); bNode *node_src = (bNode *)ntree->nodes.first; @@ -3481,15 +3312,6 @@ bNodeTree *ntreeLocalize(bNodeTree *ntree) return ltree; } -void ntreeLocalSync(bNodeTree *localtree, bNodeTree *ntree) -{ - if (localtree && ntree) { - if (ntree->typeinfo->local_sync) { - ntree->typeinfo->local_sync(localtree, ntree); - } - } -} - void ntreeLocalMerge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) { if (ntree && localtree) { @@ -3514,7 +3336,7 @@ static bNodeSocket *make_socket_interface(bNodeTree *ntree, return nullptr; } - bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "socket template"); + bNodeSocket *sock = MEM_cnew<bNodeSocket>("socket template"); BLI_strncpy(sock->idname, stype->idname, sizeof(sock->idname)); node_socket_set_typeinfo(ntree, sock, stype); sock->in_out = in_out; @@ -3560,12 +3382,11 @@ bNodeSocket *ntreeAddSocketInterface(bNodeTree *ntree, bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); if (in_out == SOCK_IN) { BLI_addtail(&ntree->inputs, iosock); - ntree->update |= NTREE_UPDATE_GROUP_IN; } else if (in_out == SOCK_OUT) { BLI_addtail(&ntree->outputs, iosock); - ntree->update |= NTREE_UPDATE_GROUP_OUT; } + BKE_ntree_update_tag_interface(ntree); return iosock; } @@ -3578,12 +3399,11 @@ bNodeSocket *ntreeInsertSocketInterface(bNodeTree *ntree, bNodeSocket *iosock = make_socket_interface(ntree, in_out, idname, name); if (in_out == SOCK_IN) { BLI_insertlinkbefore(&ntree->inputs, next_sock, iosock); - ntree->update |= NTREE_UPDATE_GROUP_IN; } else if (in_out == SOCK_OUT) { BLI_insertlinkbefore(&ntree->outputs, next_sock, iosock); - ntree->update |= NTREE_UPDATE_GROUP_OUT; } + BKE_ntree_update_tag_interface(ntree); return iosock; } @@ -3629,7 +3449,7 @@ void ntreeRemoveSocketInterface(bNodeTree *ntree, bNodeSocket *sock) node_socket_interface_free(ntree, sock, true); MEM_freeN(sock); - ntree->update |= NTREE_UPDATE_GROUP; + BKE_ntree_update_tag_interface(ntree); } /* generates a valid RNA identifier from the node tree name */ @@ -3973,10 +3793,13 @@ int nodeSocketIsHidden(const bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } -void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available) +void nodeSetSocketAvailability(bNodeTree *ntree, bNodeSocket *sock, bool is_available) { - /* #ntree is not needed right now, but it's generally necessary when changing the tree because we - * want to tag it as changed in the future. */ + const bool was_available = (sock->flag & SOCK_UNAVAIL) == 0; + if (is_available != was_available) { + BKE_ntree_update_tag_socket_availability(ntree, sock); + } + if (is_available) { sock->flag &= ~SOCK_UNAVAIL; } @@ -4428,7 +4251,7 @@ void ntreeGetDependencyList(struct bNodeTree *ntree, struct bNode ***r_deplist, } /* only updates node->level for detecting cycles links */ -static void ntree_update_node_level(bNodeTree *ntree) +void ntreeUpdateNodeLevels(bNodeTree *ntree) { /* first clear tag */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { @@ -4443,769 +4266,42 @@ static void ntree_update_node_level(bNodeTree *ntree) } } -void ntreeTagUsedSockets(bNodeTree *ntree) -{ - /* first clear data */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - sock->flag &= ~SOCK_IN_USE; - } - LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - sock->flag &= ~SOCK_IN_USE; - } - } - - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - link->fromsock->flag |= SOCK_IN_USE; - if (!(link->flag & NODE_LINK_MUTED)) { - link->tosock->flag |= SOCK_IN_USE; - } - } -} - -static void ntree_update_link_pointers(bNodeTree *ntree) -{ - /* first clear data */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - sock->link = nullptr; - } - } - - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - link->tosock->link = link; - } - - ntreeTagUsedSockets(ntree); -} - -static void ntree_validate_links(bNodeTree *ntree) -{ - LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - link->flag |= NODE_LINK_VALID; - if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) { - link->flag &= ~NODE_LINK_VALID; - } - else if (ntree->typeinfo->validate_link) { - if (!ntree->typeinfo->validate_link((eNodeSocketDatatype)link->fromsock->type, - (eNodeSocketDatatype)link->tosock->type)) { - link->flag &= ~NODE_LINK_VALID; - } - } - } -} - void ntreeUpdateAllNew(Main *main) { + Vector<bNodeTree *> new_ntrees; + /* Update all new node trees on file read or append, to add/remove sockets * in groups nodes if the group changed, and handle any update flags that * might have been set in file reading or versioning. */ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { if (owner_id->tag & LIB_TAG_NEW) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->typeinfo->group_update_func) { - node->typeinfo->group_update_func(ntree, node); - } - } - - ntreeUpdateTree(nullptr, ntree); + BKE_ntree_update_tag_all(ntree); } } FOREACH_NODETREE_END; + BKE_ntree_update_main(main, nullptr); } -namespace blender::bke::node_field_inferencing { - -static bool is_field_socket_type(eNodeSocketDatatype type) -{ - return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); -} - -static bool is_field_socket_type(const SocketRef &socket) -{ - return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); -} - -static bool update_field_inferencing(bNodeTree &btree); - -static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, - const InputSocketRef &socket) -{ - if (!is_field_socket_type(socket)) { - return InputSocketFieldType::None; - } - if (node.is_reroute_node()) { - return InputSocketFieldType::IsSupported; - } - if (node.is_group_output_node()) { - /* Outputs always support fields when the data type is correct. */ - return InputSocketFieldType::IsSupported; - } - if (node.is_undefined()) { - return InputSocketFieldType::None; - } - - const NodeDeclaration *node_decl = node.declaration(); - - /* Node declarations should be implemented for nodes involved here. */ - BLI_assert(node_decl != nullptr); - - /* Get the field type from the declaration. */ - const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()]; - const InputSocketFieldType field_type = socket_decl.input_field_type(); - if (field_type == InputSocketFieldType::Implicit) { - return field_type; - } - if (node_decl->is_function_node()) { - /* In a function node, every socket supports fields. */ - return InputSocketFieldType::IsSupported; - } - return field_type; -} - -static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, - const OutputSocketRef &socket) -{ - if (!is_field_socket_type(socket)) { - /* Non-field sockets always output data. */ - return OutputFieldDependency::ForDataSource(); - } - if (node.is_reroute_node()) { - /* The reroute just forwards what is passed in. */ - return OutputFieldDependency::ForDependentField(); - } - if (node.is_group_input_node()) { - /* Input nodes get special treatment in #determine_group_input_states. */ - return OutputFieldDependency::ForDependentField(); - } - if (node.is_undefined()) { - return OutputFieldDependency::ForDataSource(); - } - - const NodeDeclaration *node_decl = node.declaration(); - - /* Node declarations should be implemented for nodes involved here. */ - BLI_assert(node_decl != nullptr); - - if (node_decl->is_function_node()) { - /* In a generic function node, all outputs depend on all inputs. */ - return OutputFieldDependency::ForDependentField(); - } - - /* Use the socket declaration. */ - const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()]; - return socket_decl.output_field_dependency(); -} - -static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) -{ - FieldInferencingInterface inferencing_interface; - inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); - inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), - node.outputs().size()); - return inferencing_interface; -} - -/** - * Retrieves information about how the node interacts with fields. - * In the future, this information can be stored in the node declaration. This would allow this - * function to return a reference, making it more efficient. - */ -static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) -{ - /* Node groups already reference all required information, so just return that. */ - if (node.is_group_node()) { - bNodeTree *group = (bNodeTree *)node.bnode()->id; - if (group == nullptr) { - return FieldInferencingInterface(); - } - if (!ntreeIsRegistered(group)) { - /* This can happen when there is a linked node group that was not found (see T92799). */ - return get_dummy_field_inferencing_interface(node); - } - if (group->field_inferencing_interface == nullptr) { - /* Update group recursively. */ - update_field_inferencing(*group); - } - return *group->field_inferencing_interface; - } - - FieldInferencingInterface inferencing_interface; - for (const InputSocketRef *input_socket : node.inputs()) { - inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); - } - - for (const OutputSocketRef *output_socket : node.outputs()) { - inferencing_interface.outputs.append( - get_interface_output_field_dependency(node, *output_socket)); - } - return inferencing_interface; -} - -/** - * This struct contains information for every socket. The values are propagated through the - * network. - */ -struct SocketFieldState { - /* This socket starts a new field. */ - bool is_field_source = false; - /* This socket can never become a field, because the node itself does not support it. */ - bool is_always_single = false; - /* This socket is currently a single value. It could become a field though. */ - bool is_single = true; - /* This socket is required to be a single value. This can be because the node itself only - * supports this socket to be a single value, or because a node afterwards requires this to be a - * single value. */ - bool requires_single = false; -}; - -static Vector<const InputSocketRef *> gather_input_socket_dependencies( - const OutputFieldDependency &field_dependency, const NodeRef &node) -{ - const OutputSocketFieldType type = field_dependency.field_type(); - Vector<const InputSocketRef *> input_sockets; - switch (type) { - case OutputSocketFieldType::FieldSource: - case OutputSocketFieldType::None: { - break; - } - case OutputSocketFieldType::DependentField: { - /* This output depends on all inputs. */ - input_sockets.extend(node.inputs()); - break; - } - case OutputSocketFieldType::PartiallyDependent: { - /* This output depends only on a few inputs. */ - for (const int i : field_dependency.linked_input_indices()) { - input_sockets.append(&node.input(i)); - } - break; - } - } - return input_sockets; -} - -/** - * Check what the group output socket depends on. Potentially traverses the node tree - * to figure out if it is always a field or if it depends on any group inputs. - */ -static OutputFieldDependency find_group_output_dependencies( - const InputSocketRef &group_output_socket, - const Span<SocketFieldState> field_state_by_socket_id) -{ - if (!is_field_socket_type(group_output_socket)) { - return OutputFieldDependency::ForDataSource(); - } - - /* Use a Set here instead of an array indexed by socket id, because we my only need to look at - * very few sockets. */ - Set<const InputSocketRef *> handled_sockets; - Stack<const InputSocketRef *> sockets_to_check; - - handled_sockets.add(&group_output_socket); - sockets_to_check.push(&group_output_socket); - - /* Keeps track of group input indices that are (indirectly) connected to the output. */ - Vector<int> linked_input_indices; - - while (!sockets_to_check.is_empty()) { - const InputSocketRef *input_socket = sockets_to_check.pop(); - - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - const NodeRef &origin_node = origin_socket->node(); - const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; - - if (origin_state.is_field_source) { - if (origin_node.is_group_input_node()) { - /* Found a group input that the group output depends on. */ - linked_input_indices.append_non_duplicates(origin_socket->index()); - } - else { - /* Found a field source that is not the group input. So the output is always a field. */ - return OutputFieldDependency::ForFieldSource(); - } - } - else if (!origin_state.is_single) { - const FieldInferencingInterface inferencing_interface = - get_node_field_inferencing_interface(origin_node); - const OutputFieldDependency &field_dependency = - inferencing_interface.outputs[origin_socket->index()]; - - /* Propagate search further to the left. */ - for (const InputSocketRef *origin_input_socket : - gather_input_socket_dependencies(field_dependency, origin_node)) { - if (!origin_input_socket->is_available()) { - continue; - } - if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { - if (handled_sockets.add(origin_input_socket)) { - sockets_to_check.push(origin_input_socket); - } - } - } - } - } - } - return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices)); -} - -static void propagate_data_requirements_from_right_to_left( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) -{ - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::RightToLeft); - - for (const NodeRef *node : toposort_result.sorted_nodes) { - const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( - *node); - - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; - - const OutputFieldDependency &field_dependency = - inferencing_interface.outputs[output_socket->index()]; - - if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) { - continue; - } - if (field_dependency.field_type() == OutputSocketFieldType::None) { - state.requires_single = true; - state.is_always_single = true; - continue; - } - - /* The output is required to be a single value when it is connected to any input that does - * not support fields. */ - for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { - if (target_socket->is_available()) { - state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; - } - } - - if (state.requires_single) { - bool any_input_is_field_implicitly = false; - const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies( - field_dependency, *node); - for (const InputSocketRef *input_socket : connected_inputs) { - if (!input_socket->is_available()) { - continue; - } - if (inferencing_interface.inputs[input_socket->index()] == - InputSocketFieldType::Implicit) { - if (!input_socket->is_logically_linked()) { - any_input_is_field_implicitly = true; - break; - } - } - } - if (any_input_is_field_implicitly) { - /* This output isn't a single value actually. */ - state.requires_single = false; - } - else { - /* If the output is required to be a single value, the connected inputs in the same node - * must not be fields as well. */ - for (const InputSocketRef *input_socket : connected_inputs) { - field_state_by_socket_id[input_socket->id()].requires_single = true; - } - } - } - } - - /* Some inputs do not require fields independent of what the outputs are connected to. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; - if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { - state.requires_single = true; - state.is_always_single = true; - } - } - } -} - -static void determine_group_input_states( - const NodeTreeRef &tree, - FieldInferencingInterface &new_inferencing_interface, - const MutableSpan<SocketFieldState> field_state_by_socket_id) -{ - { - /* Non-field inputs never support fields. */ - int index; - LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { - if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { - new_inferencing_interface.inputs[index] = InputSocketFieldType::None; - } - } - } - /* Check if group inputs are required to be single values, because they are (indirectly) - * connected to some socket that does not support fields. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; - if (state.requires_single) { - new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; - } - } - } - /* If an input does not support fields, this should be reflected in all Group Input nodes. */ - for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { - for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; - const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != - InputSocketFieldType::None; - if (supports_field) { - state.is_single = false; - state.is_field_source = true; - } - else { - state.requires_single = true; - } - } - SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; - dummy_socket_state.requires_single = true; - } -} - -static void propagate_field_status_from_left_to_right( - const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) -{ - const NodeTreeRef::ToposortResult toposort_result = tree.toposort( - NodeTreeRef::ToposortDirection::LeftToRight); - - for (const NodeRef *node : toposort_result.sorted_nodes) { - if (node->is_group_input_node()) { - continue; - } - - const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( - *node); - - /* Update field state of input sockets, also taking into account linked origin sockets. */ - for (const InputSocketRef *input_socket : node->inputs()) { - SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; - if (state.is_always_single) { - state.is_single = true; - continue; - } - state.is_single = true; - if (input_socket->directly_linked_sockets().is_empty()) { - if (inferencing_interface.inputs[input_socket->index()] == - InputSocketFieldType::Implicit) { - state.is_single = false; - } - } - else { - for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { - if (!field_state_by_socket_id[origin_socket->id()].is_single) { - state.is_single = false; - break; - } - } - } - } - - /* Update field state of output sockets, also taking into account input sockets. */ - for (const OutputSocketRef *output_socket : node->outputs()) { - SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; - const OutputFieldDependency &field_dependency = - inferencing_interface.outputs[output_socket->index()]; - - switch (field_dependency.field_type()) { - case OutputSocketFieldType::None: { - state.is_single = true; - break; - } - case OutputSocketFieldType::FieldSource: { - state.is_single = false; - state.is_field_source = true; - break; - } - case OutputSocketFieldType::PartiallyDependent: - case OutputSocketFieldType::DependentField: { - for (const InputSocketRef *input_socket : - gather_input_socket_dependencies(field_dependency, *node)) { - if (!input_socket->is_available()) { - continue; - } - if (!field_state_by_socket_id[input_socket->id()].is_single) { - state.is_single = false; - break; - } - } - break; - } - } - } - } -} - -static void determine_group_output_states(const NodeTreeRef &tree, - FieldInferencingInterface &new_inferencing_interface, - const Span<SocketFieldState> field_state_by_socket_id) -{ - for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { - /* Ignore inactive group output nodes. */ - if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { - continue; - } - /* Determine dependencies of all group outputs. */ - for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { - OutputFieldDependency field_dependency = find_group_output_dependencies( - *group_output_socket, field_state_by_socket_id); - new_inferencing_interface.outputs[group_output_socket->index()] = std::move( - field_dependency); - } - break; - } -} - -static void update_socket_shapes(const NodeTreeRef &tree, - const Span<SocketFieldState> field_state_by_socket_id) -{ - const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; - const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT; - const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND; - - auto get_shape_for_state = [&](const SocketFieldState &state) { - if (state.is_always_single) { - return requires_data_shape; - } - if (!state.is_single) { - return is_field_shape; - } - if (state.requires_single) { - return requires_data_shape; - } - return data_but_can_be_field_shape; - }; - - for (const InputSocketRef *socket : tree.input_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); - } - for (const OutputSocketRef *socket : tree.output_sockets()) { - bNodeSocket *bsocket = socket->bsocket(); - const SocketFieldState &state = field_state_by_socket_id[socket->id()]; - bsocket->display_shape = get_shape_for_state(state); - } -} - -static bool update_field_inferencing(bNodeTree &btree) -{ - using namespace blender::nodes; - if (btree.type != NTREE_GEOMETRY) { - return false; - } - - /* Create new inferencing interface for this node group. */ - FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface(); - new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), - InputSocketFieldType::IsSupported); - new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), - OutputFieldDependency::ForDataSource()); - - /* Create #NodeTreeRef to accelerate various queries on the node tree (e.g. linked sockets). */ - const NodeTreeRef tree{&btree}; - - /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ - Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size()); - - propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); - determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); - propagate_field_status_from_left_to_right(tree, field_state_by_socket_id); - determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id); - update_socket_shapes(tree, field_state_by_socket_id); - - /* Update the previous group interface. */ - const bool group_interface_changed = btree.field_inferencing_interface == nullptr || - *btree.field_inferencing_interface != - *new_inferencing_interface; - delete btree.field_inferencing_interface; - btree.field_inferencing_interface = new_inferencing_interface; - - return group_interface_changed; -} - -} // namespace blender::bke::node_field_inferencing - -void ntreeUpdateAllUsers(Main *main, ID *id, const int tree_update_flag) +void ntreeUpdateAllUsers(Main *main, ID *id) { if (id == nullptr) { return; } + bool need_update = false; + /* Update all users of ngroup, to add/remove sockets as needed. */ FOREACH_NODETREE_BEGIN (main, ntree, owner_id) { - bool need_update = false; - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->id == id) { - if (node->typeinfo->group_update_func) { - node->typeinfo->group_update_func(ntree, node); - } - + BKE_ntree_update_tag_node_property(ntree, node); need_update = true; } } - - if (need_update) { - ntree->update |= tree_update_flag; - ntreeUpdateTree(tree_update_flag ? main : nullptr, ntree); - } } FOREACH_NODETREE_END; - - if (GS(id->name) == ID_NT) { - bNodeTree *ngroup = (bNodeTree *)id; - if (ngroup->type == NTREE_GEOMETRY && (ngroup->update & NTREE_UPDATE_GROUP)) { - LISTBASE_FOREACH (Object *, object, &main->objects) { - LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { - if (md->type == eModifierType_Nodes) { - NodesModifierData *nmd = (NodesModifierData *)md; - if (nmd->node_group == ngroup) { - MOD_nodes_update_interface(object, nmd); - } - } - } - } - } - } -} - -void ntreeUpdateTree(Main *bmain, bNodeTree *ntree) -{ - if (!ntree) { - return; - } - - /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ - if (ntree->is_updating) { - return; - } - ntree->is_updating = true; - - if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) { - /* set the bNodeSocket->link pointers */ - ntree_update_link_pointers(ntree); - } - - /* update individual nodes */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - /* node tree update tags override individual node update flags */ - if ((node->update & NODE_UPDATE) || (ntree->update & NTREE_UPDATE)) { - if (node->typeinfo->updatefunc) { - node->typeinfo->updatefunc(ntree, node); - } - - nodeUpdateInternalLinks(ntree, node); - } - } - - /* generic tree update callback */ - if (ntree->typeinfo->update) { - ntree->typeinfo->update(ntree); - } - /* XXX this should be moved into the tree type update callback for tree supporting node groups. - * Currently the node tree interface is still a generic feature of the base NodeTree type. - */ - if (ntree->update & NTREE_UPDATE_GROUP) { - ntreeInterfaceTypeUpdate(ntree); - } - - int tree_user_update_flag = 0; - - if (ntree->update & NTREE_UPDATE) { - /* If the field interface of this node tree has changed, all node trees using - * this group will need to recalculate their interface as well. */ - if (blender::bke::node_field_inferencing::update_field_inferencing(*ntree)) { - tree_user_update_flag |= NTREE_UPDATE_FIELD_INFERENCING; - } - } - - if (bmain) { - ntreeUpdateAllUsers(bmain, &ntree->id, tree_user_update_flag); - } - - if (ntree->update & (NTREE_UPDATE_LINKS | NTREE_UPDATE_NODES)) { - /* node updates can change sockets or links, repeat link pointer update afterward */ - ntree_update_link_pointers(ntree); - - /* update the node level from link dependencies */ - ntree_update_node_level(ntree); - - /* check link validity */ - ntree_validate_links(ntree); - } - - /* clear update flags */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - node->update = 0; - } - ntree->update = 0; - - ntree->is_updating = false; -} - -void nodeUpdate(bNodeTree *ntree, bNode *node) -{ - /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ - if (ntree->is_updating) { - return; - } - ntree->is_updating = true; - - if (node->typeinfo->updatefunc) { - node->typeinfo->updatefunc(ntree, node); - } - - nodeUpdateInternalLinks(ntree, node); - - /* clear update flag */ - node->update = 0; - - ntree->is_updating = false; -} - -bool nodeUpdateID(bNodeTree *ntree, ID *id) -{ - bool changed = false; - - if (ELEM(nullptr, id, ntree)) { - return changed; - } - - /* Avoid re-entrant updates, can be caused by RNA update callbacks. */ - if (ntree->is_updating) { - return changed; - } - ntree->is_updating = true; - - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->id == id) { - changed = true; - node->update |= NODE_UPDATE_ID; - if (node->typeinfo->updatefunc) { - node->typeinfo->updatefunc(ntree, node); - } - /* clear update flag */ - node->update = 0; - } - } - - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - nodeUpdateInternalLinks(ntree, node); - } - - ntree->is_updating = false; - return changed; -} - -void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) -{ - BLI_freelistN(&node->internal_links); - if (!node->typeinfo->no_muting) { - node_internal_links_create(ntree, node); + if (need_update) { + BKE_ntree_update_main(main, nullptr); } } @@ -5261,8 +4357,7 @@ static bool node_poll_instance_default(bNode *node, bNodeTree *ntree, const char return node->typeinfo->poll(node->typeinfo, ntree, disabled_hint); } -/* NOLINTNEXTLINE: readability-function-size */ -void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) +void node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { /* Use static type info header to map static int type to identifier string and RNA struct type. * Associate the RNA struct type with the bNodeType. @@ -5289,7 +4384,6 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, ntype->type = type; BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); ntype->nclass = nclass; - ntype->flag = flag; node_type_base_defaults(ntype); @@ -5297,14 +4391,12 @@ void node_type_base(bNodeType *ntype, int type, const char *name, short nclass, ntype->poll_instance = node_poll_instance_default; } -void node_type_base_custom( - bNodeType *ntype, const char *idname, const char *name, short nclass, short flag) +void node_type_base_custom(bNodeType *ntype, const char *idname, const char *name, short nclass) { BLI_strncpy(ntype->idname, idname, sizeof(ntype->idname)); ntype->type = NODE_CUSTOM; BLI_strncpy(ntype->ui_name, name, sizeof(ntype->ui_name)); ntype->nclass = nclass; - ntype->flag = flag; node_type_base_defaults(ntype); } @@ -5480,7 +4572,7 @@ static void register_undefined_types() strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); - node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0, 0); + node_type_base_custom(&NodeTypeUndefined, "NodeUndefined", "Undefined", 0); NodeTypeUndefined.poll = node_undefined_poll; BLI_strncpy(NodeSocketTypeUndefined.idname, @@ -5774,6 +4866,7 @@ static void registerGeometryNodes() register_node_type_geo_legacy_subdivision_surface(); register_node_type_geo_legacy_volume_to_mesh(); + register_node_type_geo_accumulate_field(); register_node_type_geo_align_rotation_to_vector(); register_node_type_geo_attribute_capture(); register_node_type_geo_attribute_clamp(); @@ -5830,6 +4923,7 @@ static void registerGeometryNodes() register_node_type_geo_input_index(); register_node_type_geo_input_material_index(); register_node_type_geo_input_material(); + register_node_type_geo_input_mesh_edge_angle(); register_node_type_geo_input_mesh_edge_neighbors(); register_node_type_geo_input_mesh_edge_vertices(); register_node_type_geo_input_mesh_face_area(); diff --git a/source/blender/blenkernel/intern/node_tree_update.cc b/source/blender/blenkernel/intern/node_tree_update.cc new file mode 100644 index 00000000000..be9777281cb --- /dev/null +++ b/source/blender/blenkernel/intern/node_tree_update.cc @@ -0,0 +1,1669 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_map.hh" +#include "BLI_multi_value_map.hh" +#include "BLI_noise.hh" +#include "BLI_set.hh" +#include "BLI_stack.hh" +#include "BLI_vector_set.hh" + +#include "DNA_anim_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + +#include "BKE_anim_data.h" +#include "BKE_main.h" +#include "BKE_node.h" +#include "BKE_node_tree_update.h" + +#include "MOD_nodes.h" + +#include "NOD_node_declaration.hh" +#include "NOD_node_tree_ref.hh" + +#include "DEG_depsgraph_query.h" + +using namespace blender::nodes; + +/** + * These flags are used by the `changed_flag` field in #bNodeTree, #bNode and #bNodeSocket. + * This enum is not part of the public api. It should be used through the `BKE_ntree_update_tag_*` + * api. + */ +enum eNodeTreeChangedFlag { + NTREE_CHANGED_NOTHING = 0, + NTREE_CHANGED_ANY = (1 << 1), + NTREE_CHANGED_NODE_PROPERTY = (1 << 2), + NTREE_CHANGED_NODE_OUTPUT = (1 << 3), + NTREE_CHANGED_INTERFACE = (1 << 4), + NTREE_CHANGED_LINK = (1 << 5), + NTREE_CHANGED_REMOVED_NODE = (1 << 6), + NTREE_CHANGED_REMOVED_SOCKET = (1 << 7), + NTREE_CHANGED_SOCKET_PROPERTY = (1 << 8), + NTREE_CHANGED_INTERNAL_LINK = (1 << 9), + NTREE_CHANGED_ALL = -1, +}; + +static void add_tree_tag(bNodeTree *ntree, const eNodeTreeChangedFlag flag) +{ + ntree->changed_flag |= flag; +} + +static void add_node_tag(bNodeTree *ntree, bNode *node, const eNodeTreeChangedFlag flag) +{ + add_tree_tag(ntree, flag); + node->changed_flag |= flag; +} + +static void add_socket_tag(bNodeTree *ntree, bNodeSocket *socket, const eNodeTreeChangedFlag flag) +{ + add_tree_tag(ntree, flag); + socket->changed_flag |= flag; +} + +namespace blender::bke { + +namespace node_field_inferencing { + +static bool is_field_socket_type(eNodeSocketDatatype type) +{ + return ELEM(type, SOCK_FLOAT, SOCK_INT, SOCK_BOOLEAN, SOCK_VECTOR, SOCK_RGBA); +} + +static bool is_field_socket_type(const SocketRef &socket) +{ + return is_field_socket_type((eNodeSocketDatatype)socket.typeinfo()->type); +} + +static InputSocketFieldType get_interface_input_field_type(const NodeRef &node, + const InputSocketRef &socket) +{ + if (!is_field_socket_type(socket)) { + return InputSocketFieldType::None; + } + if (node.is_reroute_node()) { + return InputSocketFieldType::IsSupported; + } + if (node.is_group_output_node()) { + /* Outputs always support fields when the data type is correct. */ + return InputSocketFieldType::IsSupported; + } + if (node.is_undefined()) { + return InputSocketFieldType::None; + } + + const NodeDeclaration *node_decl = node.declaration(); + + /* Node declarations should be implemented for nodes involved here. */ + BLI_assert(node_decl != nullptr); + + /* Get the field type from the declaration. */ + const SocketDeclaration &socket_decl = *node_decl->inputs()[socket.index()]; + const InputSocketFieldType field_type = socket_decl.input_field_type(); + if (field_type == InputSocketFieldType::Implicit) { + return field_type; + } + if (node_decl->is_function_node()) { + /* In a function node, every socket supports fields. */ + return InputSocketFieldType::IsSupported; + } + return field_type; +} + +static OutputFieldDependency get_interface_output_field_dependency(const NodeRef &node, + const OutputSocketRef &socket) +{ + if (!is_field_socket_type(socket)) { + /* Non-field sockets always output data. */ + return OutputFieldDependency::ForDataSource(); + } + if (node.is_reroute_node()) { + /* The reroute just forwards what is passed in. */ + return OutputFieldDependency::ForDependentField(); + } + if (node.is_group_input_node()) { + /* Input nodes get special treatment in #determine_group_input_states. */ + return OutputFieldDependency::ForDependentField(); + } + if (node.is_undefined()) { + return OutputFieldDependency::ForDataSource(); + } + + const NodeDeclaration *node_decl = node.declaration(); + + /* Node declarations should be implemented for nodes involved here. */ + BLI_assert(node_decl != nullptr); + + if (node_decl->is_function_node()) { + /* In a generic function node, all outputs depend on all inputs. */ + return OutputFieldDependency::ForDependentField(); + } + + /* Use the socket declaration. */ + const SocketDeclaration &socket_decl = *node_decl->outputs()[socket.index()]; + return socket_decl.output_field_dependency(); +} + +static FieldInferencingInterface get_dummy_field_inferencing_interface(const NodeRef &node) +{ + FieldInferencingInterface inferencing_interface; + inferencing_interface.inputs.append_n_times(InputSocketFieldType::None, node.inputs().size()); + inferencing_interface.outputs.append_n_times(OutputFieldDependency::ForDataSource(), + node.outputs().size()); + return inferencing_interface; +} + +/** + * Retrieves information about how the node interacts with fields. + * In the future, this information can be stored in the node declaration. This would allow this + * function to return a reference, making it more efficient. + */ +static FieldInferencingInterface get_node_field_inferencing_interface(const NodeRef &node) +{ + /* Node groups already reference all required information, so just return that. */ + if (node.is_group_node()) { + bNodeTree *group = (bNodeTree *)node.bnode()->id; + if (group == nullptr) { + return FieldInferencingInterface(); + } + if (!ntreeIsRegistered(group)) { + /* This can happen when there is a linked node group that was not found (see T92799). */ + return get_dummy_field_inferencing_interface(node); + } + if (group->field_inferencing_interface == nullptr) { + /* This shouldn't happen because referenced node groups should always be updated first. */ + BLI_assert_unreachable(); + } + return *group->field_inferencing_interface; + } + + FieldInferencingInterface inferencing_interface; + for (const InputSocketRef *input_socket : node.inputs()) { + inferencing_interface.inputs.append(get_interface_input_field_type(node, *input_socket)); + } + + for (const OutputSocketRef *output_socket : node.outputs()) { + inferencing_interface.outputs.append( + get_interface_output_field_dependency(node, *output_socket)); + } + return inferencing_interface; +} + +/** + * This struct contains information for every socket. The values are propagated through the + * network. + */ +struct SocketFieldState { + /* This socket starts a new field. */ + bool is_field_source = false; + /* This socket can never become a field, because the node itself does not support it. */ + bool is_always_single = false; + /* This socket is currently a single value. It could become a field though. */ + bool is_single = true; + /* This socket is required to be a single value. This can be because the node itself only + * supports this socket to be a single value, or because a node afterwards requires this to be a + * single value. */ + bool requires_single = false; +}; + +static Vector<const InputSocketRef *> gather_input_socket_dependencies( + const OutputFieldDependency &field_dependency, const NodeRef &node) +{ + const OutputSocketFieldType type = field_dependency.field_type(); + Vector<const InputSocketRef *> input_sockets; + switch (type) { + case OutputSocketFieldType::FieldSource: + case OutputSocketFieldType::None: { + break; + } + case OutputSocketFieldType::DependentField: { + /* This output depends on all inputs. */ + input_sockets.extend(node.inputs()); + break; + } + case OutputSocketFieldType::PartiallyDependent: { + /* This output depends only on a few inputs. */ + for (const int i : field_dependency.linked_input_indices()) { + input_sockets.append(&node.input(i)); + } + break; + } + } + return input_sockets; +} + +/** + * Check what the group output socket depends on. Potentially traverses the node tree + * to figure out if it is always a field or if it depends on any group inputs. + */ +static OutputFieldDependency find_group_output_dependencies( + const InputSocketRef &group_output_socket, + const Span<SocketFieldState> field_state_by_socket_id) +{ + if (!is_field_socket_type(group_output_socket)) { + return OutputFieldDependency::ForDataSource(); + } + + /* Use a Set here instead of an array indexed by socket id, because we my only need to look at + * very few sockets. */ + Set<const InputSocketRef *> handled_sockets; + Stack<const InputSocketRef *> sockets_to_check; + + handled_sockets.add(&group_output_socket); + sockets_to_check.push(&group_output_socket); + + /* Keeps track of group input indices that are (indirectly) connected to the output. */ + Vector<int> linked_input_indices; + + while (!sockets_to_check.is_empty()) { + const InputSocketRef *input_socket = sockets_to_check.pop(); + + for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { + const NodeRef &origin_node = origin_socket->node(); + const SocketFieldState &origin_state = field_state_by_socket_id[origin_socket->id()]; + + if (origin_state.is_field_source) { + if (origin_node.is_group_input_node()) { + /* Found a group input that the group output depends on. */ + linked_input_indices.append_non_duplicates(origin_socket->index()); + } + else { + /* Found a field source that is not the group input. So the output is always a field. */ + return OutputFieldDependency::ForFieldSource(); + } + } + else if (!origin_state.is_single) { + const FieldInferencingInterface inferencing_interface = + get_node_field_inferencing_interface(origin_node); + const OutputFieldDependency &field_dependency = + inferencing_interface.outputs[origin_socket->index()]; + + /* Propagate search further to the left. */ + for (const InputSocketRef *origin_input_socket : + gather_input_socket_dependencies(field_dependency, origin_node)) { + if (!origin_input_socket->is_available()) { + continue; + } + if (!field_state_by_socket_id[origin_input_socket->id()].is_single) { + if (handled_sockets.add(origin_input_socket)) { + sockets_to_check.push(origin_input_socket); + } + } + } + } + } + } + return OutputFieldDependency::ForPartiallyDependentField(std::move(linked_input_indices)); +} + +static void propagate_data_requirements_from_right_to_left( + const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) +{ + const NodeTreeRef::ToposortResult toposort_result = tree.toposort( + NodeTreeRef::ToposortDirection::RightToLeft); + + for (const NodeRef *node : toposort_result.sorted_nodes) { + const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( + *node); + + for (const OutputSocketRef *output_socket : node->outputs()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + + const OutputFieldDependency &field_dependency = + inferencing_interface.outputs[output_socket->index()]; + + if (field_dependency.field_type() == OutputSocketFieldType::FieldSource) { + continue; + } + if (field_dependency.field_type() == OutputSocketFieldType::None) { + state.requires_single = true; + state.is_always_single = true; + continue; + } + + /* The output is required to be a single value when it is connected to any input that does + * not support fields. */ + for (const InputSocketRef *target_socket : output_socket->directly_linked_sockets()) { + if (target_socket->is_available()) { + state.requires_single |= field_state_by_socket_id[target_socket->id()].requires_single; + } + } + + if (state.requires_single) { + bool any_input_is_field_implicitly = false; + const Vector<const InputSocketRef *> connected_inputs = gather_input_socket_dependencies( + field_dependency, *node); + for (const InputSocketRef *input_socket : connected_inputs) { + if (!input_socket->is_available()) { + continue; + } + if (inferencing_interface.inputs[input_socket->index()] == + InputSocketFieldType::Implicit) { + if (!input_socket->is_logically_linked()) { + any_input_is_field_implicitly = true; + break; + } + } + } + if (any_input_is_field_implicitly) { + /* This output isn't a single value actually. */ + state.requires_single = false; + } + else { + /* If the output is required to be a single value, the connected inputs in the same node + * must not be fields as well. */ + for (const InputSocketRef *input_socket : connected_inputs) { + field_state_by_socket_id[input_socket->id()].requires_single = true; + } + } + } + } + + /* Some inputs do not require fields independent of what the outputs are connected to. */ + for (const InputSocketRef *input_socket : node->inputs()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + if (inferencing_interface.inputs[input_socket->index()] == InputSocketFieldType::None) { + state.requires_single = true; + state.is_always_single = true; + } + } + } +} + +static void determine_group_input_states( + const NodeTreeRef &tree, + FieldInferencingInterface &new_inferencing_interface, + const MutableSpan<SocketFieldState> field_state_by_socket_id) +{ + { + /* Non-field inputs never support fields. */ + int index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, group_input, &tree.btree()->inputs, index) { + if (!is_field_socket_type((eNodeSocketDatatype)group_input->type)) { + new_inferencing_interface.inputs[index] = InputSocketFieldType::None; + } + } + } + /* Check if group inputs are required to be single values, because they are (indirectly) + * connected to some socket that does not support fields. */ + for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { + for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + if (state.requires_single) { + new_inferencing_interface.inputs[output_socket->index()] = InputSocketFieldType::None; + } + } + } + /* If an input does not support fields, this should be reflected in all Group Input nodes. */ + for (const NodeRef *node : tree.nodes_by_type("NodeGroupInput")) { + for (const OutputSocketRef *output_socket : node->outputs().drop_back(1)) { + SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + const bool supports_field = new_inferencing_interface.inputs[output_socket->index()] != + InputSocketFieldType::None; + if (supports_field) { + state.is_single = false; + state.is_field_source = true; + } + else { + state.requires_single = true; + } + } + SocketFieldState &dummy_socket_state = field_state_by_socket_id[node->outputs().last()->id()]; + dummy_socket_state.requires_single = true; + } +} + +static void propagate_field_status_from_left_to_right( + const NodeTreeRef &tree, const MutableSpan<SocketFieldState> field_state_by_socket_id) +{ + const NodeTreeRef::ToposortResult toposort_result = tree.toposort( + NodeTreeRef::ToposortDirection::LeftToRight); + + for (const NodeRef *node : toposort_result.sorted_nodes) { + if (node->is_group_input_node()) { + continue; + } + + const FieldInferencingInterface inferencing_interface = get_node_field_inferencing_interface( + *node); + + /* Update field state of input sockets, also taking into account linked origin sockets. */ + for (const InputSocketRef *input_socket : node->inputs()) { + SocketFieldState &state = field_state_by_socket_id[input_socket->id()]; + if (state.is_always_single) { + state.is_single = true; + continue; + } + state.is_single = true; + if (input_socket->directly_linked_sockets().is_empty()) { + if (inferencing_interface.inputs[input_socket->index()] == + InputSocketFieldType::Implicit) { + state.is_single = false; + } + } + else { + for (const OutputSocketRef *origin_socket : input_socket->directly_linked_sockets()) { + if (!field_state_by_socket_id[origin_socket->id()].is_single) { + state.is_single = false; + break; + } + } + } + } + + /* Update field state of output sockets, also taking into account input sockets. */ + for (const OutputSocketRef *output_socket : node->outputs()) { + SocketFieldState &state = field_state_by_socket_id[output_socket->id()]; + const OutputFieldDependency &field_dependency = + inferencing_interface.outputs[output_socket->index()]; + + switch (field_dependency.field_type()) { + case OutputSocketFieldType::None: { + state.is_single = true; + break; + } + case OutputSocketFieldType::FieldSource: { + state.is_single = false; + state.is_field_source = true; + break; + } + case OutputSocketFieldType::PartiallyDependent: + case OutputSocketFieldType::DependentField: { + for (const InputSocketRef *input_socket : + gather_input_socket_dependencies(field_dependency, *node)) { + if (!input_socket->is_available()) { + continue; + } + if (!field_state_by_socket_id[input_socket->id()].is_single) { + state.is_single = false; + break; + } + } + break; + } + } + } + } +} + +static void determine_group_output_states(const NodeTreeRef &tree, + FieldInferencingInterface &new_inferencing_interface, + const Span<SocketFieldState> field_state_by_socket_id) +{ + for (const NodeRef *group_output_node : tree.nodes_by_type("NodeGroupOutput")) { + /* Ignore inactive group output nodes. */ + if (!(group_output_node->bnode()->flag & NODE_DO_OUTPUT)) { + continue; + } + /* Determine dependencies of all group outputs. */ + for (const InputSocketRef *group_output_socket : group_output_node->inputs().drop_back(1)) { + OutputFieldDependency field_dependency = find_group_output_dependencies( + *group_output_socket, field_state_by_socket_id); + new_inferencing_interface.outputs[group_output_socket->index()] = std::move( + field_dependency); + } + break; + } +} + +static void update_socket_shapes(const NodeTreeRef &tree, + const Span<SocketFieldState> field_state_by_socket_id) +{ + const eNodeSocketDisplayShape requires_data_shape = SOCK_DISPLAY_SHAPE_CIRCLE; + const eNodeSocketDisplayShape data_but_can_be_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND_DOT; + const eNodeSocketDisplayShape is_field_shape = SOCK_DISPLAY_SHAPE_DIAMOND; + + auto get_shape_for_state = [&](const SocketFieldState &state) { + if (state.is_always_single) { + return requires_data_shape; + } + if (!state.is_single) { + return is_field_shape; + } + if (state.requires_single) { + return requires_data_shape; + } + return data_but_can_be_field_shape; + }; + + for (const InputSocketRef *socket : tree.input_sockets()) { + bNodeSocket *bsocket = socket->bsocket(); + const SocketFieldState &state = field_state_by_socket_id[socket->id()]; + bsocket->display_shape = get_shape_for_state(state); + } + for (const OutputSocketRef *socket : tree.output_sockets()) { + bNodeSocket *bsocket = socket->bsocket(); + const SocketFieldState &state = field_state_by_socket_id[socket->id()]; + bsocket->display_shape = get_shape_for_state(state); + } +} + +static bool update_field_inferencing(const NodeTreeRef &tree) +{ + bNodeTree &btree = *tree.btree(); + + /* Create new inferencing interface for this node group. */ + FieldInferencingInterface *new_inferencing_interface = new FieldInferencingInterface(); + new_inferencing_interface->inputs.resize(BLI_listbase_count(&btree.inputs), + InputSocketFieldType::IsSupported); + new_inferencing_interface->outputs.resize(BLI_listbase_count(&btree.outputs), + OutputFieldDependency::ForDataSource()); + + /* Keep track of the state of all sockets. The index into this array is #SocketRef::id(). */ + Array<SocketFieldState> field_state_by_socket_id(tree.sockets().size()); + + propagate_data_requirements_from_right_to_left(tree, field_state_by_socket_id); + determine_group_input_states(tree, *new_inferencing_interface, field_state_by_socket_id); + propagate_field_status_from_left_to_right(tree, field_state_by_socket_id); + determine_group_output_states(tree, *new_inferencing_interface, field_state_by_socket_id); + update_socket_shapes(tree, field_state_by_socket_id); + + /* Update the previous group interface. */ + const bool group_interface_changed = btree.field_inferencing_interface == nullptr || + *btree.field_inferencing_interface != + *new_inferencing_interface; + delete btree.field_inferencing_interface; + btree.field_inferencing_interface = new_inferencing_interface; + + return group_interface_changed; +} + +} // namespace node_field_inferencing + +/** + * Common datatype priorities, works for compositor, shader and texture nodes alike + * defines priority of datatype connection based on output type (to): + * `< 0`: never connect these types. + * `>= 0`: priority of connection (higher values chosen first). + */ +static int get_internal_link_type_priority(const bNodeSocketType *from, const bNodeSocketType *to) +{ + switch (to->type) { + case SOCK_RGBA: + switch (from->type) { + case SOCK_RGBA: + return 4; + case SOCK_FLOAT: + return 3; + case SOCK_INT: + return 2; + case SOCK_BOOLEAN: + return 1; + } + return -1; + case SOCK_VECTOR: + switch (from->type) { + case SOCK_VECTOR: + return 4; + case SOCK_FLOAT: + return 3; + case SOCK_INT: + return 2; + case SOCK_BOOLEAN: + return 1; + } + return -1; + case SOCK_FLOAT: + switch (from->type) { + case SOCK_FLOAT: + return 5; + case SOCK_INT: + return 4; + case SOCK_BOOLEAN: + return 3; + case SOCK_RGBA: + return 2; + case SOCK_VECTOR: + return 1; + } + return -1; + case SOCK_INT: + switch (from->type) { + case SOCK_INT: + return 5; + case SOCK_FLOAT: + return 4; + case SOCK_BOOLEAN: + return 3; + case SOCK_RGBA: + return 2; + case SOCK_VECTOR: + return 1; + } + return -1; + case SOCK_BOOLEAN: + switch (from->type) { + case SOCK_BOOLEAN: + return 5; + case SOCK_INT: + return 4; + case SOCK_FLOAT: + return 3; + case SOCK_RGBA: + return 2; + case SOCK_VECTOR: + return 1; + } + return -1; + } + + /* The rest of the socket types only allow an internal link if both the input and output socket + * have the same type. If the sockets are custom, we check the idname instead. */ + if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) { + return 1; + } + + return -1; +} + +using TreeNodePair = std::pair<bNodeTree *, bNode *>; +using ObjectModifierPair = std::pair<Object *, ModifierData *>; +using NodeSocketPair = std::pair<bNode *, bNodeSocket *>; + +/** + * Cache common data about node trees from the #Main database that is expensive to retrieve on + * demand every time. + */ +struct NodeTreeRelations { + private: + Main *bmain_; + std::optional<Vector<bNodeTree *>> all_trees_; + std::optional<Map<bNodeTree *, ID *>> owner_ids_; + std::optional<MultiValueMap<bNodeTree *, TreeNodePair>> group_node_users_; + std::optional<MultiValueMap<bNodeTree *, ObjectModifierPair>> modifiers_users_; + + public: + NodeTreeRelations(Main *bmain) : bmain_(bmain) + { + } + + void ensure_all_trees() + { + if (all_trees_.has_value()) { + return; + } + all_trees_.emplace(); + owner_ids_.emplace(); + if (bmain_ == nullptr) { + return; + } + + FOREACH_NODETREE_BEGIN (bmain_, ntree, id) { + all_trees_->append(ntree); + if (&ntree->id != id) { + owner_ids_->add_new(ntree, id); + } + } + FOREACH_NODETREE_END; + } + + void ensure_owner_ids() + { + this->ensure_all_trees(); + } + + void ensure_group_node_users() + { + if (group_node_users_.has_value()) { + return; + } + group_node_users_.emplace(); + if (bmain_ == nullptr) { + return; + } + + this->ensure_all_trees(); + + for (bNodeTree *ntree : *all_trees_) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->id == nullptr) { + continue; + } + ID *id = node->id; + if (GS(id->name) == ID_NT) { + bNodeTree *group = (bNodeTree *)id; + group_node_users_->add(group, {ntree, node}); + } + } + } + } + + void ensure_modifier_users() + { + if (modifiers_users_.has_value()) { + return; + } + modifiers_users_.emplace(); + if (bmain_ == nullptr) { + return; + } + + LISTBASE_FOREACH (Object *, object, &bmain_->objects) { + LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) { + if (md->type == eModifierType_Nodes) { + NodesModifierData *nmd = (NodesModifierData *)md; + if (nmd->node_group != nullptr) { + modifiers_users_->add(nmd->node_group, {object, md}); + } + } + } + } + } + + Span<ObjectModifierPair> get_modifier_users(bNodeTree *ntree) + { + BLI_assert(modifiers_users_.has_value()); + return modifiers_users_->lookup(ntree); + } + + Span<TreeNodePair> get_group_node_users(bNodeTree *ntree) + { + BLI_assert(group_node_users_.has_value()); + return group_node_users_->lookup(ntree); + } + + ID *get_owner_id(bNodeTree *ntree) + { + BLI_assert(owner_ids_.has_value()); + return owner_ids_->lookup_default(ntree, &ntree->id); + } +}; + +struct TreeUpdateResult { + bool interface_changed = false; + bool output_changed = false; +}; + +class NodeTreeMainUpdater { + private: + Main *bmain_; + NodeTreeUpdateExtraParams *params_; + Map<bNodeTree *, TreeUpdateResult> update_result_by_tree_; + NodeTreeRelations relations_; + + public: + NodeTreeMainUpdater(Main *bmain, NodeTreeUpdateExtraParams *params) + : bmain_(bmain), params_(params), relations_(bmain) + { + } + + void update() + { + Vector<bNodeTree *> changed_ntrees; + FOREACH_NODETREE_BEGIN (bmain_, ntree, id) { + if (ntree->changed_flag != NTREE_CHANGED_NOTHING) { + changed_ntrees.append(ntree); + } + } + FOREACH_NODETREE_END; + this->update_rooted(changed_ntrees); + } + + void update_rooted(Span<bNodeTree *> root_ntrees) + { + if (root_ntrees.is_empty()) { + return; + } + + bool is_single_tree_update = false; + + if (root_ntrees.size() == 1) { + bNodeTree *ntree = root_ntrees[0]; + if (ntree->changed_flag == NTREE_CHANGED_NOTHING) { + return; + } + const TreeUpdateResult result = this->update_tree(*ntree); + update_result_by_tree_.add_new(ntree, result); + if (!result.interface_changed && !result.output_changed) { + is_single_tree_update = true; + } + } + + if (!is_single_tree_update) { + Vector<bNodeTree *> ntrees_in_order = this->get_tree_update_order(root_ntrees); + for (bNodeTree *ntree : ntrees_in_order) { + if (ntree->changed_flag == NTREE_CHANGED_NOTHING) { + continue; + } + if (!update_result_by_tree_.contains(ntree)) { + const TreeUpdateResult result = this->update_tree(*ntree); + update_result_by_tree_.add_new(ntree, result); + } + const TreeUpdateResult result = update_result_by_tree_.lookup(ntree); + Span<TreeNodePair> dependent_trees = relations_.get_group_node_users(ntree); + if (result.output_changed) { + for (const TreeNodePair &pair : dependent_trees) { + add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_OUTPUT); + } + } + if (result.interface_changed) { + for (const TreeNodePair &pair : dependent_trees) { + add_node_tag(pair.first, pair.second, NTREE_CHANGED_NODE_PROPERTY); + } + } + } + } + + for (const auto item : update_result_by_tree_.items()) { + bNodeTree *ntree = item.key; + const TreeUpdateResult &result = item.value; + + this->reset_changed_flags(*ntree); + + if (result.interface_changed) { + if (ntree->type == NTREE_GEOMETRY) { + relations_.ensure_modifier_users(); + for (const ObjectModifierPair &pair : relations_.get_modifier_users(ntree)) { + Object *object = pair.first; + ModifierData *md = pair.second; + + if (md->type == eModifierType_Nodes) { + MOD_nodes_update_interface(object, (NodesModifierData *)md); + } + } + } + } + + if (params_) { + relations_.ensure_owner_ids(); + ID *id = relations_.get_owner_id(ntree); + if (params_->tree_changed_fn) { + params_->tree_changed_fn(id, ntree, params_->user_data); + } + if (params_->tree_output_changed_fn && result.output_changed) { + params_->tree_output_changed_fn(id, ntree, params_->user_data); + } + } + } + } + + private: + enum class ToposortMark { + None, + Temporary, + Permanent, + }; + + using ToposortMarkMap = Map<bNodeTree *, ToposortMark>; + + /** + * Finds all trees that depend on the given trees (through node groups). Then those trees are + * ordered such that all trees used by one tree come before it. + */ + Vector<bNodeTree *> get_tree_update_order(Span<bNodeTree *> root_ntrees) + { + relations_.ensure_group_node_users(); + + Set<bNodeTree *> trees_to_update = get_trees_to_update(root_ntrees); + + Vector<bNodeTree *> sorted_ntrees; + + ToposortMarkMap marks; + for (bNodeTree *ntree : trees_to_update) { + marks.add_new(ntree, ToposortMark::None); + } + for (bNodeTree *ntree : trees_to_update) { + if (marks.lookup(ntree) == ToposortMark::None) { + const bool cycle_detected = !this->get_tree_update_order__visit_recursive( + ntree, marks, sorted_ntrees); + /* This should be prevented by higher level operators. */ + BLI_assert(!cycle_detected); + UNUSED_VARS_NDEBUG(cycle_detected); + } + } + + std::reverse(sorted_ntrees.begin(), sorted_ntrees.end()); + + return sorted_ntrees; + } + + bool get_tree_update_order__visit_recursive(bNodeTree *ntree, + ToposortMarkMap &marks, + Vector<bNodeTree *> &sorted_ntrees) + { + ToposortMark &mark = marks.lookup(ntree); + if (mark == ToposortMark::Permanent) { + return true; + } + if (mark == ToposortMark::Temporary) { + /* There is a dependency cycle. */ + return false; + } + + mark = ToposortMark::Temporary; + + for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) { + this->get_tree_update_order__visit_recursive(pair.first, marks, sorted_ntrees); + } + sorted_ntrees.append(ntree); + + mark = ToposortMark::Permanent; + return true; + } + + Set<bNodeTree *> get_trees_to_update(Span<bNodeTree *> root_ntrees) + { + relations_.ensure_group_node_users(); + + Set<bNodeTree *> reachable_trees; + VectorSet<bNodeTree *> trees_to_check = root_ntrees; + + while (!trees_to_check.is_empty()) { + bNodeTree *ntree = trees_to_check.pop(); + if (reachable_trees.add(ntree)) { + for (const TreeNodePair &pair : relations_.get_group_node_users(ntree)) { + trees_to_check.add(pair.first); + } + } + } + + return reachable_trees; + } + + TreeUpdateResult update_tree(bNodeTree &ntree) + { + TreeUpdateResult result; + + /* Use a #NodeTreeRef to speedup certain queries. It is rebuilt whenever the node tree topology + * changes, which typically happens zero or one times during the entire update of the node + * tree. */ + std::unique_ptr<NodeTreeRef> tree_ref; + this->ensure_tree_ref(ntree, tree_ref); + + this->update_socket_link_and_use(*tree_ref); + this->update_individual_nodes(ntree, tree_ref); + this->update_internal_links(ntree, tree_ref); + this->update_generic_callback(ntree, tree_ref); + this->remove_unused_previews_when_necessary(ntree); + + this->ensure_tree_ref(ntree, tree_ref); + if (ntree.type == NTREE_GEOMETRY) { + if (node_field_inferencing::update_field_inferencing(*tree_ref)) { + result.interface_changed = true; + } + } + + result.output_changed = this->check_if_output_changed(*tree_ref); + + this->update_socket_link_and_use(*tree_ref); + this->update_node_levels(ntree); + this->update_link_validation(ntree); + + if (ntree.type == NTREE_TEXTURE) { + ntreeTexCheckCyclics(&ntree); + } + + if (ntree.changed_flag & NTREE_CHANGED_INTERFACE || ntree.changed_flag & NTREE_CHANGED_ANY) { + result.interface_changed = true; + } + + if (result.interface_changed) { + ntreeInterfaceTypeUpdate(&ntree); + } + + return result; + } + + void ensure_tree_ref(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + { + if (!tree_ref) { + tree_ref = std::make_unique<NodeTreeRef>(&ntree); + } + } + + void update_socket_link_and_use(const NodeTreeRef &tree) + { + for (const InputSocketRef *socket : tree.input_sockets()) { + bNodeSocket *bsocket = socket->bsocket(); + if (socket->directly_linked_links().is_empty()) { + bsocket->link = nullptr; + } + else { + bsocket->link = socket->directly_linked_links()[0]->blink(); + } + } + + this->update_socket_used_tags(tree); + } + + void update_socket_used_tags(const NodeTreeRef &tree) + { + for (const SocketRef *socket : tree.sockets()) { + bNodeSocket *bsocket = socket->bsocket(); + bsocket->flag &= ~SOCK_IN_USE; + for (const LinkRef *link : socket->directly_linked_links()) { + if (!link->is_muted()) { + bsocket->flag |= SOCK_IN_USE; + break; + } + } + } + } + + void update_individual_nodes(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + { + /* Iterate over nodes instead of #NodeTreeRef, because the #tree_ref might be outdated after + * some update functions. */ + LISTBASE_FOREACH (bNode *, bnode, &ntree.nodes) { + this->ensure_tree_ref(ntree, tree_ref); + const NodeRef &node = *tree_ref->find_node(*bnode); + if (this->should_update_individual_node(node)) { + const uint32_t old_changed_flag = ntree.changed_flag; + ntree.changed_flag = NTREE_CHANGED_NOTHING; + + /* This may set #ntree.changed_flag which is detected below. */ + this->update_individual_node(node); + + if (ntree.changed_flag != NTREE_CHANGED_NOTHING) { + /* The tree ref is outdated and needs to be rebuilt. Generally, only very few update + * functions change the node. Typically zero or one nodes change after an update. */ + tree_ref.reset(); + } + ntree.changed_flag |= old_changed_flag; + } + } + } + + bool should_update_individual_node(const NodeRef &node) + { + bNodeTree &ntree = *node.btree(); + bNode &bnode = *node.bnode(); + if (ntree.changed_flag & NTREE_CHANGED_ANY) { + return true; + } + if (bnode.changed_flag & NTREE_CHANGED_NODE_PROPERTY) { + return true; + } + if (ntree.changed_flag & NTREE_CHANGED_LINK) { + /* Node groups currently always rebuilt their sockets when they are updated. + * So avoid calling the update method when no new link was added to it. */ + if (node.is_group_input_node()) { + if (node.outputs().last()->is_directly_linked()) { + return true; + } + } + else if (node.is_group_output_node()) { + if (node.inputs().last()->is_directly_linked()) { + return true; + } + } + else { + /* Currently we have no way to tell if a node needs to be updated when a link changed. */ + return true; + } + } + if (ntree.changed_flag & NTREE_CHANGED_INTERFACE) { + if (node.is_group_input_node() || node.is_group_output_node()) { + return true; + } + } + return false; + } + + void update_individual_node(const NodeRef &node) + { + bNodeTree &ntree = *node.btree(); + bNode &bnode = *node.bnode(); + bNodeType &ntype = *bnode.typeinfo; + if (ntype.group_update_func) { + ntype.group_update_func(&ntree, &bnode); + } + if (ntype.updatefunc) { + ntype.updatefunc(&ntree, &bnode); + } + } + + void update_internal_links(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + { + bool any_internal_links_updated = false; + this->ensure_tree_ref(ntree, tree_ref); + for (const NodeRef *node : tree_ref->nodes()) { + if (!this->should_update_individual_node(*node)) { + continue; + } + /* Find all expected internal links. */ + Vector<std::pair<bNodeSocket *, bNodeSocket *>> expected_internal_links; + for (const OutputSocketRef *output_socket : node->outputs()) { + if (!output_socket->is_available()) { + continue; + } + if (!output_socket->is_directly_linked()) { + continue; + } + if (output_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + continue; + } + const InputSocketRef *input_socket = this->find_internally_linked_input(output_socket); + if (input_socket != nullptr) { + expected_internal_links.append({input_socket->bsocket(), output_socket->bsocket()}); + } + } + /* rebuilt internal links if they have changed. */ + if (node->internal_links().size() != expected_internal_links.size()) { + this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); + any_internal_links_updated = true; + } + else { + for (auto &item : expected_internal_links) { + const bNodeSocket *from_socket = item.first; + const bNodeSocket *to_socket = item.second; + bool found = false; + for (const InternalLinkRef *internal_link : node->internal_links()) { + if (from_socket == internal_link->from().bsocket() && + to_socket == internal_link->to().bsocket()) { + found = true; + } + } + if (!found) { + this->update_internal_links_in_node(ntree, *node->bnode(), expected_internal_links); + any_internal_links_updated = true; + break; + } + } + } + } + + if (any_internal_links_updated) { + tree_ref.reset(); + } + } + + const InputSocketRef *find_internally_linked_input(const OutputSocketRef *output_socket) + { + const InputSocketRef *selected_socket = nullptr; + int selected_priority = -1; + bool selected_is_linked = false; + for (const InputSocketRef *input_socket : output_socket->node().inputs()) { + if (!input_socket->is_available()) { + continue; + } + if (input_socket->bsocket()->flag & SOCK_NO_INTERNAL_LINK) { + continue; + } + const int priority = get_internal_link_type_priority(input_socket->bsocket()->typeinfo, + output_socket->bsocket()->typeinfo); + if (priority < 0) { + continue; + } + const bool is_linked = input_socket->is_directly_linked(); + const bool is_preferred = priority > selected_priority || (is_linked && !selected_is_linked); + if (!is_preferred) { + continue; + } + selected_socket = input_socket; + selected_priority = priority; + selected_is_linked = is_linked; + } + return selected_socket; + } + + void update_internal_links_in_node(bNodeTree &ntree, + bNode &node, + Span<std::pair<bNodeSocket *, bNodeSocket *>> links) + { + BLI_freelistN(&node.internal_links); + for (const auto &item : links) { + bNodeSocket *from_socket = item.first; + bNodeSocket *to_socket = item.second; + bNodeLink *link = MEM_cnew<bNodeLink>(__func__); + link->fromnode = &node; + link->fromsock = from_socket; + link->tonode = &node; + link->tosock = to_socket; + link->flag |= NODE_LINK_VALID; + BLI_addtail(&node.internal_links, link); + } + BKE_ntree_update_tag_node_internal_link(&ntree, &node); + } + + void update_generic_callback(bNodeTree &ntree, std::unique_ptr<NodeTreeRef> &tree_ref) + { + if (ntree.typeinfo->update == nullptr) { + return; + } + + /* Reset the changed_flag to allow detecting when the update callback changed the node tree. */ + const uint32_t old_changed_flag = ntree.changed_flag; + ntree.changed_flag = NTREE_CHANGED_NOTHING; + + ntree.typeinfo->update(&ntree); + + if (ntree.changed_flag != NTREE_CHANGED_NOTHING) { + /* The tree ref is outdated and needs to be rebuilt. */ + tree_ref.reset(); + } + ntree.changed_flag |= old_changed_flag; + } + + void remove_unused_previews_when_necessary(bNodeTree &ntree) + { + /* Don't trigger preview removal when only those flags are set. */ + const uint32_t allowed_flags = NTREE_CHANGED_LINK | NTREE_CHANGED_SOCKET_PROPERTY | + NTREE_CHANGED_NODE_PROPERTY | NTREE_CHANGED_NODE_OUTPUT | + NTREE_CHANGED_INTERFACE; + if ((ntree.changed_flag & allowed_flags) == ntree.changed_flag) { + return; + } + BKE_node_preview_remove_unused(&ntree); + } + + void update_node_levels(bNodeTree &ntree) + { + ntreeUpdateNodeLevels(&ntree); + } + + void update_link_validation(bNodeTree &ntree) + { + LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { + link->flag |= NODE_LINK_VALID; + if (link->fromnode && link->tonode && link->fromnode->level <= link->tonode->level) { + link->flag &= ~NODE_LINK_VALID; + } + else if (ntree.typeinfo->validate_link) { + const eNodeSocketDatatype from_type = static_cast<eNodeSocketDatatype>( + link->fromsock->type); + const eNodeSocketDatatype to_type = static_cast<eNodeSocketDatatype>(link->tosock->type); + if (!ntree.typeinfo->validate_link(from_type, to_type)) { + link->flag &= ~NODE_LINK_VALID; + } + } + } + } + + bool check_if_output_changed(const NodeTreeRef &tree) + { + bNodeTree &btree = *tree.btree(); + + /* Compute a hash that represents the node topology connected to the output. This always has to + * be updated even if it is not used to detect changes right now. Otherwise + * #btree.output_topology_hash will go out of date. */ + const Vector<const SocketRef *> tree_output_sockets = this->find_output_sockets(tree); + const uint32_t old_topology_hash = btree.output_topology_hash; + const uint32_t new_topology_hash = this->get_combined_socket_topology_hash( + tree, tree_output_sockets); + btree.output_topology_hash = new_topology_hash; + + if (const AnimData *adt = BKE_animdata_from_id(&btree.id)) { + /* Drivers may copy values in the node tree around arbitrarily and may cause the output to + * change even if it wouldn't without drivers. Only some special drivers like `frame/5` can + * be used without causing updates all the time currently. In the future we could try to + * handle other drivers better as well. + * Note that this optimization only works in practice when the depsgraph didn't also get a + * copy-on-write tag for the node tree (which happens when changing node properties). It does + * work in a few situations like adding reroutes and duplicating nodes though. */ + LISTBASE_FOREACH (const FCurve *, fcurve, &adt->drivers) { + const ChannelDriver *driver = fcurve->driver; + const StringRef expression = driver->expression; + if (expression.startswith("frame")) { + const StringRef remaining_expression = expression.drop_known_prefix("frame"); + if (remaining_expression.find_first_not_of(" */+-0123456789.") == StringRef::not_found) { + continue; + } + } + /* Unrecognized driver, assume that the output always changes. */ + return true; + } + } + + if (btree.changed_flag & NTREE_CHANGED_ANY) { + return true; + } + + if (old_topology_hash != new_topology_hash) { + return true; + } + + /* The topology hash can only be used when only topology-changing operations have been done. */ + if (btree.changed_flag == + (btree.changed_flag & (NTREE_CHANGED_LINK | NTREE_CHANGED_REMOVED_NODE))) { + if (old_topology_hash == new_topology_hash) { + return false; + } + } + + if (!this->check_if_socket_outputs_changed_based_on_flags(tree, tree_output_sockets)) { + return false; + } + + return true; + } + + Vector<const SocketRef *> find_output_sockets(const NodeTreeRef &tree) + { + Vector<const SocketRef *> sockets; + for (const NodeRef *node : tree.nodes()) { + const bNode *bnode = node->bnode(); + if (bnode->typeinfo->nclass != NODE_CLASS_OUTPUT && bnode->type != NODE_GROUP_OUTPUT) { + continue; + } + for (const InputSocketRef *socket : node->inputs()) { + if (socket->idname() != "NodeSocketVirtual") { + sockets.append(socket); + } + } + } + return sockets; + } + + /** + * Computes a hash that changes when the node tree topology connected to an output node changes. + * Adding reroutes does not have an effect on the hash. + */ + uint32_t get_combined_socket_topology_hash(const NodeTreeRef &tree, + Span<const SocketRef *> sockets) + { + if (tree.has_link_cycles()) { + /* Return dummy value when the link has any cycles. The algorithm below could be improved to + * handle cycles more gracefully. */ + return 0; + } + Array<uint32_t> hashes = this->get_socket_topology_hashes(tree, sockets); + uint32_t combined_hash = 0; + for (uint32_t hash : hashes) { + combined_hash = noise::hash(combined_hash, hash); + } + return combined_hash; + } + + Array<uint32_t> get_socket_topology_hashes(const NodeTreeRef &tree, + Span<const SocketRef *> sockets) + { + BLI_assert(!tree.has_link_cycles()); + Array<std::optional<uint32_t>> hash_by_socket_id(tree.sockets().size()); + Stack<const SocketRef *> sockets_to_check = sockets; + + while (!sockets_to_check.is_empty()) { + const SocketRef &in_out_socket = *sockets_to_check.peek(); + const NodeRef &node = in_out_socket.node(); + + if (hash_by_socket_id[in_out_socket.id()].has_value()) { + sockets_to_check.pop(); + /* Socket is handled already. */ + continue; + } + + if (in_out_socket.is_input()) { + /* For input sockets, first compute the hashes of all linked sockets. */ + const InputSocketRef &socket = in_out_socket.as_input(); + bool all_origins_computed = true; + for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { + if (!hash_by_socket_id[origin_socket->id()].has_value()) { + sockets_to_check.push(origin_socket); + all_origins_computed = false; + } + } + if (!all_origins_computed) { + continue; + } + /* When the hashes for the linked sockets are ready, combine them into a hash for the input + * socket. */ + const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); + for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { + const uint32_t origin_socket_hash = *hash_by_socket_id[origin_socket->id()]; + socket_hash = noise::hash(socket_hash, origin_socket_hash); + } + hash_by_socket_id[socket.id()] = socket_hash; + sockets_to_check.pop(); + } + else { + /* For output sockets, first compute the hashes of all available input sockets. */ + const OutputSocketRef &socket = in_out_socket.as_output(); + bool all_available_inputs_computed = true; + for (const InputSocketRef *input_socket : node.inputs()) { + if (input_socket->is_available()) { + if (!hash_by_socket_id[input_socket->id()].has_value()) { + sockets_to_check.push(input_socket); + all_available_inputs_computed = false; + } + } + } + if (!all_available_inputs_computed) { + continue; + } + /* When all input socket hashes have been computed, combine them into a hash for the output + * socket. */ + const uint64_t socket_ptr = (uintptr_t)socket.bsocket(); + uint32_t socket_hash = noise::hash(socket_ptr, socket_ptr >> 32); + for (const InputSocketRef *input_socket : node.inputs()) { + if (input_socket->is_available()) { + const uint32_t input_socket_hash = *hash_by_socket_id[input_socket->id()]; + socket_hash = noise::hash(socket_hash, input_socket_hash); + } + } + hash_by_socket_id[socket.id()] = socket_hash; + sockets_to_check.pop(); + } + } + + /* Create output array. */ + Array<uint32_t> hashes(sockets.size()); + for (const int i : sockets.index_range()) { + hashes[i] = *hash_by_socket_id[sockets[i]->id()]; + } + return hashes; + } + + /** + * Returns true when any of the provided sockets changed its values. A change is detected by + * checking the #changed_flag on connected sockets and nodes. + */ + bool check_if_socket_outputs_changed_based_on_flags(const NodeTreeRef &tree, + Span<const SocketRef *> sockets) + { + /* Avoid visiting the same socket twice when multiple links point to the same socket. */ + Array<bool> pushed_by_socket_id(tree.sockets().size(), false); + Stack<const SocketRef *> sockets_to_check = sockets; + + for (const SocketRef *socket : sockets) { + pushed_by_socket_id[socket->id()] = true; + } + + while (!sockets_to_check.is_empty()) { + const SocketRef &in_out_socket = *sockets_to_check.pop(); + const bNode &bnode = *in_out_socket.node().bnode(); + const bNodeSocket &bsocket = *in_out_socket.bsocket(); + if (bsocket.changed_flag != NTREE_CHANGED_NOTHING) { + return true; + } + if (bnode.changed_flag != NTREE_CHANGED_NOTHING) { + const bool only_unused_internal_link_changed = (bnode.flag & NODE_MUTED) == 0 && + bnode.changed_flag == + NTREE_CHANGED_INTERNAL_LINK; + if (!only_unused_internal_link_changed) { + return true; + } + } + if (in_out_socket.is_input()) { + const InputSocketRef &socket = in_out_socket.as_input(); + for (const OutputSocketRef *origin_socket : socket.logically_linked_sockets()) { + bool &pushed = pushed_by_socket_id[origin_socket->id()]; + if (!pushed) { + sockets_to_check.push(origin_socket); + pushed = true; + } + } + } + else { + const OutputSocketRef &socket = in_out_socket.as_output(); + for (const InputSocketRef *input_socket : socket.node().inputs()) { + if (input_socket->is_available()) { + bool &pushed = pushed_by_socket_id[input_socket->id()]; + if (!pushed) { + sockets_to_check.push(input_socket); + pushed = true; + } + } + } + } + } + return false; + } + + void reset_changed_flags(bNodeTree &ntree) + { + ntree.changed_flag = NTREE_CHANGED_NOTHING; + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { + node->changed_flag = NTREE_CHANGED_NOTHING; + node->update = 0; + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->changed_flag = NTREE_CHANGED_NOTHING; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->changed_flag = NTREE_CHANGED_NOTHING; + } + } + } +}; + +} // namespace blender::bke + +void BKE_ntree_update_tag_all(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_ANY); +} + +void BKE_ntree_update_tag_node_property(bNodeTree *ntree, bNode *node) +{ + add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY); +} + +void BKE_ntree_update_tag_node_new(bNodeTree *ntree, bNode *node) +{ + add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY); +} + +void BKE_ntree_update_tag_socket_property(bNodeTree *ntree, bNodeSocket *socket) +{ + add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY); +} + +void BKE_ntree_update_tag_socket_new(bNodeTree *ntree, bNodeSocket *socket) +{ + add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY); +} + +void BKE_ntree_update_tag_socket_removed(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_REMOVED_SOCKET); +} + +void BKE_ntree_update_tag_socket_type(bNodeTree *ntree, bNodeSocket *socket) +{ + add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY); +} + +void BKE_ntree_update_tag_socket_availability(bNodeTree *ntree, bNodeSocket *socket) +{ + add_socket_tag(ntree, socket, NTREE_CHANGED_SOCKET_PROPERTY); +} + +void BKE_ntree_update_tag_node_removed(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_REMOVED_NODE); +} + +void BKE_ntree_update_tag_node_mute(bNodeTree *ntree, bNode *node) +{ + add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY); +} + +void BKE_ntree_update_tag_node_internal_link(bNodeTree *ntree, bNode *node) +{ + add_node_tag(ntree, node, NTREE_CHANGED_INTERNAL_LINK); +} + +void BKE_ntree_update_tag_link_changed(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_LINK); +} + +void BKE_ntree_update_tag_link_removed(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_LINK); +} + +void BKE_ntree_update_tag_link_added(bNodeTree *ntree, bNodeLink *UNUSED(link)) +{ + add_tree_tag(ntree, NTREE_CHANGED_LINK); +} + +void BKE_ntree_update_tag_link_mute(bNodeTree *ntree, bNodeLink *UNUSED(link)) +{ + add_tree_tag(ntree, NTREE_CHANGED_LINK); +} + +void BKE_ntree_update_tag_missing_runtime_data(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_ALL); +} + +void BKE_ntree_update_tag_interface(bNodeTree *ntree) +{ + add_tree_tag(ntree, NTREE_CHANGED_INTERFACE); +} + +void BKE_ntree_update_tag_id_changed(Main *bmain, ID *id) +{ + FOREACH_NODETREE_BEGIN (bmain, ntree, ntree_id) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->id == id) { + node->update |= NODE_UPDATE_ID; + add_node_tag(ntree, node, NTREE_CHANGED_NODE_PROPERTY); + } + } + } + FOREACH_NODETREE_END; +} + +/** + * Protect from recursive calls into the updating function. Some node update functions might + * trigger this from Python or in other cases. + * + * This could be added to #Main, but given that there is generally only one #Main, that's not + * really worth it now. + */ +static bool is_updating = false; + +void BKE_ntree_update_main(Main *bmain, NodeTreeUpdateExtraParams *params) +{ + if (is_updating) { + return; + } + + is_updating = true; + blender::bke::NodeTreeMainUpdater updater{bmain, params}; + updater.update(); + is_updating = false; +} + +void BKE_ntree_update_main_tree(Main *bmain, bNodeTree *ntree, NodeTreeUpdateExtraParams *params) +{ + if (ntree == nullptr) { + BKE_ntree_update_main(bmain, params); + return; + } + + if (is_updating) { + return; + } + + is_updating = true; + blender::bke::NodeTreeMainUpdater updater{bmain, params}; + updater.update_rooted({ntree}); + is_updating = false; +} diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 7fec91ed65a..5045851d7f9 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -1773,8 +1773,9 @@ static void object_update_from_subsurf_ccg(Object *object) if (!object->runtime.is_data_eval_owned) { return; } - /* Object was never evaluated, so can not have CCG subdivision surface. */ - Mesh *mesh_eval = BKE_object_get_evaluated_mesh(object); + /* Object was never evaluated, so can not have CCG subdivision surface. If it were evaluated, do + * not try to compute OpenSubDiv on the CPU as it is not needed here. */ + Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(object); if (mesh_eval == nullptr) { return; } @@ -3793,7 +3794,7 @@ BoundBox *BKE_boundbox_alloc_unit() { const float min[3] = {-1.0f, -1.0f, -1.0f}, max[3] = {1.0f, 1.0f, 1.0f}; - BoundBox *bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "OB-BoundBox"); + BoundBox *bb = MEM_cnew<BoundBox>("OB-BoundBox"); BKE_boundbox_init_from_minmax(bb, min, max); return bb; @@ -3903,7 +3904,7 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval) } if (ob->runtime.bb == nullptr) { - ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), "DM-BoundBox"); + ob->runtime.bb = MEM_cnew<BoundBox>("DM-BoundBox"); } BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); @@ -3917,11 +3918,15 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob) INIT_MINMAX(min, max); if (ob->runtime.geometry_set_eval) { - ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max); + if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) { + zero_v3(min); + zero_v3(max); + } } else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) { if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) { - return false; + zero_v3(min); + zero_v3(max); } } else if (ob->runtime.curve_cache) { @@ -3932,7 +3937,7 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob) } if (ob->runtime.bb == nullptr) { - ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__); + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); } BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); @@ -4108,7 +4113,7 @@ void BKE_object_empty_draw_type_set(Object *ob, const int value) if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { if (!ob->iuser) { - ob->iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "image user"); + ob->iuser = MEM_cnew<ImageUser>("image user"); ob->iuser->flag |= IMA_ANIM_ALWAYS; ob->iuser->frames = 100; ob->iuser->sfra = 1; @@ -4447,7 +4452,7 @@ void BKE_object_handle_update(Depsgraph *depsgraph, Scene *scene, Object *ob) void BKE_object_sculpt_data_create(Object *ob) { BLI_assert((ob->sculpt == nullptr) && (ob->mode & OB_MODE_ALL_SCULPT)); - ob->sculpt = (SculptSession *)MEM_callocN(sizeof(SculptSession), __func__); + ob->sculpt = MEM_cnew<SculptSession>(__func__); ob->sculpt->mode_type = (eObjectMode)ob->mode; } @@ -4496,7 +4501,7 @@ bool BKE_object_obdata_texspace_get(Object *ob, char **r_texflag, float **r_loc, return true; } -Mesh *BKE_object_get_evaluated_mesh(const Object *object) +Mesh *BKE_object_get_evaluated_mesh_no_subsurf(const Object *object) { /* First attempt to retrieve the evaluated mesh from the evaluated geometry set. Most * object types either store it there or add a reference to it if it's owned elsewhere. */ @@ -4523,6 +4528,20 @@ Mesh *BKE_object_get_evaluated_mesh(const Object *object) return nullptr; } +Mesh *BKE_object_get_evaluated_mesh(const Object *object) +{ + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(object); + if (!mesh) { + return nullptr; + } + + if (object->data && GS(((const ID *)object->data)->name) == ID_ME) { + mesh = BKE_mesh_wrapper_ensure_subdivision(object, mesh); + } + + return mesh; +} + Mesh *BKE_object_get_pre_modified_mesh(const Object *object) { if (object->type == OB_MESH && object->runtime.data_orig != nullptr) { @@ -4621,7 +4640,7 @@ int BKE_object_insert_ptcache(Object *ob) } } - link = (LinkData *)MEM_callocN(sizeof(LinkData), "PCLink"); + link = MEM_cnew<LinkData>("PCLink"); link->data = POINTER_FROM_INT(i); BLI_addtail(&ob->pc_ids, link); @@ -5779,6 +5798,21 @@ void BKE_object_modifiers_lib_link_common(void *userData, } } +SubsurfModifierData *BKE_object_get_last_subsurf_modifier(const Object *ob) +{ + ModifierData *md = (ModifierData *)(ob->modifiers.last); + + while (md) { + if (md->type == eModifierType_Subsurf) { + break; + } + + md = md->prev; + } + + return (SubsurfModifierData *)(md); +} + void BKE_object_replace_data_on_shallow_copy(Object *ob, ID *new_data) { ob->type = BKE_object_obdata_to_type(new_data); diff --git a/source/blender/blenkernel/intern/object_dupli.cc b/source/blender/blenkernel/intern/object_dupli.cc index 9f998b746a2..e682486390c 100644 --- a/source/blender/blenkernel/intern/object_dupli.cc +++ b/source/blender/blenkernel/intern/object_dupli.cc @@ -190,7 +190,7 @@ static DupliObject *make_dupli(const DupliContext *ctx, /* Add a #DupliObject instance to the result container. */ if (ctx->duplilist) { - dob = (DupliObject *)MEM_callocN(sizeof(DupliObject), "dupli object"); + dob = MEM_cnew<DupliObject>("dupli object"); BLI_addtail(ctx->duplilist, dob); } else { @@ -1690,7 +1690,7 @@ static const DupliGenerator *get_dupli_generator(const DupliContext *ctx) ListBase *object_duplilist(Depsgraph *depsgraph, Scene *sce, Object *ob) { - ListBase *duplilist = (ListBase *)MEM_callocN(sizeof(ListBase), "duplilist"); + ListBase *duplilist = MEM_cnew<ListBase>("duplilist"); DupliContext ctx; Vector<Object *> instance_stack; instance_stack.append(ob); diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index df76f003498..38575f3048f 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -3505,6 +3505,11 @@ void BKE_ptcache_disk_cache_rename(PTCacheID *pid, const char *name_src, const c char old_path_full[MAX_PTCACHE_FILE]; char ext[MAX_PTCACHE_PATH]; + /* If both names are the same, there is nothing to do. */ + if (STREQ(name_src, name_dst)) { + return; + } + /* save old name */ BLI_strncpy(old_name, pid->cache->name, sizeof(old_name)); diff --git a/source/blender/blenkernel/intern/pointcloud.cc b/source/blender/blenkernel/intern/pointcloud.cc index 82dde79cff6..a041e04bf71 100644 --- a/source/blender/blenkernel/intern/pointcloud.cc +++ b/source/blender/blenkernel/intern/pointcloud.cc @@ -25,10 +25,13 @@ #include "DNA_object_types.h" #include "DNA_pointcloud_types.h" +#include "BLI_float3.hh" +#include "BLI_index_range.hh" #include "BLI_listbase.h" -#include "BLI_math.h" #include "BLI_rand.h" +#include "BLI_span.hh" #include "BLI_string.h" +#include "BLI_task.hh" #include "BLI_utildefines.h" #include "BKE_anim_data.h" @@ -51,6 +54,10 @@ #include "BLO_read_write.h" +using blender::float3; +using blender::IndexRange; +using blender::Span; + /* PointCloud datablock */ static void pointcloud_random(PointCloud *pointcloud); @@ -261,18 +268,64 @@ PointCloud *BKE_pointcloud_new_nomain(const int totpoint) return pointcloud; } -void BKE_pointcloud_minmax(const struct PointCloud *pointcloud, float r_min[3], float r_max[3]) +struct MinMaxResult { + float3 min; + float3 max; +}; + +static MinMaxResult min_max_no_radii(Span<float3> positions) +{ + return blender::threading::parallel_reduce( + positions.index_range(), + 1024, + MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)}, + [&](IndexRange range, const MinMaxResult &init) { + MinMaxResult result = init; + for (const int i : range) { + float3::min_max(positions[i], result.min, result.max); + } + return result; + }, + [](const MinMaxResult &a, const MinMaxResult &b) { + return MinMaxResult{float3::min(a.min, b.min), float3::max(a.max, b.max)}; + }); +} + +static MinMaxResult min_max_with_radii(Span<float3> positions, Span<float> radii) { - float(*pointcloud_co)[3] = pointcloud->co; - float *pointcloud_radius = pointcloud->radius; - for (int a = 0; a < pointcloud->totpoint; a++) { - float *co = pointcloud_co[a]; - float radius = (pointcloud_radius) ? pointcloud_radius[a] : 0.0f; - const float co_min[3] = {co[0] - radius, co[1] - radius, co[2] - radius}; - const float co_max[3] = {co[0] + radius, co[1] + radius, co[2] + radius}; - DO_MIN(co_min, r_min); - DO_MAX(co_max, r_max); + return blender::threading::parallel_reduce( + positions.index_range(), + 1024, + MinMaxResult{float3(FLT_MAX), float3(-FLT_MAX)}, + [&](IndexRange range, const MinMaxResult &init) { + MinMaxResult result = init; + for (const int i : range) { + result.min = float3::min(positions[i] - radii[i], result.min); + result.max = float3::max(positions[i] + radii[i], result.max); + } + return result; + }, + [](const MinMaxResult &a, const MinMaxResult &b) { + return MinMaxResult{float3::min(a.min, b.min), float3::max(a.max, b.max)}; + }); +} + +bool BKE_pointcloud_minmax(const PointCloud *pointcloud, float r_min[3], float r_max[3]) +{ + if (!pointcloud->totpoint) { + return false; } + + Span<float3> positions{reinterpret_cast<float3 *>(pointcloud->co), pointcloud->totpoint}; + const MinMaxResult min_max = (pointcloud->radius) ? + min_max_with_radii(positions, + {pointcloud->radius, pointcloud->totpoint}) : + min_max_no_radii(positions); + + copy_v3_v3(r_min, float3::min(min_max.min, r_min)); + copy_v3_v3(r_max, float3::max(min_max.max, r_max)); + + return true; } BoundBox *BKE_pointcloud_boundbox_get(Object *ob) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index cd8493ee559..6e352b6ba90 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -900,7 +900,7 @@ ARegion *BKE_area_find_region_active_win(ScrArea *area) return BKE_area_find_region_type(area, RGN_TYPE_WINDOW); } -ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int y) +ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, const int xy[2]) { if (area == NULL) { return NULL; @@ -908,7 +908,7 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) { - if (BLI_rcti_isect_pt(®ion->winrct, x, y)) { + if (BLI_rcti_isect_pt_v(®ion->winrct, xy)) { return region; } } @@ -916,11 +916,11 @@ ARegion *BKE_area_find_region_xy(ScrArea *area, const int regiontype, int x, int return NULL; } -ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, int x, int y) +ARegion *BKE_screen_find_region_xy(bScreen *screen, const int regiontype, const int xy[2]) { LISTBASE_FOREACH (ARegion *, region, &screen->regionbase) { if (ELEM(regiontype, RGN_TYPE_ANY, region->regiontype)) { - if (BLI_rcti_isect_pt(®ion->winrct, x, y)) { + if (BLI_rcti_isect_pt_v(®ion->winrct, xy)) { return region; } } @@ -961,11 +961,10 @@ ScrArea *BKE_screen_find_big_area(bScreen *screen, const int spacetype, const sh ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, const int spacetype, - int x, - int y) + const int xy[2]) { LISTBASE_FOREACH (ScrArea *, area, &areamap->areabase) { - if (BLI_rcti_isect_pt(&area->totrct, x, y)) { + if (BLI_rcti_isect_pt_v(&area->totrct, xy)) { if (ELEM(spacetype, SPACE_TYPE_ANY, area->spacetype)) { return area; } @@ -974,9 +973,9 @@ ScrArea *BKE_screen_area_map_find_area_xy(const ScrAreaMap *areamap, } return NULL; } -ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, int x, int y) +ScrArea *BKE_screen_find_area_xy(bScreen *screen, const int spacetype, const int xy[2]) { - return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, x, y); + return BKE_screen_area_map_find_area_xy(AREAMAP_FROM_SCREEN(screen), spacetype, xy); } void BKE_screen_view3d_sync(View3D *v3d, struct Scene *scene) @@ -1016,16 +1015,13 @@ void BKE_screen_view3d_shading_init(View3DShading *shading) memcpy(shading, shading_default, sizeof(*shading)); } -ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen, - const int space_type, - const int x, - const int y) +ARegion *BKE_screen_find_main_region_at_xy(bScreen *screen, const int space_type, const int xy[2]) { - ScrArea *area = BKE_screen_find_area_xy(screen, space_type, x, y); + ScrArea *area = BKE_screen_find_area_xy(screen, space_type, xy); if (!area) { return NULL; } - return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, x, y); + return BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, xy); } /* Magic zoom calculation, no idea what it signifies, if you find out, tell me! -zr diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index 4ff392a5ddb..857022345f3 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -417,7 +417,9 @@ Spline::LookupResult Spline::lookup_evaluated_length(const float length) const const int next_index = (index == this->evaluated_points_size() - 1) ? 0 : index + 1; const float previous_length = (index == 0) ? 0.0f : lengths[index - 1]; - const float factor = (length - previous_length) / (lengths[index] - previous_length); + const float length_in_segment = length - previous_length; + const float segment_length = lengths[index] - previous_length; + const float factor = segment_length == 0.0f ? 0.0f : length_in_segment / segment_length; return LookupResult{index, next_index, factor}; } diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 9ce285cebb8..b24c8960857 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -70,24 +70,6 @@ void BezierSpline::set_resolution(const int value) this->mark_cache_invalid(); } -void BezierSpline::add_point(const float3 position, - const HandleType handle_type_left, - const float3 handle_position_left, - const HandleType handle_type_right, - const float3 handle_position_right, - const float radius, - const float tilt) -{ - handle_types_left_.append(handle_type_left); - handle_positions_left_.append(handle_position_left); - positions_.append(position); - handle_types_right_.append(handle_type_right); - handle_positions_right_.append(handle_position_right); - radii_.append(radius); - tilts_.append(tilt); - this->mark_cache_invalid(); -} - void BezierSpline::resize(const int size) { handle_types_left_.resize(size); diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 69afb82baa8..719ba4b7ecd 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -81,19 +81,6 @@ void NURBSpline::set_order(const uint8_t value) this->mark_cache_invalid(); } -void NURBSpline::add_point(const float3 position, - const float radius, - const float tilt, - const float weight) -{ - positions_.append(position); - radii_.append(radius); - tilts_.append(tilt); - weights_.append(weight); - knots_dirty_ = true; - this->mark_cache_invalid(); -} - void NURBSpline::resize(const int size) { positions_.resize(size); @@ -257,13 +244,13 @@ void NURBSpline::calculate_knots() const Span<float> NURBSpline::knots() const { if (!knots_dirty_) { - BLI_assert(knots_.size() == this->size() + order_); + BLI_assert(knots_.size() == this->knots_size()); return knots_; } std::lock_guard lock{knots_mutex_}; if (!knots_dirty_) { - BLI_assert(knots_.size() == this->size() + order_); + BLI_assert(knots_.size() == this->knots_size()); return knots_; } diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc index 4af68b5f270..480bbd1dfe8 100644 --- a/source/blender/blenkernel/intern/spline_poly.cc +++ b/source/blender/blenkernel/intern/spline_poly.cc @@ -45,14 +45,6 @@ int PolySpline::size() const return size; } -void PolySpline::add_point(const float3 position, const float radius, const float tilt) -{ - positions_.append(position); - radii_.append(radius); - tilts_.append(tilt); - this->mark_cache_invalid(); -} - void PolySpline::resize(const int size) { positions_.resize(size); diff --git a/source/blender/blenkernel/intern/subdiv.c b/source/blender/blenkernel/intern/subdiv.c index fd32f52351a..45810e29565 100644 --- a/source/blender/blenkernel/intern/subdiv.c +++ b/source/blender/blenkernel/intern/subdiv.c @@ -29,6 +29,9 @@ #include "BLI_utildefines.h" +#include "BKE_modifier.h" +#include "BKE_subdiv_modifier.h" + #include "MEM_guardedalloc.h" #include "subdiv_converter.h" @@ -189,6 +192,12 @@ Subdiv *BKE_subdiv_update_from_mesh(Subdiv *subdiv, void BKE_subdiv_free(Subdiv *subdiv) { if (subdiv->evaluator != NULL) { + const eOpenSubdivEvaluator evaluator_type = subdiv->evaluator->type; + if (evaluator_type != OPENSUBDIV_EVALUATOR_CPU) { + /* Let the draw code do the freeing, to ensure that the OpenGL context is valid. */ + BKE_subsurf_modifier_free_gpu_cache_cb(subdiv); + return; + } openSubdiv_deleteEvaluator(subdiv->evaluator); } if (subdiv->topology_refiner != NULL) { @@ -214,12 +223,13 @@ int *BKE_subdiv_face_ptex_offset_get(Subdiv *subdiv) } const int num_coarse_faces = topology_refiner->getNumFaces(topology_refiner); subdiv->cache_.face_ptex_offset = MEM_malloc_arrayN( - num_coarse_faces, sizeof(int), "subdiv face_ptex_offset"); + num_coarse_faces + 1, sizeof(int), "subdiv face_ptex_offset"); int ptex_offset = 0; for (int face_index = 0; face_index < num_coarse_faces; face_index++) { const int num_ptex_faces = topology_refiner->getNumFacePtexFaces(topology_refiner, face_index); subdiv->cache_.face_ptex_offset[face_index] = ptex_offset; ptex_offset += num_ptex_faces; } + subdiv->cache_.face_ptex_offset[num_coarse_faces] = ptex_offset; return subdiv->cache_.face_ptex_offset; } diff --git a/source/blender/blenkernel/intern/subdiv_ccg.c b/source/blender/blenkernel/intern/subdiv_ccg.c index 77962ec924c..7d876acf776 100644 --- a/source/blender/blenkernel/intern/subdiv_ccg.c +++ b/source/blender/blenkernel/intern/subdiv_ccg.c @@ -603,7 +603,8 @@ Mesh *BKE_subdiv_to_ccg_mesh(Subdiv *subdiv, { /* Make sure evaluator is ready. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_CCG); - if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) { + if (!BKE_subdiv_eval_begin_from_mesh( + subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { if (coarse_mesh->totpoly) { return NULL; } diff --git a/source/blender/blenkernel/intern/subdiv_deform.c b/source/blender/blenkernel/intern/subdiv_deform.c index 7a2d639e4e5..c385b1b291d 100644 --- a/source/blender/blenkernel/intern/subdiv_deform.c +++ b/source/blender/blenkernel/intern/subdiv_deform.c @@ -117,7 +117,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex const int UNUSED(num_vertices), const int UNUSED(num_edges), const int UNUSED(num_loops), - const int UNUSED(num_polygons)) + const int UNUSED(num_polygons), + const int *UNUSED(subdiv_polygon_offset)) { SubdivDeformContext *subdiv_context = foreach_context->user_data; subdiv_mesh_prepare_accumulator(subdiv_context, subdiv_context->coarse_mesh->totvert); @@ -202,7 +203,8 @@ void BKE_subdiv_deform_coarse_vertices(struct Subdiv *subdiv, BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); /* Make sure evaluator is up to date with possible new topology, and that * is refined for the new positions of coarse vertices. */ - if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, vertex_cos)) { + if (!BKE_subdiv_eval_begin_from_mesh( + subdiv, coarse_mesh, vertex_cos, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our diff --git a/source/blender/blenkernel/intern/subdiv_eval.c b/source/blender/blenkernel/intern/subdiv_eval.c index 0001eb8a205..9733a1498a6 100644 --- a/source/blender/blenkernel/intern/subdiv_eval.c +++ b/source/blender/blenkernel/intern/subdiv_eval.c @@ -28,6 +28,7 @@ #include "BLI_bitmap.h" #include "BLI_math_vector.h" +#include "BLI_task.h" #include "BLI_utildefines.h" #include "BKE_customdata.h" @@ -38,7 +39,28 @@ #include "opensubdiv_evaluator_capi.h" #include "opensubdiv_topology_refiner_capi.h" -bool BKE_subdiv_eval_begin(Subdiv *subdiv) +/* ============================ Helper Function ============================ */ + +static eOpenSubdivEvaluator opensubdiv_evalutor_from_subdiv_evaluator_type( + eSubdivEvaluatorType evaluator_type) +{ + switch (evaluator_type) { + case SUBDIV_EVALUATOR_TYPE_CPU: { + return OPENSUBDIV_EVALUATOR_CPU; + } + case SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE: { + return OPENSUBDIV_EVALUATOR_GLSL_COMPUTE; + } + } + BLI_assert_msg(0, "Unknown evaluator type"); + return OPENSUBDIV_EVALUATOR_CPU; +} + +/* ====================== Main Subdivision Evaluation ====================== */ + +bool BKE_subdiv_eval_begin(Subdiv *subdiv, + eSubdivEvaluatorType evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache) { BKE_subdiv_stats_reset(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->topology_refiner == NULL) { @@ -47,8 +69,11 @@ bool BKE_subdiv_eval_begin(Subdiv *subdiv) return false; } if (subdiv->evaluator == NULL) { + eOpenSubdivEvaluator opensubdiv_evaluator_type = + opensubdiv_evalutor_from_subdiv_evaluator_type(evaluator_type); BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); - subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner(subdiv->topology_refiner); + subdiv->evaluator = openSubdiv_createEvaluatorFromTopologyRefiner( + subdiv->topology_refiner, opensubdiv_evaluator_type, evaluator_cache); BKE_subdiv_stats_end(&subdiv->stats, SUBDIV_STATS_EVALUATOR_CREATE); if (subdiv->evaluator == NULL) { return false; @@ -80,6 +105,9 @@ static void set_coarse_positions(Subdiv *subdiv, BLI_BITMAP_ENABLE(vertex_used_map, loop->v); } } + /* Use a temporary buffer so we do not upload vertices one at a time to the GPU. */ + float(*buffer)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, "subdiv tmp coarse positions"); + int manifold_vertex_count = 0; for (int vertex_index = 0, manifold_vertex_index = 0; vertex_index < mesh->totvert; vertex_index++) { if (!BLI_BITMAP_TEST_BOOL(vertex_used_map, vertex_index)) { @@ -93,13 +121,49 @@ static void set_coarse_positions(Subdiv *subdiv, const MVert *vertex = &mvert[vertex_index]; vertex_co = vertex->co; } - subdiv->evaluator->setCoarsePositions(subdiv->evaluator, vertex_co, manifold_vertex_index, 1); + copy_v3_v3(&buffer[manifold_vertex_index][0], vertex_co); manifold_vertex_index++; + manifold_vertex_count++; } + subdiv->evaluator->setCoarsePositions( + subdiv->evaluator, &buffer[0][0], 0, manifold_vertex_count); MEM_freeN(vertex_used_map); + MEM_freeN(buffer); +} + +/* Context which is used to fill face varying data in parallel. */ +typedef struct FaceVaryingDataFromUVContext { + OpenSubdiv_TopologyRefiner *topology_refiner; + const Mesh *mesh; + const MLoopUV *mloopuv; + float (*buffer)[2]; + int layer_index; +} FaceVaryingDataFromUVContext; + +static void set_face_varying_data_from_uv_task(void *__restrict userdata, + const int face_index, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + FaceVaryingDataFromUVContext *ctx = userdata; + OpenSubdiv_TopologyRefiner *topology_refiner = ctx->topology_refiner; + const int layer_index = ctx->layer_index; + const Mesh *mesh = ctx->mesh; + const MPoly *mpoly = &mesh->mpoly[face_index]; + const MLoopUV *mluv = &ctx->mloopuv[mpoly->loopstart]; + + /* TODO(sergey): OpenSubdiv's C-API converter can change winding of + * loops of a face, need to watch for that, to prevent wrong UVs assigned. + */ + const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, face_index); + const int *uv_indices = topology_refiner->getFaceFVarValueIndices( + topology_refiner, face_index, layer_index); + for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) { + copy_v2_v2(ctx->buffer[uv_indices[vertex_index]], mluv->uv); + } } static void set_face_varying_data_from_uv(Subdiv *subdiv, + const Mesh *mesh, const MLoopUV *mloopuv, const int layer_index) { @@ -107,25 +171,37 @@ static void set_face_varying_data_from_uv(Subdiv *subdiv, OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; const int num_faces = topology_refiner->getNumFaces(topology_refiner); const MLoopUV *mluv = mloopuv; - /* TODO(sergey): OpenSubdiv's C-API converter can change winding of - * loops of a face, need to watch for that, to prevent wrong UVs assigned. - */ - for (int face_index = 0; face_index < num_faces; face_index++) { - const int num_face_vertices = topology_refiner->getNumFaceVertices(topology_refiner, - face_index); - const int *uv_indices = topology_refiner->getFaceFVarValueIndices( - topology_refiner, face_index, layer_index); - for (int vertex_index = 0; vertex_index < num_face_vertices; vertex_index++, mluv++) { - evaluator->setFaceVaryingData(evaluator, layer_index, mluv->uv, uv_indices[vertex_index], 1); - } - } + + const int num_fvar_values = topology_refiner->getNumFVarValues(topology_refiner, layer_index); + /* Use a temporary buffer so we do not upload UVs one at a time to the GPU. */ + float(*buffer)[2] = MEM_mallocN(sizeof(float[2]) * num_fvar_values, "temp UV storage"); + + FaceVaryingDataFromUVContext ctx; + ctx.topology_refiner = topology_refiner; + ctx.layer_index = layer_index; + ctx.mloopuv = mluv; + ctx.mesh = mesh; + ctx.buffer = buffer; + + TaskParallelSettings parallel_range_settings; + BLI_parallel_range_settings_defaults(¶llel_range_settings); + parallel_range_settings.min_iter_per_thread = 1; + + BLI_task_parallel_range( + 0, num_faces, &ctx, set_face_varying_data_from_uv_task, ¶llel_range_settings); + + evaluator->setFaceVaryingData(evaluator, layer_index, &buffer[0][0], 0, num_fvar_values); + + MEM_freeN(buffer); } bool BKE_subdiv_eval_begin_from_mesh(Subdiv *subdiv, const Mesh *mesh, - const float (*coarse_vertex_cos)[3]) + const float (*coarse_vertex_cos)[3], + eSubdivEvaluatorType evaluator_type, + OpenSubdiv_EvaluatorCache *evaluator_cache) { - if (!BKE_subdiv_eval_begin(subdiv)) { + if (!BKE_subdiv_eval_begin(subdiv, evaluator_type, evaluator_cache)) { return false; } return BKE_subdiv_eval_refine_from_mesh(subdiv, mesh, coarse_vertex_cos); @@ -146,7 +222,7 @@ bool BKE_subdiv_eval_refine_from_mesh(Subdiv *subdiv, const int num_uv_layers = CustomData_number_of_layers(&mesh->ldata, CD_MLOOPUV); for (int layer_index = 0; layer_index < num_uv_layers; layer_index++) { const MLoopUV *mloopuv = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPUV, layer_index); - set_face_varying_data_from_uv(subdiv, mloopuv, layer_index); + set_face_varying_data_from_uv(subdiv, mesh, mloopuv, layer_index); } /* Update evaluator to the new coarse geometry. */ BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_EVALUATOR_REFINE); diff --git a/source/blender/blenkernel/intern/subdiv_foreach.c b/source/blender/blenkernel/intern/subdiv_foreach.c index 061c196df2a..69bead27fe6 100644 --- a/source/blender/blenkernel/intern/subdiv_foreach.c +++ b/source/blender/blenkernel/intern/subdiv_foreach.c @@ -1877,7 +1877,8 @@ bool BKE_subdiv_foreach_subdiv_geometry(Subdiv *subdiv, ctx.num_subdiv_vertices, ctx.num_subdiv_edges, ctx.num_subdiv_loops, - ctx.num_subdiv_polygons)) { + ctx.num_subdiv_polygons, + ctx.subdiv_polygon_offset)) { subdiv_foreach_ctx_free(&ctx); return false; } diff --git a/source/blender/blenkernel/intern/subdiv_mesh.c b/source/blender/blenkernel/intern/subdiv_mesh.c index e5c7d13edab..1f31d0543ad 100644 --- a/source/blender/blenkernel/intern/subdiv_mesh.c +++ b/source/blender/blenkernel/intern/subdiv_mesh.c @@ -514,7 +514,8 @@ static bool subdiv_mesh_topology_info(const SubdivForeachContext *foreach_contex const int num_vertices, const int num_edges, const int num_loops, - const int num_polygons) + const int num_polygons, + const int *UNUSED(subdiv_polygon_offset)) { /* Multires grid data will be applied or become invalid after subdivision, * so don't try to preserve it and use memory. */ @@ -1193,7 +1194,8 @@ Mesh *BKE_subdiv_to_mesh(Subdiv *subdiv, BKE_subdiv_stats_begin(&subdiv->stats, SUBDIV_STATS_SUBDIV_TO_MESH); /* Make sure evaluator is up to date with possible new topology, and that * it is refined for the new positions of coarse vertices. */ - if (!BKE_subdiv_eval_begin_from_mesh(subdiv, coarse_mesh, NULL)) { + if (!BKE_subdiv_eval_begin_from_mesh( + subdiv, coarse_mesh, NULL, SUBDIV_EVALUATOR_TYPE_CPU, NULL)) { /* This could happen in two situations: * - OpenSubdiv is disabled. * - Something totally bad happened, and OpenSubdiv rejected our diff --git a/source/blender/blenkernel/intern/subdiv_modifier.c b/source/blender/blenkernel/intern/subdiv_modifier.c new file mode 100644 index 00000000000..bafcb631f59 --- /dev/null +++ b/source/blender/blenkernel/intern/subdiv_modifier.c @@ -0,0 +1,162 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2021 by Blender Foundation. + * All rights reserved. + */ + +#include "BKE_subdiv_modifier.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_userdef_types.h" + +#include "BKE_modifier.h" +#include "BKE_subdiv.h" + +#include "GPU_capabilities.h" +#include "GPU_context.h" + +#include "opensubdiv_capi.h" + +void BKE_subsurf_modifier_subdiv_settings_init(SubdivSettings *settings, + const SubsurfModifierData *smd, + const bool use_render_params) +{ + const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels; + + settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); + settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision); + settings->level = settings->is_simple ? + 1 : + (settings->is_adaptive ? smd->quality : requested_levels); + settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); + settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( + smd->boundary_smooth); + settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( + smd->uv_smooth); +} + +static ModifierData *modifier_get_last_enabled_for_mode(const Scene *scene, + const Object *ob, + int required_mode) +{ + ModifierData *md = ob->modifiers.last; + + while (md) { + if (BKE_modifier_is_enabled(scene, md, required_mode)) { + break; + } + + md = md->prev; + } + + return md; +} + +bool BKE_subsurf_modifier_can_do_gpu_subdiv_ex(const Scene *scene, + const Object *ob, + const SubsurfModifierData *smd, + int required_mode, + bool skip_check_is_last) +{ + if ((U.gpu_flag & USER_GPU_FLAG_SUBDIVISION_EVALUATION) == 0) { + return false; + } + + if (!skip_check_is_last) { + ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode); + if (md != (const ModifierData *)smd) { + return false; + } + } + + /* Only OpenGL is supported for OpenSubdiv evaluation for now. */ + if (GPU_backend_get_type() != GPU_BACKEND_OPENGL) { + return false; + } + + if (!GPU_compute_shader_support()) { + return false; + } + + const int available_evaluators = openSubdiv_getAvailableEvaluators(); + if ((available_evaluators & OPENSUBDIV_EVALUATOR_GLSL_COMPUTE) == 0) { + return false; + } + + return true; +} + +bool BKE_subsurf_modifier_can_do_gpu_subdiv(const Scene *scene, + const Object *ob, + int required_mode) +{ + ModifierData *md = modifier_get_last_enabled_for_mode(scene, ob, required_mode); + + if (!md) { + return false; + } + + if (md->type != eModifierType_Subsurf) { + return false; + } + + return BKE_subsurf_modifier_can_do_gpu_subdiv_ex( + scene, ob, (SubsurfModifierData *)md, required_mode, true); +} + +void (*BKE_subsurf_modifier_free_gpu_cache_cb)(Subdiv *subdiv) = NULL; + +/* Main goal of this function is to give usable subdivision surface descriptor + * which matches settings and topology. */ +Subdiv *BKE_subsurf_modifier_subdiv_descriptor_ensure(const SubsurfModifierData *smd, + const SubdivSettings *subdiv_settings, + const Mesh *mesh, + const bool for_draw_code) +{ + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + if (runtime_data->subdiv && runtime_data->set_by_draw_code != for_draw_code) { + BKE_subdiv_free(runtime_data->subdiv); + runtime_data->subdiv = NULL; + } + Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh); + runtime_data->subdiv = subdiv; + runtime_data->set_by_draw_code = for_draw_code; + return subdiv; +} + +SubsurfRuntimeData *BKE_subsurf_modifier_ensure_runtime(SubsurfModifierData *smd) +{ + SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; + if (runtime_data == NULL) { + runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); + smd->modifier.runtime = runtime_data; + } + return runtime_data; +} + +int BKE_subsurf_modifier_eval_required_mode(bool is_final_render, bool is_edit_mode) +{ + if (is_final_render) { + return eModifierMode_Render; + } + + return eModifierMode_Realtime | (is_edit_mode ? eModifierMode_Editmode : 0); +} diff --git a/source/blender/blenkernel/intern/volume.cc b/source/blender/blenkernel/intern/volume.cc index 130aa957491..4b71c98339b 100644 --- a/source/blender/blenkernel/intern/volume.cc +++ b/source/blender/blenkernel/intern/volume.cc @@ -537,7 +537,7 @@ static void volume_copy_data(Main *UNUSED(bmain), #ifdef WITH_OPENVDB if (volume_src->runtime.grids) { const VolumeGridVector &grids_src = *(volume_src->runtime.grids); - volume_dst->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector, grids_src); + volume_dst->runtime.grids = MEM_new<VolumeGridVector>(__func__, grids_src); } #endif @@ -551,7 +551,8 @@ static void volume_free_data(ID *id) BKE_volume_batch_cache_free(volume); MEM_SAFE_FREE(volume->mat); #ifdef WITH_OPENVDB - OBJECT_GUARDED_SAFE_DELETE(volume->runtime.grids, VolumeGridVector); + MEM_delete(volume->runtime.grids); + volume->runtime.grids = nullptr; #endif } @@ -683,7 +684,7 @@ void BKE_volume_init_grids(Volume *volume) { #ifdef WITH_OPENVDB if (volume->runtime.grids == nullptr) { - volume->runtime.grids = OBJECT_GUARDED_NEW(VolumeGridVector); + volume->runtime.grids = MEM_new<VolumeGridVector>(__func__); } #else UNUSED_VARS(volume); @@ -954,7 +955,7 @@ BoundBox *BKE_volume_boundbox_get(Object *ob) } if (ob->runtime.bb == nullptr) { - ob->runtime.bb = (BoundBox *)MEM_callocN(sizeof(BoundBox), __func__); + ob->runtime.bb = MEM_cnew<BoundBox>(__func__); } const Volume *volume = (Volume *)ob->data; @@ -1129,16 +1130,16 @@ void BKE_volume_grids_backup_restore(Volume *volume, VolumeGridVector *grids, co if (!grids->is_loaded()) { /* No grids loaded in CoW datablock, nothing lost by discarding. */ - OBJECT_GUARDED_DELETE(grids, VolumeGridVector); + MEM_delete(grids); } else if (!STREQ(volume->filepath, filepath)) { /* Filepath changed, discard grids from CoW datablock. */ - OBJECT_GUARDED_DELETE(grids, VolumeGridVector); + MEM_delete(grids); } else { /* Keep grids from CoW datablock. We might still unload them a little * later in BKE_volume_eval_geometry if the frame changes. */ - OBJECT_GUARDED_DELETE(volume->runtime.grids, VolumeGridVector); + MEM_delete(volume->runtime.grids); volume->runtime.grids = grids; } #else diff --git a/source/blender/blenlib/BLI_assert.h b/source/blender/blenlib/BLI_assert.h index 6019f0f3566..e32a19cfc25 100644 --- a/source/blender/blenlib/BLI_assert.h +++ b/source/blender/blenlib/BLI_assert.h @@ -30,6 +30,7 @@ extern "C" { #endif /* Utility functions. */ + void _BLI_assert_print_pos(const char *file, const int line, const char *function, const char *id); void _BLI_assert_print_extra(const char *str); void _BLI_assert_print_backtrace(void); diff --git a/source/blender/blenlib/BLI_color.hh b/source/blender/blenlib/BLI_color.hh index d93bd7f6f76..dce625777b9 100644 --- a/source/blender/blenlib/BLI_color.hh +++ b/source/blender/blenlib/BLI_color.hh @@ -73,27 +73,27 @@ namespace blender { * - Add non RGB spaces/storages ColorXyz. */ -/* Enumeration containing the different alpha modes. */ +/** Enumeration containing the different alpha modes. */ enum class eAlpha { - /* Color and alpha are unassociated. */ + /** Color and alpha are unassociated. */ Straight, - /* Color and alpha are associated. */ + /** Color and alpha are associated. */ Premultiplied, }; std::ostream &operator<<(std::ostream &stream, const eAlpha &space); -/* Enumeration containing internal spaces. */ +/** Enumeration containing internal spaces. */ enum class eSpace { - /* Blender theme color space (sRGB). */ + /** Blender theme color space (sRGB). */ Theme, - /* Blender internal scene linear color space (maps to SceneReference role in OCIO). */ + /** Blender internal scene linear color space (maps to SceneReference role in OCIO). */ SceneLinear, - /* Blender internal scene linear color space compressed to be stored in 4 uint8_t. */ + /** Blender internal scene linear color space compressed to be stored in 4 uint8_t. */ SceneLinearByteEncoded, }; std::ostream &operator<<(std::ostream &stream, const eSpace &space); -/* Template class to store RGBA values with different precision, space and alpha association. */ +/** Template class to store RGBA values with different precision, space and alpha association. */ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGBA { public: ChannelStorageType r, g, b, a; @@ -153,11 +153,13 @@ template<typename ChannelStorageType, eSpace Space, eAlpha Alpha> class ColorRGB }; /* Forward declarations of concrete color classes. */ + template<eAlpha Alpha> class ColorSceneLinear4f; template<eAlpha Alpha> class ColorSceneLinearByteEncoded4b; template<typename ChannelStorageType> class ColorTheme4; /* Forward declaration of precision conversion methods. */ + BLI_INLINE ColorTheme4<float> BLI_color_convert_to_theme4f(const ColorTheme4<uint8_t> &srgb4b); BLI_INLINE ColorTheme4<uint8_t> BLI_color_convert_to_theme4b(const ColorTheme4<float> &srgb4f); @@ -354,6 +356,7 @@ BLI_color_convert_to_theme4b(const ColorSceneLinear4f<eAlpha::Straight> &scene_l } /* Internal roles. For convenience to shorten the type names and hide complexity. */ + using ColorGeometry4f = ColorSceneLinear4f<eAlpha::Premultiplied>; using ColorGeometry4b = ColorSceneLinearByteEncoded4b<eAlpha::Premultiplied>; diff --git a/source/blender/blenlib/BLI_compiler_compat.h b/source/blender/blenlib/BLI_compiler_compat.h index bd8f84cedd6..023fea3853e 100644 --- a/source/blender/blenlib/BLI_compiler_compat.h +++ b/source/blender/blenlib/BLI_compiler_compat.h @@ -34,7 +34,7 @@ #if (defined(__GNUC__) || defined(__clang__)) && defined(__cplusplus) extern "C++" { -/* Some magic to be sure we don't have reference in the type. */ +/** Some magic to be sure we don't have reference in the type. */ template<typename T> static inline T decltype_helper(T x) { return x; diff --git a/source/blender/blenlib/BLI_delaunay_2d.h b/source/blender/blenlib/BLI_delaunay_2d.h index 658dcadadce..db0df95499f 100644 --- a/source/blender/blenlib/BLI_delaunay_2d.h +++ b/source/blender/blenlib/BLI_delaunay_2d.h @@ -222,7 +222,7 @@ void BLI_delaunay_2d_cdt_free(CDT_result *result); namespace blender::meshintersect { -/* vec2<Arith_t> is a 2d vector with Arith_t as the type for coordinates. */ +/** #vec2<Arith_t> is a 2d vector with #Arith_t as the type for coordinates. */ template<typename Arith_t> struct vec2_impl; template<> struct vec2_impl<double> { typedef double2 type; diff --git a/source/blender/blenlib/BLI_dlrbTree.h b/source/blender/blenlib/BLI_dlrbTree.h index 72f18244d5b..3cf849efaef 100644 --- a/source/blender/blenlib/BLI_dlrbTree.h +++ b/source/blender/blenlib/BLI_dlrbTree.h @@ -40,7 +40,7 @@ extern "C" { /** \name Base Structs * \{ */ -/* Basic Layout for a Node */ +/** Basic Layout for a Node. */ typedef struct DLRBT_Node { /* ListBase capabilities */ struct DLRBT_Node *next, *prev; @@ -53,7 +53,7 @@ typedef struct DLRBT_Node { /* ... for nice alignment, next item should usually be a char too... */ } DLRBT_Node; -/* Red/Black defines for tree_col */ +/** Red/Black defines for tree_col. */ typedef enum eDLRBT_Colors { DLRBT_BLACK = 0, DLRBT_RED, @@ -61,7 +61,7 @@ typedef enum eDLRBT_Colors { /* -------- */ -/* The Tree Data */ +/** The Tree Data. */ typedef struct DLRBT_Tree { /* ListBase capabilities */ void *first, *last; /* these should be based on DLRBT_Node-s */ diff --git a/source/blender/blenlib/BLI_endian_switch.h b/source/blender/blenlib/BLI_endian_switch.h index b512133b34c..e6ccbe4629a 100644 --- a/source/blender/blenlib/BLI_endian_switch.h +++ b/source/blender/blenlib/BLI_endian_switch.h @@ -30,6 +30,7 @@ extern "C" { #endif /* BLI_endian_switch_inline.h */ + BLI_INLINE void BLI_endian_switch_int16(short *val) ATTR_NONNULL(1); BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) ATTR_NONNULL(1); BLI_INLINE void BLI_endian_switch_int32(int *val) ATTR_NONNULL(1); @@ -40,6 +41,7 @@ BLI_INLINE void BLI_endian_switch_uint64(uint64_t *val) ATTR_NONNULL(1); BLI_INLINE void BLI_endian_switch_double(double *val) ATTR_NONNULL(1); /* endian_switch.c */ + void BLI_endian_switch_int16_array(short *val, const int size) ATTR_NONNULL(1); void BLI_endian_switch_uint16_array(unsigned short *val, const int size) ATTR_NONNULL(1); void BLI_endian_switch_int32_array(int *val, const int size) ATTR_NONNULL(1); diff --git a/source/blender/blenlib/BLI_endian_switch_inline.h b/source/blender/blenlib/BLI_endian_switch_inline.h index ec4cfe4801a..31be7fd47e4 100644 --- a/source/blender/blenlib/BLI_endian_switch_inline.h +++ b/source/blender/blenlib/BLI_endian_switch_inline.h @@ -33,6 +33,7 @@ extern "C" { * use bit shifting instead. */ /* *** 16 *** */ + BLI_INLINE void BLI_endian_switch_int16(short *val) { BLI_endian_switch_uint16((unsigned short *)val); @@ -48,6 +49,7 @@ BLI_INLINE void BLI_endian_switch_uint16(unsigned short *val) } /* *** 32 *** */ + BLI_INLINE void BLI_endian_switch_int32(int *val) { BLI_endian_switch_uint32((unsigned int *)val); @@ -67,6 +69,7 @@ BLI_INLINE void BLI_endian_switch_float(float *val) } /* *** 64 *** */ + BLI_INLINE void BLI_endian_switch_int64(int64_t *val) { BLI_endian_switch_uint64((uint64_t *)val); diff --git a/source/blender/blenlib/BLI_fileops.hh b/source/blender/blenlib/BLI_fileops.hh new file mode 100644 index 00000000000..c69b1983c59 --- /dev/null +++ b/source/blender/blenlib/BLI_fileops.hh @@ -0,0 +1,52 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + * \brief File and directory operations. + */ + +#pragma once + +#ifndef __cplusplus +# error This is a C++ header +#endif + +#include "BLI_fileops.h" +#include "BLI_string_ref.hh" + +#include <fstream> +#include <string> + +namespace blender { + +/** + * std::fstream subclass that handles UTF-16 encoding on Windows. + * + * For documentation, see https://en.cppreference.com/w/cpp/io/basic_fstream + */ +class fstream : public std::fstream { + public: + fstream() = default; + explicit fstream(const char *filepath, + std::ios_base::openmode mode = ios_base::in | ios_base::out); + explicit fstream(const std::string &filepath, + std::ios_base::openmode mode = ios_base::in | ios_base::out); + + void open(StringRefNull filepath, ios_base::openmode mode = ios_base::in | ios_base::out); +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_filereader.h b/source/blender/blenlib/BLI_filereader.h index da223cddf40..f232ad72cc4 100644 --- a/source/blender/blenlib/BLI_filereader.h +++ b/source/blender/blenlib/BLI_filereader.h @@ -47,7 +47,7 @@ typedef ssize_t (*FileReaderReadFn)(struct FileReader *reader, void *buffer, siz typedef off64_t (*FileReaderSeekFn)(struct FileReader *reader, off64_t offset, int whence); typedef void (*FileReaderCloseFn)(struct FileReader *reader); -/* General structure for all FileReaders, implementations add custom fields at the end. */ +/** General structure for all #FileReaders, implementations add custom fields at the end. */ typedef struct FileReader { FileReaderReadFn read; FileReaderSeekFn seek; @@ -64,16 +64,16 @@ typedef struct FileReader { * take over the base FileReader and will clean it up when their clean() is called. */ -/* Create FileReader from raw file descriptor. */ +/** Create #FileReader from raw file descriptor. */ FileReader *BLI_filereader_new_file(int filedes) ATTR_WARN_UNUSED_RESULT; -/* Create FileReader from raw file descriptor using memory-mapped IO. */ +/** Create #FileReader from raw file descriptor using memory-mapped IO. */ FileReader *BLI_filereader_new_mmap(int filedes) ATTR_WARN_UNUSED_RESULT; -/* Create FileReader from a region of memory. */ +/** Create #FileReader from a region of memory. */ FileReader *BLI_filereader_new_memory(const void *data, size_t len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -/* Create FileReader from applying `Zstd` decompression on an underlying file. */ +/** Create #FileReader from applying `Zstd` decompression on an underlying file. */ FileReader *BLI_filereader_new_zstd(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -/* Create FileReader from applying `Gzip` decompression on an underlying file. */ +/** Create #FileReader from applying `Gzip` decompression on an underlying file. */ FileReader *BLI_filereader_new_gzip(FileReader *base) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); #ifdef __cplusplus diff --git a/source/blender/blenlib/BLI_float3.hh b/source/blender/blenlib/BLI_float3.hh index 6ee0c4b973b..765f524fb31 100644 --- a/source/blender/blenlib/BLI_float3.hh +++ b/source/blender/blenlib/BLI_float3.hh @@ -228,6 +228,22 @@ struct float3 { return result; } + static float3 min(const float3 &a, const float3 &b) + { + return {a.x < b.x ? a.x : b.x, a.y < b.y ? a.y : b.y, a.z < b.z ? a.z : b.z}; + } + + static float3 max(const float3 &a, const float3 &b) + { + return {a.x > b.x ? a.x : b.x, a.y > b.y ? a.y : b.y, a.z > b.z ? a.z : b.z}; + } + + static void min_max(const float3 &vector, float3 &min, float3 &max) + { + min = float3::min(vector, min); + max = float3::max(vector, max); + } + static float3 safe_divide(const float3 &a, const float b) { return (b != 0.0f) ? a / b : float3(0.0f); diff --git a/source/blender/blenlib/BLI_ghash.h b/source/blender/blenlib/BLI_ghash.h index 0194f9aad40..fca705535a3 100644 --- a/source/blender/blenlib/BLI_ghash.h +++ b/source/blender/blenlib/BLI_ghash.h @@ -450,7 +450,7 @@ void *BLI_gset_pop_key(GSet *gs, const void *key) ATTR_WARN_UNUSED_RESULT; /* rely on inline api for now */ -/* so we can cast but compiler sees as different */ +/** Use a GSet specific type so we can cast but compiler sees as different */ typedef struct GSetIterator { GHashIterator _ghi #if defined(__GNUC__) && !defined(__clang__) diff --git a/source/blender/blenlib/BLI_hash.hh b/source/blender/blenlib/BLI_hash.hh index 11ff7d040aa..9132aacf7b9 100644 --- a/source/blender/blenlib/BLI_hash.hh +++ b/source/blender/blenlib/BLI_hash.hh @@ -243,6 +243,16 @@ uint64_t get_default_hash_3(const T1 &v1, const T2 &v2, const T3 &v3) return h1 ^ (h2 * 19349669) ^ (h3 * 83492791); } +template<typename T1, typename T2, typename T3, typename T4> +uint64_t get_default_hash_4(const T1 &v1, const T2 &v2, const T3 &v3, const T4 &v4) +{ + const uint64_t h1 = get_default_hash(v1); + const uint64_t h2 = get_default_hash(v2); + const uint64_t h3 = get_default_hash(v3); + const uint64_t h4 = get_default_hash(v4); + return h1 ^ (h2 * 19349669) ^ (h3 * 83492791) ^ (h4 * 3632623); +} + template<typename T> struct DefaultHash<std::unique_ptr<T>> { uint64_t operator()(const std::unique_ptr<T> &value) const { diff --git a/source/blender/blenlib/BLI_kdtree_impl.h b/source/blender/blenlib/BLI_kdtree_impl.h index 26a22fc2ac4..35dbf141c92 100644 --- a/source/blender/blenlib/BLI_kdtree_impl.h +++ b/source/blender/blenlib/BLI_kdtree_impl.h @@ -74,7 +74,7 @@ int BLI_kdtree_nd_(calc_duplicates_fast)(const KDTree *tree, int BLI_kdtree_nd_(deduplicate)(KDTree *tree); -/* Versions of find/range search that take a squared distance callback to support bias. */ +/** Versions of find/range search that take a squared distance callback to support bias. */ int BLI_kdtree_nd_(find_nearest_n_with_len_squared_cb)( const KDTree *tree, const float co[KD_DIMS], diff --git a/source/blender/blenlib/BLI_linklist_lockfree.h b/source/blender/blenlib/BLI_linklist_lockfree.h index 142fa1cf243..d2083bdd44e 100644 --- a/source/blender/blenlib/BLI_linklist_lockfree.h +++ b/source/blender/blenlib/BLI_linklist_lockfree.h @@ -48,18 +48,19 @@ typedef void (*LockfreeeLinkNodeFreeFP)(void *link); /* NOTE: These functions are NOT safe for use from threads. */ /* NOTE: !!! I REPEAT: DO NOT USE THEM WITHOUT EXTERNAL LOCK !!! */ -/* Make list ready for lock-free access. */ +/** Make list ready for lock-free access. */ void BLI_linklist_lockfree_init(LockfreeLinkList *list); -/* Completely free the whole list, it is NOT re-usable after this. */ +/** Completely free the whole list, it is NOT re-usable after this. */ void BLI_linklist_lockfree_free(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func); -/* Remove all the elements from the list, keep it usable for further - * inserts. +/** + * Remove all the elements from the list, keep it usable for further inserts. */ void BLI_linklist_lockfree_clear(LockfreeLinkList *list, LockfreeeLinkNodeFreeFP free_func); -/* Begin iteration of lock-free linked list, starting with a +/** + * Begin iteration of lock-free linked list, starting with a * first user=defined node. Will ignore the dummy node. */ LockfreeLinkNode *BLI_linklist_lockfree_begin(LockfreeLinkList *list); diff --git a/source/blender/blenlib/BLI_listbase.h b/source/blender/blenlib/BLI_listbase.h index 7d808d339e9..a2a6e958213 100644 --- a/source/blender/blenlib/BLI_listbase.h +++ b/source/blender/blenlib/BLI_listbase.h @@ -46,6 +46,11 @@ int BLI_findstringindex(const struct ListBase *listbase, const char *id, const int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1); +/** + * Return a ListBase representing the entire list the given Link is in. + */ +ListBase BLI_listbase_from_link(struct Link *some_link); + /* Find forwards. */ /** @@ -279,6 +284,23 @@ BLI_INLINE void BLI_listbase_clear(struct ListBase *lb) } /** + * Equality check for ListBase. + * + * This only shallowly compares the ListBase itself (so the first/last + * pointers), and does not do any equality checks on the list items. + */ +BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b) +{ + if (a == NULL) { + return b == NULL; + } + if (b == NULL) { + return false; + } + return a->first == b->first && a->last == b->last; +} + +/** * Create a generic list node containing link to provided data. */ struct LinkData *BLI_genericNodeN(void *data); @@ -353,3 +375,10 @@ struct LinkData *BLI_genericNodeN(void *data); #ifdef __cplusplus } #endif + +#ifdef __cplusplus +BLI_INLINE bool operator==(const ListBase &a, const ListBase &b) +{ + return BLI_listbase_equal(&a, &b); +} +#endif diff --git a/source/blender/blenlib/BLI_math_base.h b/source/blender/blenlib/BLI_math_base.h index 83822481112..6c82bd89e64 100644 --- a/source/blender/blenlib/BLI_math_base.h +++ b/source/blender/blenlib/BLI_math_base.h @@ -76,8 +76,7 @@ #if defined(__GNUC__) # define NAN_FLT __builtin_nanf("") -#else -/* evil quiet NaN definition */ +#else /* evil quiet NaN definition */ static const int NAN_INT = 0x7FC00000; # define NAN_FLT (*((float *)(&NAN_INT))) #endif @@ -97,7 +96,8 @@ extern "C" { /******************************* Float ******************************/ -/* powf is really slow for raising to integer powers. */ +/* `powf` is really slow for raising to integer powers. */ + MINLINE float pow2f(float x); MINLINE float pow3f(float x); MINLINE float pow4f(float x); diff --git a/source/blender/blenlib/BLI_math_bits.h b/source/blender/blenlib/BLI_math_bits.h index e881f1a0e4e..70a54879446 100644 --- a/source/blender/blenlib/BLI_math_bits.h +++ b/source/blender/blenlib/BLI_math_bits.h @@ -28,24 +28,29 @@ extern "C" { #endif /* Search the value from LSB to MSB for a set bit. Returns index of this bit. */ + MINLINE int bitscan_forward_i(int a); MINLINE unsigned int bitscan_forward_uint(unsigned int a); MINLINE unsigned int bitscan_forward_uint64(unsigned long long a); /* Similar to above, but also clears the bit. */ + MINLINE int bitscan_forward_clear_i(int *a); MINLINE unsigned int bitscan_forward_clear_uint(unsigned int *a); /* Search the value from MSB to LSB for a set bit. Returns index of this bit. */ + MINLINE int bitscan_reverse_i(int a); MINLINE unsigned int bitscan_reverse_uint(unsigned int a); MINLINE unsigned int bitscan_reverse_uint64(unsigned long long a); /* Similar to above, but also clears the bit. */ + MINLINE int bitscan_reverse_clear_i(int *a); MINLINE unsigned int bitscan_reverse_clear_uint(unsigned int *a); /* NOTE: Those functions returns 2 to the power of index of highest order bit. */ + MINLINE unsigned int highest_order_bit_uint(unsigned int n); MINLINE unsigned short highest_order_bit_s(unsigned short n); diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 55d118d17de..c2a5ffafa64 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -441,7 +441,9 @@ void isect_seg_seg_v3(const float a0[3], float r_a[3], float r_b[3]); -/* intersect Line-Line, shorts */ +/** + * Intersect Line-Line, integer. + */ int isect_seg_seg_v2_int(const int v1[2], const int v2[2], const int v3[2], const int v4[2]); /** * Get intersection point of two 2D segments. @@ -929,7 +931,7 @@ void interp_weights_quad_v3(float w[4], void interp_weights_poly_v3(float w[], float v[][3], const int n, const float co[3]); void interp_weights_poly_v2(float w[], float v[][2], const int n, const float co[2]); -/* (x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t) */ +/** `(x1, v1)(t1=0)------(x2, v2)(t2=1), 0<t<1 --> (x, v)(t)`. */ void interp_cubic_v3(float x[3], float v[3], const float x1[3], diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 3d8fe6f564a..90b74e2f504 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -56,16 +56,18 @@ void copy_m4_m2(float m1[4][4], const float m2[2][2]); void copy_m4_m4_db(double m1[4][4], const double m2[4][4]); /* double->float */ + void copy_m3_m3d(float m1[3][3], const double m2[3][3]); /* float->double */ + void copy_m3d_m3(double m1[3][3], const float m2[3][3]); void copy_m4d_m4(double m1[4][4], const float m2[4][4]); void swap_m3m3(float m1[3][3], float m2[3][3]); void swap_m4m4(float m1[4][4], float m2[4][4]); -/* Build index shuffle matrix */ +/** Build index shuffle matrix. */ void shuffle_m4(float R[4][4], const int index[4]); /** \} */ @@ -112,7 +114,8 @@ void mul_m4db_m4db_m4fl_uniq(double R[4][4], const double A[4][4], const float B void mul_m4_m4_pre(float R[4][4], const float A[4][4]); void mul_m4_m4_post(float R[4][4], const float B[4][4]); -/* mul_m3_series */ +/* Implement #mul_m3_series macro. */ + void _va_mul_m3_series_3(float R[3][3], const float M1[3][3], const float M2[3][3]) ATTR_NONNULL(); void _va_mul_m3_series_4(float R[3][3], const float M1[3][3], @@ -153,7 +156,9 @@ void _va_mul_m3_series_9(float R[3][3], const float M6[3][3], const float M7[3][3], const float M8[3][3]) ATTR_NONNULL(); -/* mul_m4_series */ + +/* Implement #mul_m4_series macro. */ + void _va_mul_m4_series_3(float R[4][4], const float M1[4][4], const float M2[4][4]) ATTR_NONNULL(); void _va_mul_m4_series_4(float R[4][4], const float M1[4][4], @@ -266,11 +271,13 @@ bool invert_m4_m4(float R[4][4], const float A[4][4]); */ bool invert_m4_m4_fallback(float R[4][4], const float A[4][4]); -/* double arithmetic (mixed float/double) */ +/* Double arithmetic (mixed float/double). */ + void mul_m4_v4d(const float M[4][4], double r[4]); void mul_v4d_m4v4d(double r[4], const float M[4][4], const double v[4]); -/* double matrix functions (no mixing types) */ +/* Double matrix functions (no mixing types). */ + void mul_v3_m3v3_db(double r[3], const double M[3][3], const double a[3]); void mul_m3_v3_db(const double M[3][3], double r[3]); @@ -282,7 +289,9 @@ void mul_m3_v3_db(const double M[3][3], double r[3]); void transpose_m3(float R[3][3]); void transpose_m3_m3(float R[3][3], const float M[3][3]); -/* seems obscure but in-fact a common operation */ +/** + * \note Seems obscure but in-fact a common operation. + */ void transpose_m3_m4(float R[3][3], const float M[4][4]); void transpose_m4(float R[4][4]); void transpose_m4_m4(float R[4][4], const float M[4][4]); diff --git a/source/blender/blenlib/BLI_math_rotation.h b/source/blender/blenlib/BLI_math_rotation.h index 5e72d502262..8106251684d 100644 --- a/source/blender/blenlib/BLI_math_rotation.h +++ b/source/blender/blenlib/BLI_math_rotation.h @@ -57,7 +57,8 @@ void unit_axis_angle(float axis[3], float *angle); void unit_qt(float q[4]); void copy_qt_qt(float q[4], const float a[4]); -/* arithmetic */ +/* Arithmetic. */ + void mul_qt_qtqt(float q[4], const float a[4], const float b[4]); /** * \note @@ -106,7 +107,8 @@ float dot_qtqt(const float a[4], const float b[4]); float normalize_qt(float q[4]); float normalize_qt_qt(float r[4], const float q[4]); -/* comparison */ +/* Comparison. */ + bool is_zero_qt(const float q[4]); /* interpolation */ @@ -122,7 +124,8 @@ void interp_dot_slerp(const float t, const float cosom, float r_w[2]); void interp_qt_qtqt(float q[4], const float a[4], const float b[4], const float t); void add_qt_qtqt(float q[4], const float a[4], const float b[4], const float t); -/* conversion */ +/* Conversion. */ + void quat_to_mat3(float mat[3][3], const float q[4]); void quat_to_mat4(float mat[4][4], const float q[4]); @@ -188,7 +191,8 @@ float angle_signed_qtqt(const float q1[4], const float q2[4]); */ void mat3_to_quat_is_ok(float q[4], const float mat[3][3]); -/* other */ +/* Other. */ + void print_qt(const char *str, const float q[4]); #define print_qt_id(q) print_qt(STRINGIFY(q), q) @@ -199,7 +203,8 @@ void print_qt(const char *str, const float q[4]); /** \name Axis Angle * \{ */ -/* conversion */ +/* Conversion. */ + void axis_angle_normalized_to_quat(float r[4], const float axis[3], const float angle); void axis_angle_to_quat(float r[4], const float axis[3], const float angle); /** @@ -271,32 +276,25 @@ void expmap_to_quat(float r[4], const float expmap[3]); /** \name XYZ Eulers * \{ */ -/* XYZ order. */ void eul_to_quat(float quat[4], const float eul[3]); -/* XYZ order */ void eul_to_mat3(float mat[3][3], const float eul[3]); -/* XYZ order */ void eul_to_mat4(float mat[4][4], const float eul[3]); -/* XYZ order */ void mat3_normalized_to_eul(float eul[3], const float mat[3][3]); -/* XYZ order */ void mat4_normalized_to_eul(float eul[3], const float mat[4][4]); void mat3_to_eul(float eul[3], const float mat[3][3]); void mat4_to_eul(float eul[3], const float mat[4][4]); -/* XYZ order */ void quat_to_eul(float eul[3], const float quat[4]); -/* XYZ order */ void mat3_normalized_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); void mat3_to_compatible_eul(float eul[3], const float old[3], float mat[3][3]); void quat_to_compatible_eul(float eul[3], const float oldrot[3], const float quat[4]); -/* order independent! */ -void compatible_eul(float eul[3], const float old[3]); - -/* XYZ order */ void rotate_eul(float eul[3], const char axis, const float angle); +/* Order independent. */ + +void compatible_eul(float eul[3], const float old[3]); + void add_eul_euleul(float r_eul[3], float a[3], float b[3], const short order); void sub_eul_euleul(float r_eul[3], float a[3], float b[3], const short order); diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 8f955076baf..61090e30f7b 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -79,7 +79,9 @@ MINLINE void copy_v4_v4_char(char r[4], const char a[4]); MINLINE void copy_v2_v2_short(short r[2], const short a[2]); MINLINE void copy_v3_v3_short(short r[3], const short a[3]); MINLINE void copy_v4_v4_short(short r[4], const short a[4]); + /* int */ + MINLINE void zero_v3_int(int r[3]); MINLINE void copy_v2_v2_int(int r[2], const int a[2]); MINLINE void copy_v3_v3_int(int r[3], const int a[3]); diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index 14eca49d126..9a5be79b61e 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -498,6 +498,12 @@ inline constexpr bool is_span_convertible_pointer_v = std::is_same_v<To, const void *>); /** + * Same as #std::is_same_v but allows for checking multiple types at the same time. + */ +template<typename T, typename... Args> +inline constexpr bool is_same_any_v = (std::is_same_v<T, Args> || ...); + +/** * Inline buffers for small-object-optimization should be disable by default. Otherwise we might * get large unexpected allocations on the stack. */ diff --git a/source/blender/blenlib/BLI_mempool.h b/source/blender/blenlib/BLI_mempool.h index d6abae36e00..a3cf2a77646 100644 --- a/source/blender/blenlib/BLI_mempool.h +++ b/source/blender/blenlib/BLI_mempool.h @@ -103,14 +103,14 @@ void BLI_mempool_set_memory_debug(void); * \note this may easy to produce bugs with. */ -/* Private structure. */ +/** \note Private structure. */ typedef struct BLI_mempool_iter { BLI_mempool *pool; struct BLI_mempool_chunk *curchunk; unsigned int curindex; } BLI_mempool_iter; -/* flag */ +/** #BLI_mempool.flag */ enum { BLI_MEMPOOL_NOP = 0, /** allow iterating on this mempool. diff --git a/source/blender/blenlib/BLI_path_util.h b/source/blender/blenlib/BLI_path_util.h index 8b54ee52322..70eb80e7763 100644 --- a/source/blender/blenlib/BLI_path_util.h +++ b/source/blender/blenlib/BLI_path_util.h @@ -254,6 +254,10 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); /** * Make given name safe to be used in paths. * + * \param allow_tokens: Permit the usage of '<' and '>' characters. This can be + * leveraged by higher layers to support "virtual filenames" which contain + * substitution markers delineated between the two characters. + * * \return true if \a fname was changed, false otherwise. * * For now, simply replaces reserved chars (as listed in @@ -273,7 +277,9 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) ATTR_NONNULL(2); * \note On Windows, it also checks for forbidden names * (see https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx ). */ +bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) ATTR_NONNULL(1); bool BLI_filename_make_safe(char *fname) ATTR_NONNULL(1); + /** * Make given path OS-safe. * diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h index fdb7d1e67ac..450653a20ea 100644 --- a/source/blender/blenlib/BLI_quadric.h +++ b/source/blender/blenlib/BLI_quadric.h @@ -31,18 +31,21 @@ typedef struct Quadric { double a2, ab, ac, ad, b2, bc, bd, c2, cd, d2; } Quadric; -/* conversion */ +/* Conversion. */ + void BLI_quadric_from_plane(Quadric *q, const double v[4]); void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]); void BLI_quadric_clear(Quadric *q); -/* math */ +/* Math operations. */ + void BLI_quadric_add_qu_qu(Quadric *a, const Quadric *b); void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b); void BLI_quadric_mul(Quadric *a, const double scalar); -/* solve */ +/* Solve. */ + double BLI_quadric_evaluate(const Quadric *q, const double v[3]); bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon); diff --git a/source/blender/blenlib/BLI_scanfill.h b/source/blender/blenlib/BLI_scanfill.h index 744d30397d4..ec7fa8f27a0 100644 --- a/source/blender/blenlib/BLI_scanfill.h +++ b/source/blender/blenlib/BLI_scanfill.h @@ -91,6 +91,7 @@ typedef struct ScanFillFace { } ScanFillFace; /* scanfill.c */ + struct ScanFillVert *BLI_scanfill_vert_add(ScanFillContext *sf_ctx, const float vec[3]); struct ScanFillEdge *BLI_scanfill_edge_add(ScanFillContext *sf_ctx, struct ScanFillVert *v1, diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh index 051731ab801..5945960c450 100644 --- a/source/blender/blenlib/BLI_serialize.hh +++ b/source/blender/blenlib/BLI_serialize.hh @@ -36,7 +36,7 @@ * - DoubleValue: for double precision floating point numbers * - BooleanValue: for boolean values * - ArrayValue: An array of any supported value. - * - ObjectValue: A key value pair where keys are std::string. + * - DictionaryValue: A key value pair where keys are std::string. * - NullValue: for null values. * * # Basic usage @@ -92,12 +92,12 @@ enum class eValueType { Null, Boolean, Double, - Object, + Dictionary, }; class Value; class StringValue; -class ObjectValue; +class DictionaryValue; template<typename T, eValueType V> class PrimitiveValue; using IntValue = PrimitiveValue<int64_t, eValueType::Int>; using DoubleValue = PrimitiveValue<double, eValueType::Double>; @@ -122,8 +122,8 @@ using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Ar * - `NullValue`: represents nothing (null pointer or optional). * - `BooleanValue`: contains a boolean (true/false). * - `DoubleValue`: contains a double precision floating point number. - * - `ObjectValue`: represents an object (key value pairs where keys are strings and values can be - * of different types. + * - `DictionaryValue`: represents an object (key value pairs where keys are strings and values can + * be of different types. * */ class Value { @@ -174,10 +174,10 @@ class Value { const ArrayValue *as_array_value() const; /** - * Casts to an ObjectValue. + * Casts to an DictionaryValue. * Will return nullptr when it is a different type. */ - const ObjectValue *as_object_value() const; + const DictionaryValue *as_dictionary_value() const; }; /** @@ -228,7 +228,7 @@ class StringValue : public Value { /** * Template for arrays and objects. * - * Both ArrayValue and ObjectValue store their values in an array. + * Both ArrayValue and DictionaryValue store their values in an array. */ template< /** The container type where the elements are stored in. */ @@ -264,18 +264,19 @@ class ContainerValue : public Value { }; /** - * Internal storage type for ObjectValue. + * Internal storage type for DictionaryValue. * * The elements are stored as an key value pair. The value is a shared pointer so it can be shared - * when using `ObjectValue::create_lookup`. + * when using `DictionaryValue::create_lookup`. */ -using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>; +using DictionaryElementType = std::pair<std::string, std::shared_ptr<Value>>; /** * Object is a key-value container where the key must be a std::string. * Internally it is stored in a blender::Vector to ensure the order of keys. */ -class ObjectValue : public ContainerValue<Vector<ObjectElementType>, eValueType::Object> { +class DictionaryValue + : public ContainerValue<Vector<DictionaryElementType>, eValueType::Dictionary> { public: using LookupValue = std::shared_ptr<Value>; using Lookup = Map<std::string, LookupValue>; diff --git a/source/blender/blenlib/BLI_session_uuid.h b/source/blender/blenlib/BLI_session_uuid.h index 887044e9b54..29e291add5a 100644 --- a/source/blender/blenlib/BLI_session_uuid.h +++ b/source/blender/blenlib/BLI_session_uuid.h @@ -33,18 +33,19 @@ extern "C" { #include "DNA_session_uuid_types.h" -/* Generate new UUID which is unique throughout the Blender session. */ +/** Generate new UUID which is unique throughout the Blender session. */ SessionUUID BLI_session_uuid_generate(void); -/* Check whether the UUID is properly generated. */ +/** Check whether the UUID is properly generated. */ bool BLI_session_uuid_is_generated(const SessionUUID *uuid); -/* Check whether two UUIDs are identical. */ +/** Check whether two UUIDs are identical. */ bool BLI_session_uuid_is_equal(const SessionUUID *lhs, const SessionUUID *rhs); uint64_t BLI_session_uuid_hash_uint64(const SessionUUID *uuid); /* Utility functions to make it possible to create GHash/GSet with UUID as a key. */ + uint BLI_session_uuid_ghash_hash(const void *uuid_v); bool BLI_session_uuid_ghash_compare(const void *lhs_v, const void *rhs_v); diff --git a/source/blender/blenlib/BLI_sort.h b/source/blender/blenlib/BLI_sort.h index 969816086e2..31a052eb79d 100644 --- a/source/blender/blenlib/BLI_sort.h +++ b/source/blender/blenlib/BLI_sort.h @@ -30,7 +30,7 @@ # define BLI_qsort_r qsort_r #endif -/* Quick sort re-entrant */ +/** Quick sort (re-entrant). */ typedef int (*BLI_sort_cmp_t)(const void *a, const void *b, void *ctx); void BLI_qsort_r(void *a, size_t n, size_t es, BLI_sort_cmp_t cmp, void *thunk) diff --git a/source/blender/blenlib/BLI_span.hh b/source/blender/blenlib/BLI_span.hh index 5b7981e0302..995dc70a84d 100644 --- a/source/blender/blenlib/BLI_span.hh +++ b/source/blender/blenlib/BLI_span.hh @@ -599,6 +599,11 @@ template<typename T> class MutableSpan { return MutableSpan(data_ + start, new_size); } + constexpr MutableSpan slice(IndexRange range) const + { + return this->slice(range.start(), range.size()); + } + /** * Returns a new MutableSpan with n elements removed from the beginning. This invokes * undefined behavior when n is negative. diff --git a/source/blender/blenlib/BLI_sys_types.h b/source/blender/blenlib/BLI_sys_types.h index 2740e3740f2..95327ff33b8 100644 --- a/source/blender/blenlib/BLI_sys_types.h +++ b/source/blender/blenlib/BLI_sys_types.h @@ -72,8 +72,8 @@ typedef uint64_t u_int64_t; #include <stddef.h> /* size_t define */ #ifndef __cplusplus +/* The <uchar.h> standard header is missing on some systems. */ # if defined(__APPLE__) || defined(__NetBSD__) -/* The <uchar.h> standard header is missing on macOS. */ typedef unsigned int char32_t; # else # include <uchar.h> diff --git a/source/blender/blenlib/BLI_system.h b/source/blender/blenlib/BLI_system.h index 0d5b2e6e2df..2e5e07d8407 100644 --- a/source/blender/blenlib/BLI_system.h +++ b/source/blender/blenlib/BLI_system.h @@ -30,7 +30,7 @@ int BLI_cpu_support_sse2(void); int BLI_cpu_support_sse41(void); void BLI_system_backtrace(FILE *fp); -/* Get CPU brand, result is to be MEM_freeN()-ed. */ +/** Get CPU brand, result is to be MEM_freeN()-ed. */ char *BLI_cpu_brand_string(void); /** @@ -45,15 +45,19 @@ char *BLI_cpu_brand_string(void); */ void BLI_hostname_get(char *buffer, size_t bufsize); -/* Get maximum addressable memory in megabytes. */ +/** Get maximum addressable memory in megabytes. */ size_t BLI_system_memory_max_in_megabytes(void); +/** Get maximum addressable memory in megabytes (clamped to #INT_MAX). */ int BLI_system_memory_max_in_megabytes_int(void); /* For `getpid`. */ #ifdef WIN32 # define BLI_SYSTEM_PID_H <process.h> -/* void* since we really do not want to drag Windows.h in to get the proper typedef. */ +/** + * \note Use `void *` for `exception` since we really do not want to drag Windows.h + * in to get the proper `typedef`. + */ void BLI_windows_handle_exception(void *exception); #else diff --git a/source/blender/blenlib/BLI_task.h b/source/blender/blenlib/BLI_task.h index a67de2e2910..616237bc261 100644 --- a/source/blender/blenlib/BLI_task.h +++ b/source/blender/blenlib/BLI_task.h @@ -303,7 +303,7 @@ void BLI_task_parallel_mempool(struct BLI_mempool *mempool, TaskParallelMempoolFunc func, const TaskParallelSettings *settings); -/* TODO(sergey): Think of a better place for this. */ +/** TODO(sergey): Think of a better place for this. */ BLI_INLINE void BLI_parallel_range_settings_defaults(TaskParallelSettings *settings) { memset(settings, 0, sizeof(*settings)); diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index 6e60430ea38..7bae16f25ef 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -31,7 +31,7 @@ extern "C" { #endif -/* for tables, button in UI, etc */ +/** For tables, button in UI, etc. */ #define BLENDER_MAX_THREADS 1024 struct ListBase; diff --git a/source/blender/blenlib/BLI_timer.h b/source/blender/blenlib/BLI_timer.h index c219b5502f3..b1cc8d5514f 100644 --- a/source/blender/blenlib/BLI_timer.h +++ b/source/blender/blenlib/BLI_timer.h @@ -29,8 +29,11 @@ extern "C" { #endif -/* ret < 0: the timer will be removed. - * ret >= 0: the timer will be called again in ret seconds */ +/** + * \return A value of: + * - < 0: the timer will be removed. + * - >= 0: the timer will be called again in this number of seconds. + */ typedef double (*BLI_timer_func)(uintptr_t uuid, void *user_data); typedef void (*BLI_timer_data_free)(uintptr_t uuid, void *user_data); @@ -45,10 +48,10 @@ void BLI_timer_register(uintptr_t uuid, bool BLI_timer_is_registered(uintptr_t uuid); -/* Returns False when the timer does not exist (anymore). */ +/** Returns False when the timer does not exist (anymore). */ bool BLI_timer_unregister(uintptr_t uuid); -/* Execute all registered functions that are due. */ +/** Execute all registered functions that are due. */ void BLI_timer_execute(void); void BLI_timer_free(void); diff --git a/source/blender/blenlib/BLI_vector.hh b/source/blender/blenlib/BLI_vector.hh index d2b94a6d8ef..4ac48f259cf 100644 --- a/source/blender/blenlib/BLI_vector.hh +++ b/source/blender/blenlib/BLI_vector.hh @@ -637,7 +637,7 @@ class Vector { * Insert values at the beginning of the vector. The has to move all the other elements, so it * has a linear running time. */ - void prepend(const T &&value) + void prepend(const T &value) { this->insert(0, value); } diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 5103ac4b668..86ac95e2c77 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -44,7 +44,7 @@ namespace blender { -/* Forward declarations for generic virtual arrays. */ +/** Forward declarations for generic virtual arrays. */ namespace fn { class GVArray; class GVMutableArray; @@ -194,7 +194,7 @@ template<typename T> class VArrayImpl { } }; -/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ +/** Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ template<typename T> class VMutableArrayImpl : public VArrayImpl<T> { public: using VArrayImpl<T>::VArrayImpl; @@ -477,9 +477,9 @@ template<typename T> struct VArrayAnyExtraInfo { template<typename StorageT> static VArrayAnyExtraInfo get() { /* These are the only allowed types in the #Any. */ - static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> || - std::is_same_v<StorageT, const VArrayImpl<T> *> || - std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>); + static_assert( + std::is_base_of_v<VArrayImpl<T>, StorageT> || + is_same_any_v<StorageT, const VArrayImpl<T> *, std::shared_ptr<const VArrayImpl<T>>>); /* Depending on how the virtual array implementation is stored in the #Any, a different * #get_varray function is required. */ diff --git a/source/blender/blenlib/BLI_virtual_vector_array.hh b/source/blender/blenlib/BLI_virtual_vector_array.hh index ab5afd2d80a..7672a76d5de 100644 --- a/source/blender/blenlib/BLI_virtual_vector_array.hh +++ b/source/blender/blenlib/BLI_virtual_vector_array.hh @@ -29,7 +29,7 @@ namespace blender { -/* A readonly virtual array of vectors. */ +/** A read-only virtual array of vectors. */ template<typename T> class VVectorArray { protected: int64_t size_; diff --git a/source/blender/blenlib/BLI_winstuff.h b/source/blender/blenlib/BLI_winstuff.h index cbf1716602a..568734ee8a7 100644 --- a/source/blender/blenlib/BLI_winstuff.h +++ b/source/blender/blenlib/BLI_winstuff.h @@ -88,7 +88,7 @@ typedef SSIZE_T ssize_t; # endif #endif -/* Directory reading compatibility with UNIX. */ +/** Directory reading compatibility with UNIX. */ struct dirent { int d_ino; int d_off; @@ -96,7 +96,7 @@ struct dirent { char *d_name; }; -/* intentionally opaque to users */ +/** Intentionally opaque to users. */ typedef struct __dirstream DIR; DIR *opendir(const char *path); @@ -105,6 +105,7 @@ int closedir(DIR *dp); const char *dirname(char *path); /* Windows utility functions. */ + bool BLI_windows_register_blend_extension(const bool background); void BLI_windows_get_default_root_dir(char root_dir[4]); int BLI_windows_get_executable_dir(char *str); diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 29493c799b3..516d9d2fe84 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -76,6 +76,7 @@ set(SRC intern/endian_switch.c intern/expr_pylike_eval.c intern/fileops.c + intern/fileops.cc intern/filereader_file.c intern/filereader_gzip.c intern/filereader_memory.c @@ -204,6 +205,7 @@ set(SRC BLI_enumerable_thread_specific.hh BLI_expr_pylike_eval.h BLI_fileops.h + BLI_fileops.hh BLI_fileops_types.h BLI_filereader.h BLI_float2.hh @@ -422,6 +424,7 @@ if(WITH_GTESTS) tests/BLI_edgehash_test.cc tests/BLI_expr_pylike_eval_test.cc tests/BLI_function_ref_test.cc + tests/BLI_fileops_test.cc tests/BLI_ghash_test.cc tests/BLI_hash_mm2a_test.cc tests/BLI_heap_simple_test.cc diff --git a/source/blender/blenlib/intern/fileops.cc b/source/blender/blenlib/intern/fileops.cc new file mode 100644 index 00000000000..5ceedbd8cb5 --- /dev/null +++ b/source/blender/blenlib/intern/fileops.cc @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bli + */ + +#include "BLI_fileops.hh" + +#ifdef WIN32 +# include "utfconv.h" +#endif + +namespace blender { +fstream::fstream(const char *filepath, std::ios_base::openmode mode) +{ + this->open(filepath, mode); +} + +fstream::fstream(const std::string &filepath, std::ios_base::openmode mode) +{ + this->open(filepath, mode); +} + +void fstream::open(StringRefNull filepath, ios_base::openmode mode) +{ +#ifdef WIN32 + const char *filepath_cstr = filepath.c_str(); + UTF16_ENCODE(filepath_cstr); + std::wstring filepath_wstr(filepath_cstr_16); + std::fstream::open(filepath_wstr.c_str(), mode); + UTF16_UN_ENCODE(filepath_cstr); +#else + std::fstream::open(filepath, mode); +#endif +} + +} // namespace blender diff --git a/source/blender/blenlib/intern/listbase.c b/source/blender/blenlib/intern/listbase.c index a166c846ea7..513b08a589d 100644 --- a/source/blender/blenlib/intern/listbase.c +++ b/source/blender/blenlib/intern/listbase.c @@ -749,6 +749,26 @@ int BLI_findstringindex(const ListBase *listbase, const char *id, const int offs return -1; } +ListBase BLI_listbase_from_link(Link *some_link) +{ + ListBase list = {some_link, some_link}; + if (some_link == NULL) { + return list; + } + + /* Find the first element. */ + while (((Link *)list.first)->prev != NULL) { + list.first = ((Link *)list.first)->prev; + } + + /* Find the last element. */ + while (((Link *)list.last)->next != NULL) { + list.last = ((Link *)list.last)->next; + } + + return list; +} + void BLI_duplicatelist(ListBase *dst, const ListBase *src) { struct Link *dst_link, *src_link; diff --git a/source/blender/blenlib/intern/math_color_blend_inline.c b/source/blender/blenlib/intern/math_color_blend_inline.c index 53257cc9285..73ecb2cf798 100644 --- a/source/blender/blenlib/intern/math_color_blend_inline.c +++ b/source/blender/blenlib/intern/math_color_blend_inline.c @@ -382,7 +382,7 @@ MINLINE void blend_color_pinlight_byte(uchar dst[4], const uchar src1[4], const else { temp = min_ii(2 * src2[i], src1[i]); } - dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255); + dst[i] = (uchar)((min_ii(temp, 255) * fac + src1[i] * mfac) / 255); } } else { @@ -473,7 +473,7 @@ MINLINE void blend_color_exclusion_byte(uchar dst[4], const uchar src1[4], const int i = 3; while (i--) { - const int temp = 127 - ((2 * (src1[i] - 127) * (src2[i] - 127)) / 255); + const int temp = 127 - min_ii(((2 * (src1[i] - 127) * (src2[i] - 127)) / 255), 127); dst[i] = (uchar)((temp * fac + src1[i] * mfac) / 255); } } @@ -896,15 +896,9 @@ MINLINE void blend_color_softlight_float(float dst[4], const float src1[4], cons int i = 3; while (i--) { - float temp; - - if (src1[i] < 0.5f) { - temp = (src2[i] + 0.5f) * src1[i]; - } - else { - temp = 1.0f - ((1.0f - (src2[i] + 0.5f)) * (1.0f - src1[i])); - } - dst[i] = (temp * fac + src1[i] * mfac); + float screen = 1.0f - (1.0f - src1[i]) * (1.0f - src2[i]); + float soft_light = ((1.0f - src1[i]) * src2[i] + screen) * src1[i]; + dst[i] = src1[i] * mfac + soft_light * fac; } } else { diff --git a/source/blender/blenlib/intern/mesh_intersect.cc b/source/blender/blenlib/intern/mesh_intersect.cc index ab1db3f1fda..1f150137ba3 100644 --- a/source/blender/blenlib/intern/mesh_intersect.cc +++ b/source/blender/blenlib/intern/mesh_intersect.cc @@ -61,11 +61,11 @@ namespace blender::meshintersect { # ifdef PERFDEBUG -static void perfdata_init(void); +static void perfdata_init(); static void incperfcount(int countnum); static void bumpperfcount(int countnum, int amt); static void doperfmax(int maxnum, int val); -static void dump_perfdata(void); +static void dump_perfdata(); # endif /** For debugging, can disable threading in intersect code with this static constant. */ diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index c824def9104..958480cc616 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -245,12 +245,19 @@ void BLI_path_normalize_dir(const char *relabase, char *dir) BLI_path_slash_ensure(dir); } -bool BLI_filename_make_safe(char *fname) +bool BLI_filename_make_safe_ex(char *fname, bool allow_tokens) { - const char *invalid = - "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" - "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" - "/\\?*:|\"<>"; +#define INVALID_CHARS \ + "\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f" \ + "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f" \ + "/\\?*:|\"" +#define INVALID_TOKENS "<>" + + const char *invalid = allow_tokens ? INVALID_CHARS : INVALID_CHARS INVALID_TOKENS; + +#undef INVALID_CHARS +#undef INVALID_TOKENS + char *fn; bool changed = false; @@ -315,6 +322,11 @@ bool BLI_filename_make_safe(char *fname) return changed; } +bool BLI_filename_make_safe(char *fname) +{ + return BLI_filename_make_safe_ex(fname, false); +} + bool BLI_path_make_safe(char *path) { /* Simply apply BLI_filename_make_safe() over each component of the path. diff --git a/source/blender/blenlib/intern/serialize.cc b/source/blender/blenlib/intern/serialize.cc index 52aff140e3e..4e7203efe9b 100644 --- a/source/blender/blenlib/intern/serialize.cc +++ b/source/blender/blenlib/intern/serialize.cc @@ -44,12 +44,12 @@ const ArrayValue *Value::as_array_value() const return static_cast<const ArrayValue *>(this); } -const ObjectValue *Value::as_object_value() const +const DictionaryValue *Value::as_dictionary_value() const { - if (type_ != eValueType::Object) { + if (type_ != eValueType::Dictionary) { return nullptr; } - return static_cast<const ObjectValue *>(this); + return static_cast<const DictionaryValue *>(this); } static void convert_to_json(nlohmann::ordered_json &j, const Value &value); @@ -66,13 +66,13 @@ static void convert_to_json(nlohmann::ordered_json &j, const ArrayValue &value) } } -static void convert_to_json(nlohmann::ordered_json &j, const ObjectValue &value) +static void convert_to_json(nlohmann::ordered_json &j, const DictionaryValue &value) { - const ObjectValue::Items &attributes = value.elements(); + const DictionaryValue::Items &attributes = value.elements(); /* Create a json object to store the attributes. If this isn't done and attributes is empty it * would return use a null value, in stead of an empty object. */ j = "{}"_json; - for (const ObjectValue::Item &attribute : attributes) { + for (const DictionaryValue::Item &attribute : attributes) { nlohmann::ordered_json json_item; convert_to_json(json_item, *attribute.second); j[attribute.first] = json_item; @@ -98,8 +98,8 @@ static void convert_to_json(nlohmann::ordered_json &j, const Value &value) break; } - case eValueType::Object: { - const ObjectValue &object = *value.as_object_value(); + case eValueType::Dictionary: { + const DictionaryValue &object = *value.as_dictionary_value(); convert_to_json(j, object); break; } @@ -133,10 +133,11 @@ static std::unique_ptr<ArrayValue> convert_from_json_to_array(const nlohmann::or return array; } -static std::unique_ptr<ObjectValue> convert_from_json_to_object(const nlohmann::ordered_json &j) +static std::unique_ptr<DictionaryValue> convert_from_json_to_object( + const nlohmann::ordered_json &j) { - std::unique_ptr<ObjectValue> object = std::make_unique<ObjectValue>(); - ObjectValue::Items &elements = object->elements(); + std::unique_ptr<DictionaryValue> object = std::make_unique<DictionaryValue>(); + DictionaryValue::Items &elements = object->elements(); for (auto element : j.items()) { std::string key = element.key(); nlohmann::ordered_json element_json = element.value(); diff --git a/source/blender/blenlib/intern/string_cursor_utf8.c b/source/blender/blenlib/intern/string_cursor_utf8.c index eb49572f06c..5e2a0b85814 100644 --- a/source/blender/blenlib/intern/string_cursor_utf8.c +++ b/source/blender/blenlib/intern/string_cursor_utf8.c @@ -199,7 +199,7 @@ void BLI_str_cursor_step_utf8(const char *str, const int pos_prev = *pos; if (BLI_str_cursor_step_prev_utf8(str, maxlen, pos)) { if ((jump != STRCUR_JUMP_ALL) && - (delim_type != cursor_delim_type_utf8(str, maxlen, (size_t)*pos))) { + (delim_type != cursor_delim_type_utf8(str, maxlen, *pos))) { /* left only: compensate for index/change in direction */ if ((pos_orig - (*pos)) >= 1) { *pos = pos_prev; diff --git a/source/blender/blenlib/intern/task_graph.cc b/source/blender/blenlib/intern/task_graph.cc index ff7d0ecb4c4..d84857caeea 100644 --- a/source/blender/blenlib/intern/task_graph.cc +++ b/source/blender/blenlib/intern/task_graph.cc @@ -109,7 +109,7 @@ struct TaskNode { #endif }; -TaskGraph *BLI_task_graph_create(void) +TaskGraph *BLI_task_graph_create() { return new TaskGraph(); } diff --git a/source/blender/blenlib/intern/task_scheduler.cc b/source/blender/blenlib/intern/task_scheduler.cc index 69117e9dc7e..5992e092f4d 100644 --- a/source/blender/blenlib/intern/task_scheduler.cc +++ b/source/blender/blenlib/intern/task_scheduler.cc @@ -50,8 +50,8 @@ void BLI_task_scheduler_init() if (num_threads_override > 0) { /* Override number of threads. This settings is used within the lifetime * of tbb::global_control, so we allocate it on the heap. */ - task_scheduler_global_control = OBJECT_GUARDED_NEW( - tbb::global_control, tbb::global_control::max_allowed_parallelism, num_threads_override); + task_scheduler_global_control = MEM_new<tbb::global_control>( + __func__, tbb::global_control::max_allowed_parallelism, num_threads_override); task_scheduler_num_threads = num_threads_override; } else { @@ -69,7 +69,7 @@ void BLI_task_scheduler_init() void BLI_task_scheduler_exit() { #ifdef WITH_TBB_GLOBAL_CONTROL - OBJECT_GUARDED_DELETE(task_scheduler_global_control, tbb::global_control); + MEM_delete(task_scheduler_global_control); #endif } diff --git a/source/blender/blenlib/tests/BLI_fileops_test.cc b/source/blender/blenlib/tests/BLI_fileops_test.cc new file mode 100644 index 00000000000..e2a792647dc --- /dev/null +++ b/source/blender/blenlib/tests/BLI_fileops_test.cc @@ -0,0 +1,40 @@ +/* Apache License, Version 2.0 */ + +#include "BLI_fileops.hh" + +#include "testing/testing.h" + +namespace blender::tests { + +TEST(fileops, fstream_open_string_filename) +{ + const std::string test_files_dir = blender::tests::flags_test_asset_dir(); + if (test_files_dir.empty()) { + FAIL(); + } + + const std::string filepath = test_files_dir + "/asset_library/новый/blender_assets.cats.txt"; + fstream in(filepath, std::ios_base::in); + ASSERT_TRUE(in.is_open()) << "could not open " << filepath; + in.close(); /* This should not crash. */ + + /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */ +} + +TEST(fileops, fstream_open_charptr_filename) +{ + const std::string test_files_dir = blender::tests::flags_test_asset_dir(); + if (test_files_dir.empty()) { + FAIL(); + } + + const std::string filepath_str = test_files_dir + "/asset_library/новый/blender_assets.cats.txt"; + const char *filepath = filepath_str.c_str(); + fstream in(filepath, std::ios_base::in); + ASSERT_TRUE(in.is_open()) << "could not open " << filepath; + in.close(); /* This should not crash. */ + + /* Reading the file not tested here. That's deferred to `std::fstream` anyway. */ +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_listbase_test.cc b/source/blender/blenlib/tests/BLI_listbase_test.cc index d66eb214902..9e4d7c7dd36 100644 --- a/source/blender/blenlib/tests/BLI_listbase_test.cc +++ b/source/blender/blenlib/tests/BLI_listbase_test.cc @@ -154,6 +154,31 @@ TEST(listbase, FindLinkFromStringOrPointer) BLI_freelistN(&lb); } +TEST(listbase, FromLink) +{ + ListBase lb = {nullptr, nullptr}; + Link *link1 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link1")); + Link *link2 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link2")); + Link *link3 = static_cast<Link *>(MEM_callocN(sizeof(Link), "link3")); + + /* NULL safety. */ + EXPECT_EQ(lb, BLI_listbase_from_link(nullptr)); + + /* One link. */ + BLI_addtail(&lb, link1); + EXPECT_EQ(lb, BLI_listbase_from_link(link1)); + + /* Two links. */ + BLI_addtail(&lb, link2); + EXPECT_EQ(lb, BLI_listbase_from_link(link2)); + + /* Three links, search from middle. */ + BLI_addtail(&lb, link3); + EXPECT_EQ(lb, BLI_listbase_from_link(link2)); + + BLI_freelistN(&lb); +} + /* -------------------------------------------------------------------- */ /* Sort utilities & test */ diff --git a/source/blender/blenlib/tests/BLI_memory_utils_test.cc b/source/blender/blenlib/tests/BLI_memory_utils_test.cc index 23415e69b04..207f310d902 100644 --- a/source/blender/blenlib/tests/BLI_memory_utils_test.cc +++ b/source/blender/blenlib/tests/BLI_memory_utils_test.cc @@ -169,4 +169,11 @@ static_assert(is_span_convertible_pointer_v<int *, const void *>); static_assert(!is_span_convertible_pointer_v<TestBaseClass *, TestChildClass *>); static_assert(!is_span_convertible_pointer_v<TestChildClass *, TestBaseClass *>); +static_assert(is_same_any_v<int, float, bool, int>); +static_assert(is_same_any_v<int, int, float>); +static_assert(is_same_any_v<int, int>); +static_assert(!is_same_any_v<int, float, bool>); +static_assert(!is_same_any_v<int, float>); +static_assert(!is_same_any_v<int>); + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_serialize_test.cc b/source/blender/blenlib/tests/BLI_serialize_test.cc index 6c55a85ca1e..120fcdc3e81 100644 --- a/source/blender/blenlib/tests/BLI_serialize_test.cc +++ b/source/blender/blenlib/tests/BLI_serialize_test.cc @@ -93,8 +93,8 @@ TEST(serialize, object_to_json) { JsonFormatter json; std::stringstream out; - ObjectValue value_object; - ObjectValue::Items &attributes = value_object.elements(); + DictionaryValue value_object; + DictionaryValue::Items &attributes = value_object.elements(); attributes.append_as(std::pair(std::string("best_number"), new IntValue(42))); json.serialize(out, value_object); diff --git a/source/blender/blenlib/tests/BLI_task_test.cc b/source/blender/blenlib/tests/BLI_task_test.cc index dd4441517a9..3bb6f6f753c 100644 --- a/source/blender/blenlib/tests/BLI_task_test.cc +++ b/source/blender/blenlib/tests/BLI_task_test.cc @@ -154,7 +154,7 @@ static void task_mempool_iter_tls_func(void *UNUSED(userdata), EXPECT_TRUE(data != nullptr); if (task_data->accumulate_items == nullptr) { - task_data->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); + task_data->accumulate_items = MEM_cnew<ListBase>(__func__); } /* Flip to prove this has been touched. */ @@ -172,7 +172,7 @@ static void task_mempool_iter_tls_reduce(const void *__restrict UNUSED(userdata) if (data_chunk->accumulate_items != nullptr) { if (join_chunk->accumulate_items == nullptr) { - join_chunk->accumulate_items = (ListBase *)MEM_callocN(sizeof(ListBase), __func__); + join_chunk->accumulate_items = MEM_cnew<ListBase>(__func__); } BLI_movelisttolist(join_chunk->accumulate_items, data_chunk->accumulate_items); } diff --git a/source/blender/blenlib/tests/BLI_vector_test.cc b/source/blender/blenlib/tests/BLI_vector_test.cc index e8636168308..e9393a2b1e5 100644 --- a/source/blender/blenlib/tests/BLI_vector_test.cc +++ b/source/blender/blenlib/tests/BLI_vector_test.cc @@ -708,6 +708,17 @@ TEST(vector, Prepend) EXPECT_EQ_ARRAY(vec.data(), Span({7, 8, 1, 2, 3}).data(), 5); } +TEST(vector, PrependString) +{ + std::string s = "test"; + Vector<std::string> vec; + vec.prepend(s); + vec.prepend(std::move(s)); + EXPECT_EQ(vec.size(), 2); + EXPECT_EQ(vec[0], "test"); + EXPECT_EQ(vec[1], "test"); +} + TEST(vector, ReverseIterator) { Vector<int> vec = {4, 5, 6, 7}; diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 05f74bfa834..245514d4977 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../blentranslation ../depsgraph ../draw + ../editors/include ../imbuf ../makesdna ../makesrna diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 54e673b51eb..202a2a95a7c 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -70,6 +70,7 @@ #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_multires.h" +#include "BKE_node_tree_update.h" #include "BKE_particle.h" #include "BKE_pointcache.h" #include "BKE_screen.h" @@ -579,7 +580,6 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup, gsock->type = type; gsock->next = gsock->prev = NULL; - gsock->new_sock = NULL; gsock->link = NULL; /* assign new unique index */ gsock->own_index = ngroup->cur_index++; @@ -590,7 +590,7 @@ static bNodeSocket *do_versions_node_group_add_socket_2_56_2(bNodeTree *ngroup, BLI_addtail(in_out == SOCK_IN ? &ngroup->inputs : &ngroup->outputs, gsock); - ngroup->update |= (in_out == SOCK_IN ? NTREE_UPDATE_GROUP_IN : NTREE_UPDATE_GROUP_OUT); + BKE_ntree_update_tag_interface(ngroup); return gsock; } @@ -2019,7 +2019,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) link->fromsock = gsock; link->tonode = node; link->tosock = sock; - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_added(ntree, link); sock->link = link; } @@ -2042,7 +2042,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) link->fromsock = sock; link->tonode = NULL; link->tosock = gsock; - ntree->update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_added(ntree, link); gsock->link = link; } @@ -2282,7 +2282,7 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *bmain) do_versions_socket_default_value_259(sock); } - ntree->update |= NTREE_UPDATE; + BKE_ntree_update_tag_all(ntree); } FOREACH_NODETREE_END; } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 4333bdb851c..d9052c6b1f7 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -88,6 +88,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_paint.h" #include "BKE_pointcache.h" #include "BKE_report.h" @@ -896,7 +897,7 @@ static void do_versions_material_convert_legacy_blend_mode(bNodeTree *ntree, cha } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index bc3cd7a09cb..035aa293b62 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -30,6 +30,7 @@ #include "BLI_math_vector.h" #include "BLI_path_util.h" #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -57,6 +58,7 @@ #include "BKE_fcurve.h" #include "BKE_fcurve_driver.h" #include "BKE_idprop.h" +#include "BKE_image.h" #include "BKE_lib_id.h" #include "BKE_lib_override.h" #include "BKE_main.h" @@ -592,7 +594,7 @@ static bNodeTree *add_realize_node_tree(Main *bmain) nodeSetSelected(node, false); } - ntreeUpdateTree(bmain, node_tree); + version_socket_update_is_used(node_tree); return node_tree; } @@ -790,6 +792,39 @@ void do_versions_after_linking_300(Main *bmain, ReportList *UNUSED(reports)) */ { /* Keep this block, even when empty. */ + + { /* Ensure driver variable names are unique within the driver. */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + AnimData *adt = BKE_animdata_from_id(id); + if (adt == NULL) { + continue; + } + LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { + ChannelDriver *driver = fcu->driver; + /* Ensure the uniqueness front to back. Given a list of identically + * named variables, the last one gets to keep its original name. This + * matches the evaluation order, and thus shouldn't change the evaluated + * value of the driver expression. */ + LISTBASE_FOREACH (DriverVar *, dvar, &driver->variables) { + BLI_uniquename(&driver->variables, + dvar, + dvar->name, + '_', + offsetof(DriverVar, name), + sizeof(dvar->name)); + } + } + } + FOREACH_MAIN_ID_END; + } + + /* Ensure tiled image sources contain a UDIM token. */ + LISTBASE_FOREACH (Image *, ima, &bmain->images) { + if (ima->source == IMA_SRC_TILED) { + BKE_image_ensure_tile_token(ima->filepath); + } + } } } @@ -2035,7 +2070,7 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) SpaceFile *sfile = (SpaceFile *)sl; if (sfile->params) { sfile->params->flag &= ~(FILE_PARAMS_FLAG_UNUSED_1 | FILE_PARAMS_FLAG_UNUSED_2 | - FILE_PARAMS_FLAG_UNUSED_3 | FILE_PARAMS_FLAG_UNUSED_4); + FILE_PARAMS_FLAG_UNUSED_3 | FILE_PATH_TOKENS_ALLOW); } /* New default import type: Append with reuse. */ @@ -2414,7 +2449,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) data->data_type = SOCK_FLOAT; data->operation = node->custom1; strcpy(node->idname, "FunctionNodeCompare"); - node->update = NODE_UPDATE; node->storage = data; } } @@ -2432,22 +2466,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } } - - /* Add node storage for map range node. */ - FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->type == SH_NODE_MAP_RANGE) { - if (node->storage == NULL) { - NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__); - data->clamp = node->custom1; - data->data_type = CD_PROP_FLOAT; - data->interpolation_type = node->custom2; - node->storage = data; - } - } - } - } - FOREACH_NODETREE_END; } if (!MAIN_VERSION_ATLEAST(bmain, 301, 5)) { @@ -2475,5 +2493,38 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + /* Add node storage for map range node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == SH_NODE_MAP_RANGE) { + if (node->storage == NULL) { + NodeMapRange *data = MEM_callocN(sizeof(NodeMapRange), __func__); + data->clamp = node->custom1; + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = node->custom2; + node->storage = data; + } + } + } + } + FOREACH_NODETREE_END; + + /* Update spreadsheet data set region type. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_SPREADSHEET) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_CHANNELS) { + region->regiontype = RGN_TYPE_TOOLS; + } + } + } + } + } + } } -} +}
\ No newline at end of file diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index 3deaaa040d6..752157bffde 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -223,3 +223,23 @@ void version_node_socket_index_animdata(Main *bmain, FOREACH_NODETREE_END; } } + +/** + * The versioning code generally expects `SOCK_IN_USE` to be set correctly. This function updates + * the flag on all sockets after changes to the node tree. + */ +void version_socket_update_is_used(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + socket->flag &= ~SOCK_IN_USE; + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + socket->flag &= ~SOCK_IN_USE; + } + } + LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { + link->fromsock->flag |= SOCK_IN_USE; + link->tosock->flag |= SOCK_IN_USE; + } +} diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index 0613484b754..dd1dd1f22f2 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -100,6 +100,8 @@ struct bNodeSocket *version_node_add_socket_if_not_exist(struct bNodeTree *ntree const char *identifier, const char *name); +void version_socket_update_is_used(bNodeTree *ntree); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_cycles.c b/source/blender/blenloader/intern/versioning_cycles.c index afe2e1067ae..f1a2e678b2e 100644 --- a/source/blender/blenloader/intern/versioning_cycles.c +++ b/source/blender/blenloader/intern/versioning_cycles.c @@ -48,6 +48,7 @@ #include "BLO_readfile.h" #include "readfile.h" +#include "versioning_common.h" static bool socket_is_used(bNodeSocket *sock) { @@ -170,7 +171,7 @@ static void displacement_node_insert(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -243,7 +244,7 @@ static void square_roughness_node_insert(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -318,7 +319,7 @@ static void ambient_occlusion_node_relink(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -466,7 +467,7 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -528,7 +529,7 @@ static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -566,7 +567,7 @@ static void update_vector_math_node_dot_product_operator(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -631,7 +632,7 @@ static void update_vector_math_node_cross_product_operator(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -683,7 +684,7 @@ static void update_vector_math_node_normalize_operator(bNodeTree *ntree) } } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -785,7 +786,7 @@ static void update_vector_math_node_average_operator(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -974,7 +975,7 @@ static void update_mapping_node_inputs_and_properties(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -1149,7 +1150,7 @@ static void update_voronoi_node_crackle(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -1191,7 +1192,7 @@ static void update_voronoi_node_coloring(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -1234,7 +1235,7 @@ static void update_voronoi_node_square_distance(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } @@ -1279,7 +1280,7 @@ static void update_noise_and_wave_distortion(bNodeTree *ntree) } if (need_update) { - ntreeUpdateTree(NULL, ntree); + version_socket_update_is_used(ntree); } } diff --git a/source/blender/blenloader/intern/versioning_defaults.c b/source/blender/blenloader/intern/versioning_defaults.c index a5c44ea711b..234951eac9a 100644 --- a/source/blender/blenloader/intern/versioning_defaults.c +++ b/source/blender/blenloader/intern/versioning_defaults.c @@ -61,6 +61,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_paint.h" #include "BKE_screen.h" #include "BKE_workspace.h" @@ -583,11 +584,11 @@ void BLO_update_defaults_startup_blend(Main *bmain, const char *app_template) bNodeSocketValueFloat *roughness_data = roughness_socket->default_value; roughness_data->value = 0.4f; node->custom2 = SHD_SUBSURFACE_RANDOM_WALK; - nodeUpdate(ma->nodetree, node); + BKE_ntree_update_tag_node_property(ma->nodetree, node); } else if (node->type == SH_NODE_SUBSURFACE_SCATTERING) { node->custom1 = SHD_SUBSURFACE_RANDOM_WALK; - nodeUpdate(ma->nodetree, node); + BKE_ntree_update_tag_node_property(ma->nodetree, node); } } } diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index a4a5ced070d..7a8afbcb227 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -21,14 +21,17 @@ #include "BKE_appdir.h" #include "BKE_blender.h" +#include "BKE_callbacks.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_idtype.h" #include "BKE_image.h" #include "BKE_main.h" +#include "BKE_mball_tessellate.h" #include "BKE_modifier.h" #include "BKE_node.h" #include "BKE_scene.h" +#include "BKE_vfont.h" #include "BLI_path_util.h" #include "BLI_threads.h" @@ -43,6 +46,8 @@ #include "IMB_imbuf.h" +#include "ED_datafiles.h" + #include "RNA_define.h" #include "WM_api.h" @@ -71,6 +76,8 @@ void BlendfileLoadingBaseTest::SetUpTestCase() DEG_register_node_types(); RNA_init(); BKE_node_system_init(); + BKE_callback_global_init(); + BKE_vfont_builtin_register(datatoc_bfont_pfb, datatoc_bfont_pfb_size); G.background = true; G.factory_startup = true; @@ -109,6 +116,7 @@ void BlendfileLoadingBaseTest::TearDownTestCase() void BlendfileLoadingBaseTest::TearDown() { + BKE_mball_cubeTable_free(); depsgraph_free(); blendfile_free(); diff --git a/source/blender/compositor/intern/COM_Debug.cc b/source/blender/compositor/intern/COM_Debug.cc index 50a69e55b2b..8525e2fde50 100644 --- a/source/blender/compositor/intern/COM_Debug.cc +++ b/source/blender/compositor/intern/COM_Debug.cc @@ -431,8 +431,9 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name) if (!COM_EXPORT_GRAPHVIZ) { return; } - char str[1000000]; - if (graphviz_system(system, str, sizeof(str) - 1)) { + const int max_textlength = 1000000; + char *str = (char *)MEM_mallocN(max_textlength, __func__); + if (graphviz_system(system, str, max_textlength - 1)) { char basename[FILE_MAX]; char filename[FILE_MAX]; @@ -451,6 +452,7 @@ void DebugInfo::graphviz(const ExecutionSystem *system, StringRefNull name) fputs(str, fp); fclose(fp); } + MEM_freeN(str); } static std::string get_operations_export_dir() diff --git a/source/blender/compositor/intern/COM_compositor.cc b/source/blender/compositor/intern/COM_compositor.cc index be70ae792cb..5c9b34c4772 100644 --- a/source/blender/compositor/intern/COM_compositor.cc +++ b/source/blender/compositor/intern/COM_compositor.cc @@ -51,7 +51,7 @@ static void compositor_init_node_previews(const RenderData *render_data, bNodeTr preview_width = (int)(blender::compositor::COM_PREVIEW_SIZE / aspect); preview_height = blender::compositor::COM_PREVIEW_SIZE; } - BKE_node_preview_init_tree(node_tree, preview_width, preview_height, false); + BKE_node_preview_init_tree(node_tree, preview_width, preview_height); } static void compositor_reset_node_tree_status(bNodeTree *node_tree) diff --git a/source/blender/compositor/operations/COM_CropOperation.cc b/source/blender/compositor/operations/COM_CropOperation.cc index 5d78ed9d41a..2385a0b54ba 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cc +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -42,22 +42,22 @@ void CropBaseOperation::update_area() local_settings.y1 = height * local_settings.fac_y1; local_settings.y2 = height * local_settings.fac_y2; } - if (width <= local_settings.x1 + 1) { - local_settings.x1 = width - 1; + if (width < local_settings.x1) { + local_settings.x1 = width; } - if (height <= local_settings.y1 + 1) { - local_settings.y1 = height - 1; + if (height < local_settings.y1) { + local_settings.y1 = height; } - if (width <= local_settings.x2 + 1) { - local_settings.x2 = width - 1; + if (width < local_settings.x2) { + local_settings.x2 = width; } - if (height <= local_settings.y2 + 1) { - local_settings.y2 = height - 1; + if (height < local_settings.y2) { + local_settings.y2 = height; } - xmax_ = MAX2(local_settings.x1, local_settings.x2) + 1; + xmax_ = MAX2(local_settings.x1, local_settings.x2); xmin_ = MIN2(local_settings.x1, local_settings.x2); - ymax_ = MAX2(local_settings.y1, local_settings.y2) + 1; + ymax_ = MAX2(local_settings.y1, local_settings.y2); ymin_ = MIN2(local_settings.y1, local_settings.y2); } else { @@ -98,10 +98,8 @@ void CropOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - rcti crop_area; - BLI_rcti_init(&crop_area, xmin_, xmax_, ymin_, ymax_); for (BuffersIterator<float> it = output->iterate_with(inputs, area); !it.is_end(); ++it) { - if (BLI_rcti_isect_pt(&crop_area, it.x, it.y)) { + if ((it.x < xmax_ && it.x >= xmin_) && (it.y < ymax_ && it.y >= ymin_)) { copy_v4_v4(it.out, it.in(0)); } else { @@ -166,11 +164,11 @@ void CropImageOperation::update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span<MemoryBuffer *> inputs) { - rcti op_area; - BLI_rcti_init(&op_area, 0, get_width(), 0, get_height()); const MemoryBuffer *input = inputs[0]; + const int width = get_width(); + const int height = get_height(); for (BuffersIterator<float> it = output->iterate_with({}, area); !it.is_end(); ++it) { - if (BLI_rcti_isect_pt(&op_area, it.x, it.y)) { + if (it.x >= 0 && it.x < width && it.y >= 0 && it.y < height) { input->read_elem_checked(it.x + xmin_, it.y + ymin_, it.out); } else { diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc index c34eaad87ef..aa92c5c0c2b 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cc +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc @@ -132,8 +132,7 @@ KeyingScreenOperation::TriangulationData *KeyingScreenOperation::build_voronoi_t return nullptr; } - triangulation = (TriangulationData *)MEM_callocN(sizeof(TriangulationData), - "keying screen triangulation data"); + triangulation = MEM_cnew<TriangulationData>("keying screen triangulation data"); sites = (VoronoiSite *)MEM_callocN(sizeof(VoronoiSite) * sites_total, "keyingscreen voronoi sites"); @@ -243,7 +242,7 @@ KeyingScreenOperation::TileData *KeyingScreenOperation::triangulate(const rcti * return nullptr; } - tile_data = (TileData *)MEM_callocN(sizeof(TileData), "keying screen tile data"); + tile_data = MEM_cnew<TileData>("keying screen tile data"); for (i = 0; i < triangulation->triangles_total; i++) { if (BLI_rcti_isect(rect, &triangulation->triangles_AABB[i], nullptr)) { diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h index 94cba833096..8a69dbf3312 100644 --- a/source/blender/depsgraph/DEG_depsgraph_build.h +++ b/source/blender/depsgraph/DEG_depsgraph_build.h @@ -153,9 +153,9 @@ void DEG_add_collection_geometry_customdata_mask(struct DepsNodeHandle *node_han void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle, struct Simulation *simulation, const char *description); -void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle, - struct bNodeTree *node_tree, - const char *description); +void DEG_add_node_tree_output_relation(struct DepsNodeHandle *node_handle, + struct bNodeTree *node_tree, + const char *description); void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *object, const char *bone_name, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 51582508b6f..ecbe89b1e7f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -199,9 +199,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) nullptr, OperationCode::OPERATION, "", -1); /* Pin the node so that it and its relations are preserved by the unused nodes/relations * deletion. This is mainly to make it easier to debug visibility. */ - /* NOTE: Keep un-pinned for the 3.0 release. This way we are more sure that side effects of the - * change is minimal outside of the dependency graph area. */ - // visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED; + visibility_operation->flag |= OperationFlag::DEPSOP_FLAG_PINNED; graph_->operations.append(visibility_operation); } return id_node; @@ -589,11 +587,7 @@ void DepsgraphNodeBuilder::build_id(ID *id) case ID_HA: case ID_PT: case ID_VO: - /* TODO(sergey): Get visibility from a "parent" somehow. - * - * NOTE: Similarly to above, we don't want false-positives on - * visibility. */ - build_object_data_geometry_datablock(id, false); + build_object_data_geometry_datablock(id); break; case ID_SPK: build_speaker((Speaker *)id); @@ -769,32 +763,28 @@ void DepsgraphNodeBuilder::build_object(int base_index, if (object->modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; - data.is_parent_visible = is_visible; BKE_modifiers_foreach_ID_link(object, modifier_walk, &data); } /* Grease Pencil Modifiers. */ if (object->greasepencil_modifiers.first != nullptr) { BuilderWalkUserData data; data.builder = this; - data.is_parent_visible = is_visible; BKE_gpencil_modifiers_foreach_ID_link(object, modifier_walk, &data); } /* Shader FX. */ if (object->shader_fx.first != nullptr) { BuilderWalkUserData data; data.builder = this; - data.is_parent_visible = is_visible; BKE_shaderfx_foreach_ID_link(object, modifier_walk, &data); } /* Constraints. */ if (object->constraints.first != nullptr) { BuilderWalkUserData data; data.builder = this; - data.is_parent_visible = is_visible; BKE_constraints_id_loop(&object->constraints, constraint_walk, &data); } /* Object data. */ - build_object_data(object, is_visible); + build_object_data(object); /* Parameters, used by both drivers/animation and also to inform dependency * from object's data. */ build_parameters(&object->id); @@ -897,7 +887,7 @@ void DepsgraphNodeBuilder::build_object_instance_collection(Object *object, bool is_parent_collection_visible_ = is_current_parent_collection_visible; } -void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data(Object *object) { if (object->data == nullptr) { return; @@ -914,14 +904,14 @@ void DepsgraphNodeBuilder::build_object_data(Object *object, bool is_object_visi case OB_HAIR: case OB_POINTCLOUD: case OB_VOLUME: - build_object_data_geometry(object, is_object_visible); + build_object_data_geometry(object); break; case OB_ARMATURE: if (ID_IS_LINKED(object) && object->proxy_from != nullptr) { - build_proxy_rig(object, is_object_visible); + build_proxy_rig(object); } else { - build_rig(object, is_object_visible); + build_rig(object); } break; case OB_LAMP: @@ -1121,7 +1111,14 @@ void DepsgraphNodeBuilder::build_animdata_nlastrip_targets(ListBase *strips) void DepsgraphNodeBuilder::build_animation_images(ID *id) { - if (BKE_image_user_id_has_animation(id)) { + /* GPU materials might use an animated image. However, these materials have no been built yet. We + * could scan the entire node tree recursively to check if any texture node has a video. That is + * quite expensive. For now just always add this operation node, because it is very fast. */ + /* TODO: Add a more precise check when it is cheaper to iterate over all image nodes in a node + * tree. */ + const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO); + + if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) { ID *id_cow = get_cow_id(id); add_operation_node( id, @@ -1465,7 +1462,7 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key) /* ObData Geometry Evaluation */ /* XXX: what happens if the datablock is shared! */ -void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry(Object *object) { OperationNode *op_node; Scene *scene_cow = get_cow_datablock(scene_); @@ -1487,7 +1484,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob /* Point caches. */ build_object_pointcache(object); /* Geometry. */ - build_object_data_geometry_datablock((ID *)object->data, is_object_visible); + build_object_data_geometry_datablock((ID *)object->data); build_dimensions(object); /* Batch cache. */ add_operation_node( @@ -1497,7 +1494,7 @@ void DepsgraphNodeBuilder::build_object_data_geometry(Object *object, bool is_ob [object_cow](::Depsgraph *depsgraph) { BKE_object_select_update(depsgraph, object_cow); }); } -void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool is_object_visible) +void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata) { if (built_map_.checkIsBuiltAndTag(obdata)) { return; @@ -1541,17 +1538,15 @@ void DepsgraphNodeBuilder::build_object_data_geometry_datablock(ID *obdata, bool BKE_curve_eval_geometry(depsgraph, (Curve *)obdata_cow); }); op_node->set_as_entry(); - /* Make sure objects used for bevel.taper are in the graph. - * NOTE: This objects might be not linked to the scene. */ Curve *cu = (Curve *)obdata; if (cu->bevobj != nullptr) { - build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + build_object(-1, cu->bevobj, DEG_ID_LINKED_INDIRECTLY, false); } if (cu->taperobj != nullptr) { - build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + build_object(-1, cu->taperobj, DEG_ID_LINKED_INDIRECTLY, false); } if (cu->textoncurve != nullptr) { - build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + build_object(-1, cu->textoncurve, DEG_ID_LINKED_INDIRECTLY, false); } break; } @@ -1710,8 +1705,8 @@ void DepsgraphNodeBuilder::build_nodetree(bNodeTree *ntree) build_idproperties(ntree->id.properties); /* Animation, */ build_animdata(&ntree->id); - /* Shading update. */ - add_operation_node(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + /* Output update. */ + add_operation_node(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT); /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { build_idproperties(bnode->prop); @@ -2114,10 +2109,7 @@ void DepsgraphNodeBuilder::modifier_walk(void *user_data, } switch (GS(id->name)) { case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object( - -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); break; default: data->builder->build_id(id); @@ -2137,10 +2129,7 @@ void DepsgraphNodeBuilder::constraint_walk(bConstraint * /*con*/, } switch (GS(id->name)) { case ID_OB: - /* Special case for object, so we take owner visibility into - * account. */ - data->builder->build_object( - -1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, data->is_parent_visible); + data->builder->build_object(-1, (Object *)id, DEG_ID_LINKED_INDIRECTLY, false); break; default: data->builder->build_id(id); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index 2d24dc49802..83bc33b6a4e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -186,20 +186,17 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_object_flags(int base_index, Object *object, eDepsNode_LinkedState_Type linked_state); - virtual void build_object_data(Object *object, bool is_object_visible); + virtual void build_object_data(Object *object); virtual void build_object_data_camera(Object *object); - virtual void build_object_data_geometry(Object *object, bool is_object_visible); - virtual void build_object_data_geometry_datablock(ID *obdata, bool is_object_visible); + virtual void build_object_data_geometry(Object *object); + virtual void build_object_data_geometry_datablock(ID *obdata); virtual void build_object_data_light(Object *object); virtual void build_object_data_lightprobe(Object *object); virtual void build_object_data_speaker(Object *object); virtual void build_object_transform(Object *object); virtual void build_object_constraints(Object *object); virtual void build_object_pointcache(Object *object); - virtual void build_pose_constraints(Object *object, - bPoseChannel *pchan, - int pchan_index, - bool is_object_visible); + virtual void build_pose_constraints(Object *object, bPoseChannel *pchan, int pchan_index); virtual void build_rigidbody(Scene *scene); virtual void build_particle_systems(Object *object, bool is_object_visible); virtual void build_particle_settings(ParticleSettings *part); @@ -227,8 +224,8 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { virtual void build_dimensions(Object *object); virtual void build_ik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); virtual void build_splineik_pose(Object *object, bPoseChannel *pchan, bConstraint *con); - virtual void build_rig(Object *object, bool is_object_visible); - virtual void build_proxy_rig(Object *object, bool is_object_visible); + virtual void build_rig(Object *object); + virtual void build_proxy_rig(Object *object); virtual void build_armature(bArmature *armature); virtual void build_armature_bones(ListBase *bones); virtual void build_shapekeys(Key *key); @@ -284,8 +281,6 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { struct BuilderWalkUserData { DepsgraphNodeBuilder *builder; - /* Denotes whether object the walk is invoked from is visible. */ - bool is_parent_visible; }; static void modifier_walk(void *user_data, struct Object *object, diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc index 00c78b8edce..e8dda7b8de4 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes_rig.cc @@ -58,13 +58,11 @@ namespace blender::deg { void DepsgraphNodeBuilder::build_pose_constraints(Object *object, bPoseChannel *pchan, - int pchan_index, - bool is_object_visible) + int pchan_index) { /* Pull indirect dependencies via constraints. */ BuilderWalkUserData data; data.builder = this; - data.is_parent_visible = is_object_visible; BKE_constraints_id_loop(&pchan->constraints, constraint_walk, &data); /* Create node for constraint stack. */ @@ -147,7 +145,7 @@ void DepsgraphNodeBuilder::build_splineik_pose(Object *object, } /* Pose/Armature Bones Graph */ -void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_rig(Object *object) { bArmature *armature = (bArmature *)object->data; Scene *scene_cow = get_cow_datablock(scene_); @@ -272,7 +270,7 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) } /* Build constraints. */ if (pchan->constraints.first != nullptr) { - build_pose_constraints(object, pchan, pchan_index, is_object_visible); + build_pose_constraints(object, pchan, pchan_index); } /** * IK Solvers. @@ -301,14 +299,14 @@ void DepsgraphNodeBuilder::build_rig(Object *object, bool is_object_visible) } /* Custom shape. */ if (pchan->custom != nullptr) { - /* TODO(sergey): Use own visibility. */ - build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + /* NOTE: The relation builder will ensure visibility of the custom shape object. */ + build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false); } pchan_index++; } } -void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visible) +void DepsgraphNodeBuilder::build_proxy_rig(Object *object) { bArmature *armature = (bArmature *)object->data; OperationNode *op_node; @@ -356,7 +354,8 @@ void DepsgraphNodeBuilder::build_proxy_rig(Object *object, bool is_object_visibl /* Custom shape. */ if (pchan->custom != nullptr) { - build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, is_object_visible); + /* NOTE: The relation builder will ensure visibility of the custom shape object. */ + build_object(-1, pchan->custom, DEG_ID_LINKED_INDIRECTLY, false); } pchan_index++; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index b195b2d9e11..558ea3dd6e0 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -1466,8 +1466,11 @@ void DepsgraphRelationBuilder::build_animdata_drivers(ID *id) void DepsgraphRelationBuilder::build_animation_images(ID *id) { + /* See #DepsgraphNodeBuilder::build_animation_images. */ + const bool can_have_gpu_material = ELEM(GS(id->name), ID_MA, ID_WO); + /* TODO: can we check for existence of node for performance? */ - if (BKE_image_user_id_has_animation(id)) { + if (BKE_image_user_id_has_animation(id) || can_have_gpu_material) { OperationKey image_animation_key( id, NodeType::IMAGE_ANIMATION, OperationCode::IMAGE_ANIMATION); TimeSourceKey time_src_key; @@ -1770,7 +1773,7 @@ void DepsgraphRelationBuilder::build_world(World *world) if (world->nodetree != nullptr) { build_nodetree(world->nodetree); OperationKey ntree_key( - &world->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + &world->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT); add_relation(ntree_key, world_key, "World's NTree"); build_nested_nodetree(&world->id, world->nodetree); } @@ -2381,17 +2384,17 @@ void DepsgraphRelationBuilder::build_light(Light *lamp) ComponentKey lamp_parameters_key(&lamp->id, NodeType::PARAMETERS); + /* For allowing drivers on lamp properties. */ + ComponentKey shading_key(&lamp->id, NodeType::SHADING); + add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters"); + /* light's nodetree */ if (lamp->nodetree != nullptr) { build_nodetree(lamp->nodetree); - ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::SHADING); - add_relation(nodetree_key, lamp_parameters_key, "NTree->Light Parameters"); + ComponentKey nodetree_key(&lamp->nodetree->id, NodeType::NTREE_OUTPUT); + add_relation(nodetree_key, shading_key, "NTree->Light Parameters"); build_nested_nodetree(&lamp->id, lamp->nodetree); } - - /* For allowing drivers on lamp properties. */ - ComponentKey shading_key(&lamp->id, NodeType::SHADING); - add_relation(lamp_parameters_key, shading_key, "Light Shading Parameters"); } void DepsgraphRelationBuilder::build_nodetree_socket(bNodeSocket *socket) @@ -2441,7 +2444,7 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) build_idproperties(ntree->id.properties); build_animdata(&ntree->id); build_parameters(&ntree->id); - ComponentKey shading_key(&ntree->id, NodeType::SHADING); + OperationKey ntree_output_key(&ntree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT); /* nodetree's nodes... */ LISTBASE_FOREACH (bNode *, bnode, &ntree->nodes) { build_idproperties(bnode->prop); @@ -2460,25 +2463,25 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) if (id_type == ID_MA) { build_material((Material *)bnode->id); ComponentKey material_key(id, NodeType::SHADING); - add_relation(material_key, shading_key, "Material -> Node"); + add_relation(material_key, ntree_output_key, "Material -> Node"); } else if (id_type == ID_TE) { build_texture((Tex *)bnode->id); ComponentKey texture_key(id, NodeType::GENERIC_DATABLOCK); - add_relation(texture_key, shading_key, "Texture -> Node"); + add_relation(texture_key, ntree_output_key, "Texture -> Node"); } else if (id_type == ID_IM) { build_image((Image *)bnode->id); ComponentKey image_key(id, NodeType::GENERIC_DATABLOCK); - add_relation(image_key, shading_key, "Image -> Node"); + add_relation(image_key, ntree_output_key, "Image -> Node"); } else if (id_type == ID_OB) { build_object((Object *)id); ComponentKey object_transform_key(id, NodeType::TRANSFORM); - add_relation(object_transform_key, shading_key, "Object Transform -> Node"); + add_relation(object_transform_key, ntree_output_key, "Object Transform -> Node"); if (object_have_geometry_component(reinterpret_cast<Object *>(id))) { ComponentKey object_geometry_key(id, NodeType::GEOMETRY); - add_relation(object_geometry_key, shading_key, "Object Geometry -> Node"); + add_relation(object_geometry_key, ntree_output_key, "Object Geometry -> Node"); } } else if (id_type == ID_SCE) { @@ -2498,23 +2501,28 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) else if (id_type == ID_MSK) { build_mask((Mask *)id); OperationKey mask_key(id, NodeType::PARAMETERS, OperationCode::MASK_EVAL); - add_relation(mask_key, shading_key, "Mask -> Node"); + add_relation(mask_key, ntree_output_key, "Mask -> Node"); } else if (id_type == ID_MC) { build_movieclip((MovieClip *)id); OperationKey clip_key(id, NodeType::PARAMETERS, OperationCode::MOVIECLIP_EVAL); - add_relation(clip_key, shading_key, "Clip -> Node"); + add_relation(clip_key, ntree_output_key, "Clip -> Node"); } else if (id_type == ID_VF) { build_vfont((VFont *)id); ComponentKey vfont_key(id, NodeType::GENERIC_DATABLOCK); - add_relation(vfont_key, shading_key, "VFont -> Node"); + add_relation(vfont_key, ntree_output_key, "VFont -> Node"); } else if (ELEM(bnode->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { bNodeTree *group_ntree = (bNodeTree *)id; build_nodetree(group_ntree); - ComponentKey group_shading_key(&group_ntree->id, NodeType::SHADING); - add_relation(group_shading_key, shading_key, "Group Node"); + ComponentKey group_output_key(&group_ntree->id, NodeType::NTREE_OUTPUT); + /* The output of the current tree does not necessarily change when the output of the group + * changed. The parent node group is currently explicitly tagged for update in + * #ED_node_tree_propagate_change. In the future we could move this relation to the + * depsgraph, but then the depsgraph has to do some more static analysis of the node tree to + * see which groups the output actually depends on. */ + add_relation(group_output_key, ntree_output_key, "Group Node", RELATION_FLAG_NO_FLUSH); } else { BLI_assert_msg(0, "Unknown ID type used for node"); @@ -2528,14 +2536,10 @@ void DepsgraphRelationBuilder::build_nodetree(bNodeTree *ntree) build_idproperties(socket->prop); } - OperationKey shading_update_key(&ntree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); - if (check_id_has_anim_component(&ntree->id)) { ComponentKey animation_key(&ntree->id, NodeType::ANIMATION); - add_relation(animation_key, shading_update_key, "NTree Shading Parameters"); + add_relation(animation_key, ntree_output_key, "NTree Shading Parameters"); } - ComponentKey parameters_key(&ntree->id, NodeType::PARAMETERS); - add_relation(parameters_key, shading_update_key, "NTree Shading Parameters"); } /* Recursively build graph for material */ @@ -2558,7 +2562,7 @@ void DepsgraphRelationBuilder::build_material(Material *material) if (material->nodetree != nullptr) { build_nodetree(material->nodetree); OperationKey ntree_key( - &material->nodetree->id, NodeType::SHADING, OperationCode::MATERIAL_UPDATE); + &material->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT); add_relation(ntree_key, material_key, "Material's NTree"); build_nested_nodetree(&material->id, material->nodetree); } @@ -2587,8 +2591,13 @@ void DepsgraphRelationBuilder::build_texture(Tex *texture) build_parameters(&texture->id); /* texture's nodetree */ - build_nodetree(texture->nodetree); - build_nested_nodetree(&texture->id, texture->nodetree); + if (texture->nodetree) { + build_nodetree(texture->nodetree); + OperationKey ntree_key( + &texture->nodetree->id, NodeType::NTREE_OUTPUT, OperationCode::NTREE_OUTPUT); + add_relation(ntree_key, texture_key, "Texture's NTree"); + build_nested_nodetree(&texture->id, texture->nodetree); + } /* Special cases for different IDs which texture uses. */ if (texture->type == TEX_IMAGE) { @@ -2875,12 +2884,16 @@ void DepsgraphRelationBuilder::build_copy_on_write_relations() * * This is similar to what happens in ntree_hack_remap_pointers(). */ -void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id) +void DepsgraphRelationBuilder::build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes) { + int relation_flag = 0; + if (!flush_cow_changes) { + relation_flag |= RELATION_FLAG_NO_FLUSH; + } OperationKey owner_copy_on_write_key( owner, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); OperationKey id_copy_on_write_key(id, NodeType::COPY_ON_WRITE, OperationCode::COPY_ON_WRITE); - add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order"); + add_relation(id_copy_on_write_key, owner_copy_on_write_key, "Eval Order", relation_flag); } void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree) @@ -2888,7 +2901,10 @@ void DepsgraphRelationBuilder::build_nested_nodetree(ID *owner, bNodeTree *ntree if (ntree == nullptr) { return; } - build_nested_datablock(owner, &ntree->id); + /* Don't flush cow changes, because the node tree may change in ways that do not affect the + * owner data block (e.g. when a node is deleted that is not connected to any output). + * Data blocks owning node trees should add a relation to the `NTREE_OUTPUT` node instead. */ + build_nested_datablock(owner, &ntree->id, false); } void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key) @@ -2896,7 +2912,7 @@ void DepsgraphRelationBuilder::build_nested_shapekey(ID *owner, Key *key) if (key == nullptr) { return; } - build_nested_datablock(owner, &key->id); + build_nested_datablock(owner, &key->id, true); } void DepsgraphRelationBuilder::build_copy_on_write_relations(IDNode *id_node) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 09003de3ce4..787e3799029 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -299,7 +299,7 @@ class DepsgraphRelationBuilder : public DepsgraphBuilder { virtual void build_scene_speakers(Scene *scene, ViewLayer *view_layer); virtual void build_vfont(VFont *vfont); - virtual void build_nested_datablock(ID *owner, ID *id); + virtual void build_nested_datablock(ID *owner, ID *id, bool flush_cow_changes); virtual void build_nested_nodetree(ID *owner, bNodeTree *ntree); virtual void build_nested_shapekey(ID *owner, Key *key); diff --git a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc index 40e59875832..43d24125dc2 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_rna.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_rna.cc @@ -351,7 +351,7 @@ RNANodeIdentifier RNANodeQuery::construct_node_identifier(const PointerRNA *ptr, return node_identifier; } else if (RNA_struct_is_a(ptr->type, &RNA_NodeSocket)) { - node_identifier.type = NodeType::SHADING; + node_identifier.type = NodeType::NTREE_OUTPUT; return node_identifier; } else if (RNA_struct_is_a(ptr->type, &RNA_ShaderNode)) { diff --git a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc index 7be661d9668..36120ae76d1 100644 --- a/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc +++ b/source/blender/depsgraph/intern/debug/deg_debug_relations_graphviz.cc @@ -425,6 +425,7 @@ static void deg_debug_graphviz_node(DotExportContext &ctx, case NodeType::ARMATURE: case NodeType::GENERIC_DATABLOCK: case NodeType::VISIBILITY: + case NodeType::NTREE_OUTPUT: case NodeType::SIMULATION: { ComponentNode *comp_node = (ComponentNode *)node; if (comp_node->operations.is_empty()) { diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc index db00c595383..acb8fa8fe88 100644 --- a/source/blender/depsgraph/intern/depsgraph_build.cc +++ b/source/blender/depsgraph/intern/depsgraph_build.cc @@ -148,15 +148,15 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle, deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description); } -void DEG_add_node_tree_relation(DepsNodeHandle *node_handle, - bNodeTree *node_tree, - const char *description) +void DEG_add_node_tree_output_relation(DepsNodeHandle *node_handle, + bNodeTree *node_tree, + const char *description) { - /* Using shading key, because that's the one that exists right now. Should use something else in - * the future. */ - deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING); + deg::OperationKey ntree_output_key( + &node_tree->id, deg::NodeType::NTREE_OUTPUT, deg::OperationCode::NTREE_OUTPUT); deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle); - deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description); + deg_node_handle->builder->add_node_handle_relation( + ntree_output_key, deg_node_handle, description); } void DEG_add_object_cache_relation(DepsNodeHandle *node_handle, diff --git a/source/blender/depsgraph/intern/depsgraph_query_iter.cc b/source/blender/depsgraph/intern/depsgraph_query_iter.cc index 7af3d03d478..c84adbcde00 100644 --- a/source/blender/depsgraph/intern/depsgraph_query_iter.cc +++ b/source/blender/depsgraph/intern/depsgraph_query_iter.cc @@ -334,10 +334,13 @@ static void DEG_iterator_ids_step(BLI_Iterator *iter, deg::IDNode *id_node, bool return; } if (only_updated && !(id_cow->recalc & ID_RECALC_ALL)) { - bNodeTree *ntree = ntreeFromID(id_cow); - /* Node-tree is considered part of the data-block. */ - if (!(ntree && (ntree->id.recalc & ID_RECALC_ALL))) { + bNodeTree *ntree = ntreeFromID(id_cow); + if (ntree == nullptr) { + iter->skip = true; + return; + } + if ((ntree->id.recalc & ID_RECALC_NTREE_OUTPUT) == 0) { iter->skip = true; return; } diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc index 2b0d0e6e780..4bc9e0d2d14 100644 --- a/source/blender/depsgraph/intern/depsgraph_tag.cc +++ b/source/blender/depsgraph/intern/depsgraph_tag.cc @@ -232,6 +232,10 @@ void depsgraph_tag_to_component_opcode(const ID *id, break; case ID_RECALC_TAG_FOR_UNDO: break; /* Must be ignored by depsgraph. */ + case ID_RECALC_NTREE_OUTPUT: + *component_type = NodeType::NTREE_OUTPUT; + *operation_code = OperationCode::NTREE_OUTPUT; + break; } } @@ -749,6 +753,8 @@ const char *DEG_update_tag_as_string(IDRecalcFlag flag) return "ALL"; case ID_RECALC_TAG_FOR_UNDO: return "TAG_FOR_UNDO"; + case ID_RECALC_NTREE_OUTPUT: + return "ID_RECALC_NTREE_OUTPUT"; } return nullptr; } diff --git a/source/blender/depsgraph/intern/node/deg_node.cc b/source/blender/depsgraph/intern/node/deg_node.cc index 8bc03d8b736..075bfd35ec1 100644 --- a/source/blender/depsgraph/intern/node/deg_node.cc +++ b/source/blender/depsgraph/intern/node/deg_node.cc @@ -116,6 +116,8 @@ const char *nodeTypeAsString(NodeType type) return "VISIBILITY"; case NodeType::SIMULATION: return "SIMULATION"; + case NodeType::NTREE_OUTPUT: + return "NTREE_OUTPUT"; /* Total number of meaningful node types. */ case NodeType::NUM_TYPES: @@ -174,6 +176,7 @@ eDepsSceneComponentType nodeTypeToSceneComponent(NodeType type) case NodeType::CACHE: case NodeType::PROXY: case NodeType::SIMULATION: + case NodeType::NTREE_OUTPUT: return DEG_SCENE_COMP_PARAMETERS; case NodeType::VISIBILITY: @@ -251,6 +254,7 @@ eDepsObjectComponentType nodeTypeToObjectComponent(NodeType type) case NodeType::DUPLI: case NodeType::SYNCHRONIZATION: case NodeType::SIMULATION: + case NodeType::NTREE_OUTPUT: case NodeType::UNDEFINED: case NodeType::NUM_TYPES: return DEG_OB_COMP_PARAMETERS; diff --git a/source/blender/depsgraph/intern/node/deg_node.h b/source/blender/depsgraph/intern/node/deg_node.h index 7e093ab8765..6cb5e31303f 100644 --- a/source/blender/depsgraph/intern/node/deg_node.h +++ b/source/blender/depsgraph/intern/node/deg_node.h @@ -112,11 +112,11 @@ enum class NodeType { * which simplifies common algorithms which are dealing with relations and visibility. * * The fact that the visibility operates on the ID level basically means that all components in - * NodeA will be considered as affecting directly visible when NodeB's visibility is + * the NodeA will be considered as affecting directly visible when NodeB's visibility is * affecting directly visible ID. * * This is the way to ensure objects needed for visualization without any actual data dependency - * are properly evaluated. Example of this is custom shapes for bones. */ + * properly evaluated. Example of this is custom shapes for bones. */ VISIBILITY, /* **** Evaluation-Related Outer Types (with Subdata) **** */ @@ -147,6 +147,8 @@ enum class NodeType { SYNCHRONIZATION, /* Simulation component. */ SIMULATION, + /* Node tree output component. */ + NTREE_OUTPUT, /* Total number of meaningful node types. */ NUM_TYPES, diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index b716877902c..4c430904e44 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -351,6 +351,7 @@ DEG_COMPONENT_NODE_DEFINE(Armature, ARMATURE, 0); DEG_COMPONENT_NODE_DEFINE(GenericDatablock, GENERIC_DATABLOCK, 0); DEG_COMPONENT_NODE_DEFINE(Visibility, VISIBILITY, 0); DEG_COMPONENT_NODE_DEFINE(Simulation, SIMULATION, 0); +DEG_COMPONENT_NODE_DEFINE(NTreeOutput, NTREE_OUTPUT, ID_RECALC_NTREE_OUTPUT); /** \} */ @@ -385,6 +386,7 @@ void deg_register_component_depsnodes() register_node_typeinfo(&DNTI_GENERIC_DATABLOCK); register_node_typeinfo(&DNTI_VISIBILITY); register_node_typeinfo(&DNTI_SIMULATION); + register_node_typeinfo(&DNTI_NTREE_OUTPUT); } /** \} */ diff --git a/source/blender/depsgraph/intern/node/deg_node_component.h b/source/blender/depsgraph/intern/node/deg_node_component.h index 9f108af8012..8fd28dfc497 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.h +++ b/source/blender/depsgraph/intern/node/deg_node_component.h @@ -222,6 +222,7 @@ DEG_COMPONENT_NODE_DECLARE_GENERIC(Armature); DEG_COMPONENT_NODE_DECLARE_GENERIC(GenericDatablock); DEG_COMPONENT_NODE_DECLARE_NO_COW(Visibility); DEG_COMPONENT_NODE_DECLARE_GENERIC(Simulation); +DEG_COMPONENT_NODE_DECLARE_GENERIC(NTreeOutput); /* Bone Component */ struct BoneComponentNode : public ComponentNode { diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.cc b/source/blender/depsgraph/intern/node/deg_node_operation.cc index eaae5d2d5dc..2d0d6854851 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/node/deg_node_operation.cc @@ -182,6 +182,9 @@ const char *operationCodeAsString(OperationCode opcode) return "LIGHT_UPDATE"; case OperationCode::WORLD_UPDATE: return "WORLD_UPDATE"; + /* Node Tree. */ + case OperationCode::NTREE_OUTPUT: + return "NTREE_OUTPUT"; /* Movie clip. */ case OperationCode::MOVIECLIP_EVAL: return "MOVIECLIP_EVAL"; diff --git a/source/blender/depsgraph/intern/node/deg_node_operation.h b/source/blender/depsgraph/intern/node/deg_node_operation.h index 31cbb9702ba..4abdc014946 100644 --- a/source/blender/depsgraph/intern/node/deg_node_operation.h +++ b/source/blender/depsgraph/intern/node/deg_node_operation.h @@ -177,6 +177,9 @@ enum class OperationCode { LIGHT_UPDATE, WORLD_UPDATE, + /* Node Tree. ----------------------------------------------------------- */ + NTREE_OUTPUT, + /* Batch caches. -------------------------------------------------------- */ GEOMETRY_SELECT_UPDATE, diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 30a3b8087c0..eea3adc440a 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -44,9 +44,11 @@ set(INC ../../../intern/atomic ../../../intern/glew-mx ../../../intern/guardedalloc + ../../../intern/opensubdiv # dna_type_offsets.h ${CMAKE_CURRENT_BINARY_DIR}/../makesdna/intern + ${OPENSUBDIV_INCLUDE_DIRS} ) set(SRC @@ -85,12 +87,13 @@ set(SRC intern/draw_cache_impl_curve.cc intern/draw_cache_impl_displist.c intern/draw_cache_impl_gpencil.c - intern/draw_cache_impl_hair.c + intern/draw_cache_impl_hair.cc intern/draw_cache_impl_lattice.c intern/draw_cache_impl_mesh.c intern/draw_cache_impl_metaball.c intern/draw_cache_impl_particles.c intern/draw_cache_impl_pointcloud.c + intern/draw_cache_impl_subdivision.cc intern/draw_cache_impl_volume.c intern/draw_color_management.cc intern/draw_common.c @@ -209,6 +212,7 @@ set(SRC intern/draw_manager_testing.h intern/draw_manager_text.h intern/draw_shader.h + intern/draw_subdivision.h intern/draw_texture_pool.h intern/draw_view.h intern/draw_view_data.h @@ -372,6 +376,18 @@ data_to_c_simple(intern/shaders/common_view_lib.glsl SRC) data_to_c_simple(intern/shaders/common_fxaa_lib.glsl SRC) data_to_c_simple(intern/shaders/common_smaa_lib.glsl SRC) data_to_c_simple(intern/shaders/common_fullscreen_vert.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_custom_data_interp_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_ibo_lines_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_ibo_tris_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_lib.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_normals_accumulate_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_normals_finalize_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_patch_evaluation_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_vbo_lnor_comp.glsl SRC) +data_to_c_simple(intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_frag.glsl SRC) data_to_c_simple(engines/gpencil/shaders/gpencil_vert.glsl SRC) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 98e166ac3a7..132f66ecb1e 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -191,6 +191,10 @@ void DRW_xr_drawing_end(void); /* For garbage collection */ void DRW_cache_free_old_batches(struct Main *bmain); +void DRW_cache_free_old_subdiv(void); + +/* For the OpenGL evaluators and garbage collected subdivision data. */ +void DRW_subdiv_free(void); /* Never use this. Only for closing blender. */ void DRW_opengl_context_enable_ex(bool restore); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index ccd53f6c037..589b035b8bd 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -33,6 +33,10 @@ struct Scene; struct SceneEEVEE; struct ViewLayer; +#ifdef __cplusplus +extern "C" { +#endif + /** * Light Bake. */ @@ -77,3 +81,7 @@ void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee); void EEVEE_lightcache_blend_write(struct BlendWriter *writer, struct LightCache *cache); void EEVEE_lightcache_blend_read_data(struct BlendDataReader *reader, struct LightCache *cache); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c index 315133186da..dfff45cbca5 100644 --- a/source/blender/draw/engines/gpencil/gpencil_shader_fx.c +++ b/source/blender/draw/engines/gpencil/gpencil_shader_fx.c @@ -99,6 +99,11 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it return; } + if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera == NULL) { + /* No blur outside camera view (or when DOF is disabled on the camera). */ + return; + } + DRWShadingGroup *grp; const float s = sin(fx->rotation); const float c = cos(fx->rotation); @@ -108,7 +113,7 @@ static void gpencil_vfx_blur(BlurShaderFxData *fx, Object *ob, gpIterVfxData *it DRW_view_persmat_get(NULL, persmat, false); const float w = fabsf(mul_project_m4_v3_zfac(persmat, ob->obmat[3])); - if ((fx->flag & FX_BLUR_DOF_MODE) && iter->pd->camera != NULL) { + if ((fx->flag & FX_BLUR_DOF_MODE)) { /* Compute circle of confusion size. */ float coc = (iter->pd->dof_params[0] / -w) - iter->pd->dof_params[1]; copy_v2_fl(blur_size, fabsf(coc)); diff --git a/source/blender/draw/engines/overlay/overlay_armature.c b/source/blender/draw/engines/overlay/overlay_armature.c index 2345a110134..a754e81b949 100644 --- a/source/blender/draw/engines/overlay/overlay_armature.c +++ b/source/blender/draw/engines/overlay/overlay_armature.c @@ -589,7 +589,7 @@ static void drw_shgroup_bone_custom_wire(ArmatureDrawContext *ctx, Object *custom) { /* See comments in #drw_shgroup_bone_custom_solid. */ - Mesh *mesh = BKE_object_get_evaluated_mesh(custom); + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(custom); if (mesh == NULL) { return; } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 03fb3b92277..1110658e3b2 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -923,7 +923,7 @@ GPUBatch *DRW_cache_object_surface_get(Object *ob) GPUVertBuf *DRW_cache_object_pos_vertbuf_get(Object *ob) { - Mesh *me = BKE_object_get_evaluated_mesh(ob); + Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob); short type = (me != NULL) ? OB_MESH : ob->type; switch (type) { @@ -950,7 +950,7 @@ int DRW_cache_object_material_count_get(struct Object *ob) { short type = ob->type; - Mesh *me = BKE_object_get_evaluated_mesh(ob); + Mesh *me = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (me != NULL && type != OB_POINTCLOUD) { /* Some object types can have one data type in ob->data, but will be rendered as mesh. * For point clouds this never happens. Ideally this check would happen at another level @@ -3021,7 +3021,7 @@ GPUBatch *DRW_cache_surf_surface_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_surface(mesh_eval); } @@ -3034,7 +3034,7 @@ GPUBatch *DRW_cache_surf_edge_wire_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_loose_edges(mesh_eval); } @@ -3047,7 +3047,7 @@ GPUBatch *DRW_cache_surf_face_wireframe_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_wireframes_face(mesh_eval); } @@ -3059,7 +3059,7 @@ GPUBatch *DRW_cache_surf_edge_detection_get(Object *ob, bool *r_is_manifold) { BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_edge_detection(mesh_eval, r_is_manifold); } @@ -3072,7 +3072,7 @@ GPUBatch *DRW_cache_surf_loose_edges_get(Object *ob) BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_loose_edges(mesh_eval); } @@ -3089,7 +3089,7 @@ GPUBatch **DRW_cache_surf_surface_shaded_get(Object *ob, BLI_assert(ob->type == OB_SURF); struct Curve *cu = ob->data; - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); if (mesh_eval != NULL) { return DRW_mesh_batch_cache_get_surface_shaded(mesh_eval, gpumat_array, gpumat_array_len); } @@ -3382,7 +3382,7 @@ GPUBatch *DRW_cache_cursor_get(bool crosshair_lines) void drw_batch_cache_validate(Object *ob) { - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); switch (ob->type) { case OB_MESH: DRW_mesh_batch_cache_validate((Mesh *)ob->data); @@ -3431,7 +3431,7 @@ void drw_batch_cache_generate_requested(Object *ob) DRW_object_use_hide_faces(ob)) || ((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob)))); - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); switch (ob->type) { case OB_MESH: DRW_mesh_batch_cache_create_requested( @@ -3470,7 +3470,7 @@ void drw_batch_cache_generate_requested_evaluated_mesh(Object *ob) DRW_object_use_hide_faces(ob)) || ((mode == CTX_MODE_EDIT_MESH) && DRW_object_is_in_edit_mode(ob)))); - Mesh *mesh = BKE_object_get_evaluated_mesh(ob); + Mesh *mesh = BKE_object_get_evaluated_mesh_no_subsurf(ob); DRW_mesh_batch_cache_create_requested(DST.task_graph, ob, mesh, scene, is_paint_mode, use_hide); } @@ -3481,7 +3481,7 @@ void drw_batch_cache_generate_requested_delayed(Object *ob) void DRW_batch_cache_free_old(Object *ob, int ctime) { - struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob); + struct Mesh *mesh_eval = BKE_object_get_evaluated_mesh_no_subsurf(ob); switch (ob->type) { case OB_MESH: diff --git a/source/blender/draw/intern/draw_cache_extract.h b/source/blender/draw/intern/draw_cache_extract.h index ba42cdf66e7..6de9788b434 100644 --- a/source/blender/draw/intern/draw_cache_extract.h +++ b/source/blender/draw/intern/draw_cache_extract.h @@ -22,6 +22,7 @@ #pragma once +struct DRWSubdivCache; struct TaskGraph; #include "DNA_customdata_types.h" @@ -244,6 +245,13 @@ typedef enum DRWBatchFlag { BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of bit fields"); +typedef struct MeshExtractLooseGeom { + int edge_len; + int vert_len; + int *verts; + int *edges; +} MeshExtractLooseGeom; + /** * Data that are kept around between extractions to reduce rebuilding time. * @@ -252,12 +260,7 @@ BLI_STATIC_ASSERT(MBC_BATCH_LEN < 32, "Number of batches exceeded the limit of b typedef struct MeshBufferCache { MeshBufferList buff; - struct { - int edge_len; - int vert_len; - int *verts; - int *edges; - } loose_geom; + MeshExtractLooseGeom loose_geom; struct { int *tri_first_index; @@ -283,6 +286,8 @@ typedef struct MeshBatchCache { GPUBatch **surface_per_mat; + struct DRWSubdivCache *subdiv_cache; + DRWBatchFlag batch_requested; /* DRWBatchFlag */ DRWBatchFlag batch_ready; /* DRWBatchFlag */ @@ -332,9 +337,14 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, const bool do_uvedit, const bool use_subsurf_fdots, const Scene *scene, - const ToolSettings *ts, + const struct ToolSettings *ts, const bool use_hide); +void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + struct DRWSubdivCache *subdiv_cache, + const struct ToolSettings *ts); + #ifdef __cplusplus } #endif diff --git a/source/blender/draw/intern/draw_cache_extract_mesh.cc b/source/blender/draw/intern/draw_cache_extract_mesh.cc index 485b803310c..383a3b05b67 100644 --- a/source/blender/draw/intern/draw_cache_extract_mesh.cc +++ b/source/blender/draw/intern/draw_cache_extract_mesh.cc @@ -42,6 +42,7 @@ #include "draw_cache_extract.h" #include "draw_cache_inline.h" +#include "draw_subdivision.h" #include "mesh_extractors/extract_mesh.h" @@ -783,6 +784,99 @@ static void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, /** \} */ +/* ---------------------------------------------------------------------- */ +/** \name Subdivision Extract Loop + * \{ */ + +static void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + DRWSubdivCache *subdiv_cache, + const ToolSettings *ts) +{ + /* Create an array containing all the extractors that needs to be executed. */ + ExtractorRunDatas extractors; + + MeshBufferList *mbuflist = &mbc->buff; + +#define EXTRACT_ADD_REQUESTED(type, name) \ + do { \ + if (DRW_##type##_requested(mbuflist->type.name)) { \ + const MeshExtract *extractor = &extract_##name; \ + extractors.append(extractor); \ + } \ + } while (0) + + /* The order in which extractors are added to the list matters somewhat, as some buffers are + * reused when building others. */ + EXTRACT_ADD_REQUESTED(ibo, tris); + EXTRACT_ADD_REQUESTED(vbo, pos_nor); + EXTRACT_ADD_REQUESTED(vbo, lnor); + for (int i = 0; i < GPU_MAX_ATTR; i++) { + EXTRACT_ADD_REQUESTED(vbo, attr[i]); + } + + /* We use only one extractor for face dots, as the work is done in a single compute shader. */ + if (DRW_vbo_requested(mbuflist->vbo.fdots_nor) || DRW_vbo_requested(mbuflist->vbo.fdots_pos) || + DRW_ibo_requested(mbuflist->ibo.fdots)) { + extractors.append(&extract_fdots_pos); + } + + EXTRACT_ADD_REQUESTED(ibo, lines); + EXTRACT_ADD_REQUESTED(ibo, edituv_points); + EXTRACT_ADD_REQUESTED(ibo, edituv_tris); + EXTRACT_ADD_REQUESTED(ibo, edituv_lines); + EXTRACT_ADD_REQUESTED(vbo, vert_idx); + EXTRACT_ADD_REQUESTED(vbo, edge_idx); + EXTRACT_ADD_REQUESTED(vbo, poly_idx); + EXTRACT_ADD_REQUESTED(vbo, edge_fac); + EXTRACT_ADD_REQUESTED(ibo, points); + EXTRACT_ADD_REQUESTED(vbo, edit_data); + EXTRACT_ADD_REQUESTED(vbo, edituv_data); + /* Make sure UVs are computed before edituv stuffs. */ + EXTRACT_ADD_REQUESTED(vbo, uv); + EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_area); + EXTRACT_ADD_REQUESTED(vbo, edituv_stretch_angle); + EXTRACT_ADD_REQUESTED(ibo, lines_adjacency); + EXTRACT_ADD_REQUESTED(vbo, vcol); + EXTRACT_ADD_REQUESTED(vbo, weights); + EXTRACT_ADD_REQUESTED(vbo, sculpt_data); + +#undef EXTRACT_ADD_REQUESTED + + if (extractors.is_empty()) { + return; + } + + MeshRenderData mr; + draw_subdiv_init_mesh_render_data(subdiv_cache, &mr, ts); + mesh_render_data_update_loose_geom(&mr, mbc, MR_ITER_LEDGE | MR_ITER_LVERT, MR_DATA_LOOSE_GEOM); + + void *data_stack = MEM_mallocN(extractors.data_size_total(), __func__); + uint32_t data_offset = 0; + for (const ExtractorRunData &run_data : extractors) { + const MeshExtract *extractor = run_data.extractor; + void *buffer = mesh_extract_buffer_get(extractor, mbuflist); + void *data = POINTER_OFFSET(data_stack, data_offset); + + extractor->init_subdiv(subdiv_cache, &mr, cache, buffer, data); + + if (extractor->iter_subdiv) { + extractor->iter_subdiv(subdiv_cache, &mr, data); + } + + if (extractor->iter_loose_geom_subdiv) { + extractor->iter_loose_geom_subdiv(subdiv_cache, &mr, &mbc->loose_geom, buffer, data); + } + + if (extractor->finish_subdiv) { + extractor->finish_subdiv(subdiv_cache, buffer, data); + } + } + MEM_freeN(data_stack); +} + +/** \} */ + } // namespace blender::draw extern "C" { @@ -818,4 +912,12 @@ void mesh_buffer_cache_create_requested(struct TaskGraph *task_graph, use_hide); } +void mesh_buffer_cache_create_requested_subdiv(MeshBatchCache *cache, + MeshBufferCache *mbc, + DRWSubdivCache *subdiv_cache, + const ToolSettings *ts) +{ + blender::draw::mesh_buffer_cache_create_requested_subdiv(cache, mbc, subdiv_cache, ts); +} + } // extern "C" diff --git a/source/blender/draw/intern/draw_cache_impl_gpencil.c b/source/blender/draw/intern/draw_cache_impl_gpencil.c index 483e52ed547..ddad07a7476 100644 --- a/source/blender/draw/intern/draw_cache_impl_gpencil.c +++ b/source/blender/draw/intern/draw_cache_impl_gpencil.c @@ -642,7 +642,7 @@ static void gpencil_sbuffer_stroke_ensure(bGPdata *gpd, bool do_stroke, bool do_ float(*tpoints2d)[2] = MEM_mallocN(sizeof(*tpoints2d) * vert_len, __func__); /* Triangulate in 2D. */ for (int i = 0; i < vert_len; i++) { - copy_v2_v2(tpoints2d[i], &tpoints[i].x); + copy_v2_v2(tpoints2d[i], tpoints[i].m_xy); } /* Compute directly inside the IBO data buffer. */ /* OPTI: This is a bottleneck if the stroke is very long. */ diff --git a/source/blender/draw/intern/draw_cache_impl_hair.c b/source/blender/draw/intern/draw_cache_impl_hair.cc index ed0c46ad45a..80f0a3daecc 100644 --- a/source/blender/draw/intern/draw_cache_impl_hair.c +++ b/source/blender/draw/intern/draw_cache_impl_hair.cc @@ -23,7 +23,7 @@ * \brief Hair API for render engines */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -49,27 +49,28 @@ static void hair_batch_cache_clear(Hair *hair); /* ---------------------------------------------------------------------- */ /* Hair GPUBatch Cache */ -typedef struct HairBatchCache { +struct HairBatchCache { ParticleHairCache hair; /* settings to determine if cache is invalid */ bool is_dirty; -} HairBatchCache; +}; /* GPUBatch cache management. */ static bool hair_batch_cache_valid(Hair *hair) { - HairBatchCache *cache = hair->batch_cache; + HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); return (cache && cache->is_dirty == false); } static void hair_batch_cache_init(Hair *hair) { - HairBatchCache *cache = hair->batch_cache; + HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); if (!cache) { - cache = hair->batch_cache = MEM_callocN(sizeof(*cache), __func__); + cache = MEM_cnew<HairBatchCache>(__func__); + hair->batch_cache = cache; } else { memset(cache, 0, sizeof(*cache)); @@ -89,13 +90,13 @@ void DRW_hair_batch_cache_validate(Hair *hair) static HairBatchCache *hair_batch_cache_get(Hair *hair) { DRW_hair_batch_cache_validate(hair); - return hair->batch_cache; + return static_cast<HairBatchCache *>(hair->batch_cache); } void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode) { - HairBatchCache *cache = hair->batch_cache; - if (cache == NULL) { + HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); + if (cache == nullptr) { return; } switch (mode) { @@ -109,7 +110,7 @@ void DRW_hair_batch_cache_dirty_tag(Hair *hair, int mode) static void hair_batch_cache_clear(Hair *hair) { - HairBatchCache *cache = hair->batch_cache; + HairBatchCache *cache = static_cast<HairBatchCache *>(hair->batch_cache); if (!cache) { return; } @@ -125,8 +126,8 @@ void DRW_hair_batch_cache_free(Hair *hair) static void ensure_seg_pt_count(Hair *hair, ParticleHairCache *hair_cache) { - if ((hair_cache->pos != NULL && hair_cache->indices != NULL) || - (hair_cache->proc_point_buf != NULL)) { + if ((hair_cache->pos != nullptr && hair_cache->indices != nullptr) || + (hair_cache->proc_point_buf != nullptr)) { return; } @@ -153,7 +154,7 @@ static void hair_batch_cache_fill_segments_proc_pos(Hair *hair, for (int i = 0; i < num_curves; i++, curve++) { float(*curve_co)[3] = hair->co + curve->firstpoint; float total_len = 0.0f; - float *co_prev = NULL, *seg_data_first; + float *co_prev = nullptr, *seg_data_first; for (int j = 0; j < curve->numpoints; j++) { float *seg_data = (float *)GPU_vertbuf_raw_step(attr_step); copy_v3_v3(seg_data, curve_co[j]); @@ -181,7 +182,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair, ParticleHairCache *cache, GPUMaterial *gpu_material) { - if (cache->proc_point_buf == NULL) { + if (cache->proc_point_buf == nullptr) { /* initialize vertex format */ GPUVertFormat format = {0}; uint pos_id = GPU_vertformat_attr_add(&format, "posTime", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); @@ -209,7 +210,7 @@ static void hair_batch_cache_ensure_procedural_pos(Hair *hair, cache->point_tex = GPU_texture_create_from_vertbuf("hair_point", cache->proc_point_buf); } - if (gpu_material && cache->proc_length_buf != NULL && cache->length_tex) { + if (gpu_material && cache->proc_length_buf != nullptr && cache->length_tex) { ListBase gpu_attrs = GPU_material_attributes(gpu_material); LISTBASE_FOREACH (GPUMaterialAttribute *, attr, &gpu_attrs) { if (attr->type == CD_HAIRLENGTH) { @@ -306,7 +307,7 @@ static void hair_batch_cache_ensure_procedural_indices(Hair *hair, { BLI_assert(thickness_res <= MAX_THICKRES); /* Cylinder strip not currently supported. */ - if (cache->final[subdiv].proc_hairs[thickness_res - 1] != NULL) { + if (cache->final[subdiv].proc_hairs[thickness_res - 1] != nullptr) { return; } @@ -340,7 +341,7 @@ bool hair_ensure_procedural_data(Object *object, int thickness_res) { bool need_ft_update = false; - Hair *hair = object->data; + Hair *hair = static_cast<Hair *>(object->data); HairBatchCache *cache = hair_batch_cache_get(hair); *r_hair_cache = &cache->hair; @@ -349,23 +350,23 @@ bool hair_ensure_procedural_data(Object *object, (*r_hair_cache)->final[subdiv].strands_res = 1 << (steps + subdiv); /* Refreshed on combing and simulation. */ - if ((*r_hair_cache)->proc_point_buf == NULL) { + if ((*r_hair_cache)->proc_point_buf == nullptr) { ensure_seg_pt_count(hair, &cache->hair); hair_batch_cache_ensure_procedural_pos(hair, &cache->hair, gpu_material); need_ft_update = true; } /* Refreshed if active layer or custom data changes. */ - if ((*r_hair_cache)->strand_tex == NULL) { + if ((*r_hair_cache)->strand_tex == nullptr) { hair_batch_cache_ensure_procedural_strand_data(hair, &cache->hair); } /* Refreshed only on subdiv count change. */ - if ((*r_hair_cache)->final[subdiv].proc_buf == NULL) { + if ((*r_hair_cache)->final[subdiv].proc_buf == nullptr) { hair_batch_cache_ensure_procedural_final_points(&cache->hair, subdiv); need_ft_update = true; } - if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == NULL) { + if ((*r_hair_cache)->final[subdiv].proc_hairs[thickness_res - 1] == nullptr) { hair_batch_cache_ensure_procedural_indices(hair, &cache->hair, thickness_res, subdiv); } diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index 82b3b5aee41..1e5ffc14911 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -54,6 +54,7 @@ #include "BKE_object_deform.h" #include "BKE_paint.h" #include "BKE_pbvh.h" +#include "BKE_subdiv_modifier.h" #include "atomic_ops.h" @@ -69,6 +70,7 @@ #include "draw_cache_extract.h" #include "draw_cache_inline.h" +#include "draw_subdivision.h" #include "draw_cache_impl.h" /* own include */ @@ -380,6 +382,7 @@ static void drw_mesh_attributes_add_request(DRW_MeshAttributes *attrs, BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) { switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->ldata; break; @@ -395,6 +398,7 @@ BLI_INLINE const CustomData *mesh_cd_ldata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) { switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->pdata; break; @@ -410,6 +414,7 @@ BLI_INLINE const CustomData *mesh_cd_pdata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) { switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->edata; break; @@ -425,6 +430,7 @@ BLI_INLINE const CustomData *mesh_cd_edata_get_from_mesh(const Mesh *me) BLI_INLINE const CustomData *mesh_cd_vdata_get_from_mesh(const Mesh *me) { switch ((eMeshWrapperType)me->runtime.wrapper_type) { + case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_MDATA: return &me->vdata; break; @@ -1037,6 +1043,15 @@ static void mesh_buffer_cache_clear(MeshBufferCache *mbc) mbc->poly_sorted.visible_tri_len = 0; } +static void mesh_batch_cache_free_subdiv_cache(MeshBatchCache *cache) +{ + if (cache->subdiv_cache) { + draw_subdiv_cache_free(cache->subdiv_cache); + MEM_freeN(cache->subdiv_cache); + cache->subdiv_cache = NULL; + } +} + static void mesh_batch_cache_clear(Mesh *me) { MeshBatchCache *cache = me->runtime.batch_cache; @@ -1064,6 +1079,8 @@ static void mesh_batch_cache_clear(Mesh *me) cache->batch_ready = 0; drw_mesh_weight_state_clear(&cache->weight_state); + + mesh_batch_cache_free_subdiv_cache(cache); } void DRW_mesh_batch_cache_free(Mesh *me) @@ -1693,6 +1710,10 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, const bool do_uvcage = is_editmode && !me->edit_mesh->mesh_eval_final->runtime.is_original; + const int required_mode = BKE_subsurf_modifier_eval_required_mode(DRW_state_is_scene_render(), + is_editmode); + const bool do_subdivision = BKE_subsurf_modifier_can_do_gpu_subdiv(scene, ob, required_mode); + MeshBufferList *mbuflist = &cache->final.buff; /* Initialize batches and request VBO's & IBO's. */ @@ -2038,6 +2059,15 @@ void DRW_mesh_batch_cache_create_requested(struct TaskGraph *task_graph, true); } + if (do_subdivision) { + DRW_create_subdivision(scene, ob, me, cache, &cache->final, ts); + } + else { + /* The subsurf modifier may have been recently removed, or another modifier was added after it, + * so free any potential subdivision cache as it is not needed anymore. */ + mesh_batch_cache_free_subdiv_cache(cache); + } + mesh_buffer_cache_create_requested(task_graph, cache, &cache->final, diff --git a/source/blender/draw/intern/draw_cache_impl_subdivision.cc b/source/blender/draw/intern/draw_cache_impl_subdivision.cc new file mode 100644 index 00000000000..f8d8674f2a7 --- /dev/null +++ b/source/blender/draw/intern/draw_cache_impl_subdivision.cc @@ -0,0 +1,1932 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#include "draw_subdivision.h" + +#include "DNA_mesh_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_editmesh.h" +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_scene.h" +#include "BKE_subdiv.h" +#include "BKE_subdiv_eval.h" +#include "BKE_subdiv_foreach.h" +#include "BKE_subdiv_mesh.h" +#include "BKE_subdiv_modifier.h" + +#include "BLI_linklist.h" + +#include "BLI_string.h" + +#include "PIL_time.h" + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "GPU_capabilities.h" +#include "GPU_compute.h" +#include "GPU_index_buffer.h" +#include "GPU_state.h" +#include "GPU_vertex_buffer.h" + +#include "opensubdiv_capi.h" +#include "opensubdiv_capi_type.h" +#include "opensubdiv_converter_capi.h" +#include "opensubdiv_evaluator_capi.h" +#include "opensubdiv_topology_refiner_capi.h" + +#include "draw_cache_extract.h" +#include "draw_cache_impl.h" +#include "draw_cache_inline.h" +#include "mesh_extractors/extract_mesh.h" + +extern "C" char datatoc_common_subdiv_custom_data_interp_comp_glsl[]; +extern "C" char datatoc_common_subdiv_ibo_lines_comp_glsl[]; +extern "C" char datatoc_common_subdiv_ibo_tris_comp_glsl[]; +extern "C" char datatoc_common_subdiv_lib_glsl[]; +extern "C" char datatoc_common_subdiv_normals_accumulate_comp_glsl[]; +extern "C" char datatoc_common_subdiv_normals_finalize_comp_glsl[]; +extern "C" char datatoc_common_subdiv_patch_evaluation_comp_glsl[]; +extern "C" char datatoc_common_subdiv_vbo_edge_fac_comp_glsl[]; +extern "C" char datatoc_common_subdiv_vbo_lnor_comp_glsl[]; +extern "C" char datatoc_common_subdiv_vbo_sculpt_data_comp_glsl[]; +extern "C" char datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl[]; +extern "C" char datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl[]; + +enum { + SHADER_BUFFER_LINES, + SHADER_BUFFER_LINES_LOOSE, + SHADER_BUFFER_EDGE_FAC, + SHADER_BUFFER_LNOR, + SHADER_BUFFER_TRIS, + SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, + SHADER_BUFFER_NORMALS_ACCUMULATE, + SHADER_BUFFER_NORMALS_FINALIZE, + SHADER_PATCH_EVALUATION, + SHADER_PATCH_EVALUATION_LIMIT_NORMALS, + SHADER_PATCH_EVALUATION_FVAR, + SHADER_PATCH_EVALUATION_FACE_DOTS, + SHADER_COMP_CUSTOM_DATA_INTERP_1D, + SHADER_COMP_CUSTOM_DATA_INTERP_2D, + SHADER_COMP_CUSTOM_DATA_INTERP_3D, + SHADER_COMP_CUSTOM_DATA_INTERP_4D, + SHADER_BUFFER_SCULPT_DATA, + SHADER_BUFFER_UV_STRETCH_ANGLE, + SHADER_BUFFER_UV_STRETCH_AREA, + + NUM_SHADERS, +}; + +static GPUShader *g_subdiv_shaders[NUM_SHADERS]; + +static const char *get_shader_code(int shader_type) +{ + switch (shader_type) { + case SHADER_BUFFER_LINES: + case SHADER_BUFFER_LINES_LOOSE: { + return datatoc_common_subdiv_ibo_lines_comp_glsl; + } + case SHADER_BUFFER_EDGE_FAC: { + return datatoc_common_subdiv_vbo_edge_fac_comp_glsl; + } + case SHADER_BUFFER_LNOR: { + return datatoc_common_subdiv_vbo_lnor_comp_glsl; + } + case SHADER_BUFFER_TRIS: + case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: { + return datatoc_common_subdiv_ibo_tris_comp_glsl; + } + case SHADER_BUFFER_NORMALS_ACCUMULATE: { + return datatoc_common_subdiv_normals_accumulate_comp_glsl; + } + case SHADER_BUFFER_NORMALS_FINALIZE: { + return datatoc_common_subdiv_normals_finalize_comp_glsl; + } + case SHADER_PATCH_EVALUATION: + case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: + case SHADER_PATCH_EVALUATION_FVAR: + case SHADER_PATCH_EVALUATION_FACE_DOTS: { + return datatoc_common_subdiv_patch_evaluation_comp_glsl; + } + case SHADER_COMP_CUSTOM_DATA_INTERP_1D: + case SHADER_COMP_CUSTOM_DATA_INTERP_2D: + case SHADER_COMP_CUSTOM_DATA_INTERP_3D: + case SHADER_COMP_CUSTOM_DATA_INTERP_4D: { + return datatoc_common_subdiv_custom_data_interp_comp_glsl; + } + case SHADER_BUFFER_SCULPT_DATA: { + return datatoc_common_subdiv_vbo_sculpt_data_comp_glsl; + } + case SHADER_BUFFER_UV_STRETCH_ANGLE: { + return datatoc_common_subdiv_vbo_edituv_strech_angle_comp_glsl; + } + case SHADER_BUFFER_UV_STRETCH_AREA: { + return datatoc_common_subdiv_vbo_edituv_strech_area_comp_glsl; + } + } + return nullptr; +} + +static const char *get_shader_name(int shader_type) +{ + switch (shader_type) { + case SHADER_BUFFER_LINES: { + return "subdiv lines build"; + } + case SHADER_BUFFER_LINES_LOOSE: { + return "subdiv lines loose build"; + } + case SHADER_BUFFER_LNOR: { + return "subdiv lnor build"; + } + case SHADER_BUFFER_EDGE_FAC: { + return "subdiv edge fac build"; + } + case SHADER_BUFFER_TRIS: + case SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS: { + return "subdiv tris"; + } + case SHADER_BUFFER_NORMALS_ACCUMULATE: { + return "subdiv normals accumulate"; + } + case SHADER_BUFFER_NORMALS_FINALIZE: { + return "subdiv normals finalize"; + } + case SHADER_PATCH_EVALUATION: { + return "subdiv patch evaluation"; + } + case SHADER_PATCH_EVALUATION_LIMIT_NORMALS: { + return "subdiv patch evaluation limit normals"; + } + case SHADER_PATCH_EVALUATION_FVAR: { + return "subdiv patch evaluation face-varying"; + } + case SHADER_PATCH_EVALUATION_FACE_DOTS: { + return "subdiv patch evaluation face dots"; + } + case SHADER_COMP_CUSTOM_DATA_INTERP_1D: { + return "subdiv custom data interp 1D"; + } + case SHADER_COMP_CUSTOM_DATA_INTERP_2D: { + return "subdiv custom data interp 2D"; + } + case SHADER_COMP_CUSTOM_DATA_INTERP_3D: { + return "subdiv custom data interp 3D"; + } + case SHADER_COMP_CUSTOM_DATA_INTERP_4D: { + return "subdiv custom data interp 4D"; + } + case SHADER_BUFFER_SCULPT_DATA: { + return "subdiv sculpt data"; + } + case SHADER_BUFFER_UV_STRETCH_ANGLE: { + return "subdiv uv stretch angle"; + } + case SHADER_BUFFER_UV_STRETCH_AREA: { + return "subdiv uv stretch area"; + } + } + return nullptr; +} + +static GPUShader *get_patch_evaluation_shader(int shader_type) +{ + if (g_subdiv_shaders[shader_type] == nullptr) { + const char *compute_code = get_shader_code(shader_type); + + const char *defines = nullptr; + if (shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS) { + defines = + "#define OSD_PATCH_BASIS_GLSL\n" + "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n" + "#define LIMIT_NORMALS\n"; + } + else if (shader_type == SHADER_PATCH_EVALUATION_FVAR) { + defines = + "#define OSD_PATCH_BASIS_GLSL\n" + "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n" + "#define FVAR_EVALUATION\n"; + } + else if (shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) { + defines = + "#define OSD_PATCH_BASIS_GLSL\n" + "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n" + "#define FDOTS_EVALUATION\n"; + } + else { + defines = + "#define OSD_PATCH_BASIS_GLSL\n" + "#define OPENSUBDIV_GLSL_COMPUTE_USE_1ST_DERIVATIVES\n"; + } + + /* Merge OpenSubdiv library code with our own library code. */ + const char *patch_basis_source = openSubdiv_getGLSLPatchBasisSource(); + const char *subdiv_lib_code = datatoc_common_subdiv_lib_glsl; + char *library_code = static_cast<char *>( + MEM_mallocN(strlen(patch_basis_source) + strlen(subdiv_lib_code) + 1, + "subdiv patch evaluation library code")); + library_code[0] = '\0'; + strcat(library_code, patch_basis_source); + strcat(library_code, subdiv_lib_code); + + g_subdiv_shaders[shader_type] = GPU_shader_create_compute( + compute_code, library_code, defines, get_shader_name(shader_type)); + + MEM_freeN(library_code); + } + + return g_subdiv_shaders[shader_type]; +} + +static GPUShader *get_subdiv_shader(int shader_type, const char *defines) +{ + if (shader_type == SHADER_PATCH_EVALUATION || + shader_type == SHADER_PATCH_EVALUATION_LIMIT_NORMALS || + shader_type == SHADER_PATCH_EVALUATION_FVAR || + shader_type == SHADER_PATCH_EVALUATION_FACE_DOTS) { + return get_patch_evaluation_shader(shader_type); + } + if (g_subdiv_shaders[shader_type] == nullptr) { + const char *compute_code = get_shader_code(shader_type); + g_subdiv_shaders[shader_type] = GPU_shader_create_compute( + compute_code, datatoc_common_subdiv_lib_glsl, defines, get_shader_name(shader_type)); + } + return g_subdiv_shaders[shader_type]; +} + +/* -------------------------------------------------------------------- */ +/** Vertex formats used for data transfer from OpenSubdiv, and for data processing on our side. + * \{ */ + +static GPUVertFormat *get_uvs_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "uvs", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + return &format; +} + +/* Vertex format for `OpenSubdiv::Osd::PatchArray`. */ +static GPUVertFormat *get_patch_array_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "regDesc", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "desc", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "numPatches", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "indexBase", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "stride", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "primitiveIdBase", GPU_COMP_I32, 1, GPU_FETCH_INT); + } + return &format; +} + +/* Vertex format used for the `PatchTable::PatchHandle`. */ +static GPUVertFormat *get_patch_handle_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "vertex_index", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "array_index", GPU_COMP_I32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "patch_index", GPU_COMP_I32, 1, GPU_FETCH_INT); + } + return &format; +} + +/* Vertex format used for the quad-tree nodes of the PatchMap. */ +static GPUVertFormat *get_quadtree_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "child", GPU_COMP_U32, 4, GPU_FETCH_INT); + } + return &format; +} + +/* Vertex format for `OpenSubdiv::Osd::PatchParam`, not really used, it is only for making sure + * that the #GPUVertBuf used to wrap the OpenSubdiv patch param buffer is valid. */ +static GPUVertFormat *get_patch_param_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "data", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + } + return &format; +} + +/* Vertex format for the patches' vertices index buffer. */ +static GPUVertFormat *get_patch_index_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "data", GPU_COMP_I32, 1, GPU_FETCH_INT); + } + return &format; +} + +/* Vertex format for the OpenSubdiv vertex buffer. */ +static GPUVertFormat *get_subdiv_vertex_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* We use 4 components for the vectors to account for padding in the compute shaders, where + * vec3 is promoted to vec4. */ + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &format; +} + +struct CompressedPatchCoord { + int ptex_face_index; + /* UV coordinate encoded as u << 16 | v, where u and v are quantized on 16-bits. */ + unsigned int encoded_uv; +}; + +MINLINE CompressedPatchCoord make_patch_coord(int ptex_face_index, float u, float v) +{ + CompressedPatchCoord patch_coord = { + ptex_face_index, + (static_cast<unsigned int>(u * 65535.0f) << 16) | static_cast<unsigned int>(v * 65535.0f), + }; + return patch_coord; +} + +/* Vertex format used for the #CompressedPatchCoord. */ +static GPUVertFormat *get_blender_patch_coords_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* WARNING! Adjust #CompressedPatchCoord accordingly. */ + GPU_vertformat_attr_add(&format, "ptex_face_index", GPU_COMP_U32, 1, GPU_FETCH_INT); + GPU_vertformat_attr_add(&format, "uv", GPU_COMP_U32, 1, GPU_FETCH_INT); + } + return &format; +} + +static GPUVertFormat *get_origindex_format() +{ + static GPUVertFormat format; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "color", GPU_COMP_U32, 1, GPU_FETCH_INT); + } + return &format; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities to initialize a OpenSubdiv_Buffer for a GPUVertBuf. + * \{ */ + +static void vertbuf_bind_gpu(const OpenSubdiv_Buffer *buffer) +{ + GPUVertBuf *verts = (GPUVertBuf *)(buffer->data); + GPU_vertbuf_use(verts); +} + +static void *vertbuf_alloc(const OpenSubdiv_Buffer *interface, const uint len) +{ + GPUVertBuf *verts = (GPUVertBuf *)(interface->data); + GPU_vertbuf_data_alloc(verts, len); + return GPU_vertbuf_get_data(verts); +} + +static void vertbuf_device_alloc(const OpenSubdiv_Buffer *interface, const uint len) +{ + GPUVertBuf *verts = (GPUVertBuf *)(interface->data); + /* This assumes that GPU_USAGE_DEVICE_ONLY was used, which won't allocate host memory. */ + // BLI_assert(GPU_vertbuf_get_usage(verts) == GPU_USAGE_DEVICE_ONLY); + GPU_vertbuf_data_alloc(verts, len); +} + +static void vertbuf_wrap_device_handle(const OpenSubdiv_Buffer *interface, uint64_t handle) +{ + GPUVertBuf *verts = (GPUVertBuf *)(interface->data); + GPU_vertbuf_wrap_handle(verts, handle); +} + +static void vertbuf_update_data(const OpenSubdiv_Buffer *interface, + uint start, + uint len, + const void *data) +{ + GPUVertBuf *verts = (GPUVertBuf *)(interface->data); + GPU_vertbuf_update_sub(verts, start, len, data); +} + +static void opensubdiv_gpu_buffer_init(OpenSubdiv_Buffer *buffer_interface, GPUVertBuf *vertbuf) +{ + buffer_interface->data = vertbuf; + buffer_interface->bind_gpu = vertbuf_bind_gpu; + buffer_interface->buffer_offset = 0; + buffer_interface->wrap_device_handle = vertbuf_wrap_device_handle; + buffer_interface->alloc = vertbuf_alloc; + buffer_interface->device_alloc = vertbuf_device_alloc; + buffer_interface->device_update = vertbuf_update_data; +} + +static GPUVertBuf *create_buffer_and_interface(OpenSubdiv_Buffer *interface, GPUVertFormat *format) +{ + GPUVertBuf *buffer = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex(buffer, format, GPU_USAGE_DEVICE_ONLY); + opensubdiv_gpu_buffer_init(interface, buffer); + return buffer; +} + +/** \} */ + +// -------------------------------------------------------- + +static uint tris_count_from_number_of_loops(const uint number_of_loops) +{ + const uint32_t number_of_quads = number_of_loops / 4; + return number_of_quads * 2; +} + +/* -------------------------------------------------------------------- */ +/** \name Utilities to build a GPUVertBuf from an origindex buffer. + * \{ */ + +void draw_subdiv_init_origindex_buffer(GPUVertBuf *buffer, + int *vert_origindex, + uint num_loops, + uint loose_len) +{ + GPU_vertbuf_init_with_format_ex(buffer, get_origindex_format(), GPU_USAGE_STATIC); + GPU_vertbuf_data_alloc(buffer, num_loops + loose_len); + + int *vbo_data = (int *)GPU_vertbuf_get_data(buffer); + memcpy(vbo_data, vert_origindex, num_loops * sizeof(int)); +} + +GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops) +{ + GPUVertBuf *buffer = GPU_vertbuf_calloc(); + draw_subdiv_init_origindex_buffer(buffer, vert_origindex, num_loops, 0); + return buffer; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utilities for DRWPatchMap. + * \{ */ + +static void draw_patch_map_build(DRWPatchMap *gpu_patch_map, Subdiv *subdiv) +{ + GPUVertBuf *patch_map_handles = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex(patch_map_handles, get_patch_handle_format(), GPU_USAGE_STATIC); + + GPUVertBuf *patch_map_quadtree = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex(patch_map_quadtree, get_quadtree_format(), GPU_USAGE_STATIC); + + OpenSubdiv_Buffer patch_map_handles_interface; + opensubdiv_gpu_buffer_init(&patch_map_handles_interface, patch_map_handles); + + OpenSubdiv_Buffer patch_map_quad_tree_interface; + opensubdiv_gpu_buffer_init(&patch_map_quad_tree_interface, patch_map_quadtree); + + int min_patch_face = 0; + int max_patch_face = 0; + int max_depth = 0; + int patches_are_triangular = 0; + + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + evaluator->getPatchMap(evaluator, + &patch_map_handles_interface, + &patch_map_quad_tree_interface, + &min_patch_face, + &max_patch_face, + &max_depth, + &patches_are_triangular); + + gpu_patch_map->patch_map_handles = patch_map_handles; + gpu_patch_map->patch_map_quadtree = patch_map_quadtree; + gpu_patch_map->min_patch_face = min_patch_face; + gpu_patch_map->max_patch_face = max_patch_face; + gpu_patch_map->max_depth = max_depth; + gpu_patch_map->patches_are_triangular = patches_are_triangular; +} + +static void draw_patch_map_free(DRWPatchMap *gpu_patch_map) +{ + GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_handles); + GPU_VERTBUF_DISCARD_SAFE(gpu_patch_map->patch_map_quadtree); + gpu_patch_map->min_patch_face = 0; + gpu_patch_map->max_patch_face = 0; + gpu_patch_map->max_depth = 0; + gpu_patch_map->patches_are_triangular = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name DRWSubdivCache + * \{ */ + +static void draw_subdiv_cache_free_material_data(DRWSubdivCache *cache) +{ + GPU_VERTBUF_DISCARD_SAFE(cache->polygon_mat_offset); + MEM_SAFE_FREE(cache->mat_start); + MEM_SAFE_FREE(cache->mat_end); +} + +static void draw_subdiv_free_edit_mode_cache(DRWSubdivCache *cache) +{ + GPU_VERTBUF_DISCARD_SAFE(cache->verts_orig_index); + GPU_VERTBUF_DISCARD_SAFE(cache->edges_orig_index); + GPU_VERTBUF_DISCARD_SAFE(cache->fdots_patch_coords); +} + +void draw_subdiv_cache_free(DRWSubdivCache *cache) +{ + GPU_VERTBUF_DISCARD_SAFE(cache->patch_coords); + GPU_VERTBUF_DISCARD_SAFE(cache->face_ptex_offset_buffer); + GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_polygon_offset_buffer); + GPU_VERTBUF_DISCARD_SAFE(cache->extra_coarse_face_data); + MEM_SAFE_FREE(cache->subdiv_loop_subdiv_vert_index); + MEM_SAFE_FREE(cache->subdiv_loop_poly_index); + MEM_SAFE_FREE(cache->point_indices); + MEM_SAFE_FREE(cache->subdiv_polygon_offset); + GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency_offsets); + GPU_VERTBUF_DISCARD_SAFE(cache->subdiv_vertex_face_adjacency); + cache->resolution = 0; + cache->num_subdiv_loops = 0; + cache->num_coarse_poly = 0; + cache->num_subdiv_quads = 0; + draw_subdiv_free_edit_mode_cache(cache); + draw_subdiv_cache_free_material_data(cache); + draw_patch_map_free(&cache->gpu_patch_map); + if (cache->ubo) { + GPU_uniformbuf_free(cache->ubo); + cache->ubo = nullptr; + } +} + +/* Flags used in #DRWSubdivCache.extra_coarse_face_data. The flags are packed in the upper bits of + * each uint (one per coarse face), #SUBDIV_COARSE_FACE_FLAG_OFFSET tells where they are in the + * packed bits. */ +#define SUBDIV_COARSE_FACE_FLAG_SMOOTH 1u +#define SUBDIV_COARSE_FACE_FLAG_SELECT 2u +#define SUBDIV_COARSE_FACE_FLAG_ACTIVE 4u + +#define SUBDIV_COARSE_FACE_FLAG_OFFSET 29u + +#define SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK \ + (SUBDIV_COARSE_FACE_FLAG_SMOOTH << SUBDIV_COARSE_FACE_FLAG_OFFSET) +#define SUBDIV_COARSE_FACE_FLAG_SELECT_MASK \ + (SUBDIV_COARSE_FACE_FLAG_SELECT << SUBDIV_COARSE_FACE_FLAG_OFFSET) +#define SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK \ + (SUBDIV_COARSE_FACE_FLAG_ACTIVE << SUBDIV_COARSE_FACE_FLAG_OFFSET) + +#define SUBDIV_COARSE_FACE_LOOP_START_MASK \ + ~((SUBDIV_COARSE_FACE_FLAG_SMOOTH | SUBDIV_COARSE_FACE_FLAG_SELECT | \ + SUBDIV_COARSE_FACE_FLAG_ACTIVE) \ + << SUBDIV_COARSE_FACE_FLAG_OFFSET) + +static void draw_subdiv_cache_update_extra_coarse_face_data(DRWSubdivCache *cache, Mesh *mesh) +{ + if (cache->extra_coarse_face_data == nullptr) { + cache->extra_coarse_face_data = GPU_vertbuf_calloc(); + static GPUVertFormat format; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "data", GPU_COMP_U32, 1, GPU_FETCH_INT); + } + GPU_vertbuf_init_with_format_ex(cache->extra_coarse_face_data, &format, GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->extra_coarse_face_data, mesh->totpoly); + } + + uint32_t *flags_data = (uint32_t *)(GPU_vertbuf_get_data(cache->extra_coarse_face_data)); + + if (cache->bm) { + BMesh *bm = cache->bm; + BMFace *f; + BMIter iter; + + /* Ensure all current elements follow new customdata layout. */ + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + const int index = BM_elem_index_get(f); + uint32_t flag = 0; + if (BM_elem_flag_test(f, BM_ELEM_SMOOTH)) { + flag |= SUBDIV_COARSE_FACE_FLAG_SMOOTH; + } + if (BM_elem_flag_test(f, BM_ELEM_SELECT)) { + flag |= SUBDIV_COARSE_FACE_FLAG_SELECT; + } + if (f == bm->act_face) { + flag |= SUBDIV_COARSE_FACE_FLAG_ACTIVE; + } + const int loopstart = BM_elem_index_get(f->l_first); + flags_data[index] = (uint)(loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET); + } + } + else { + for (int i = 0; i < mesh->totpoly; i++) { + uint32_t flag = 0; + if ((mesh->mpoly[i].flag & ME_SMOOTH) != 0) { + flag = SUBDIV_COARSE_FACE_FLAG_SMOOTH; + } + flags_data[i] = (uint)(mesh->mpoly[i].loopstart) | (flag << SUBDIV_COARSE_FACE_FLAG_OFFSET); + } + } + + /* Make sure updated data is re-uploaded. */ + GPU_vertbuf_tag_dirty(cache->extra_coarse_face_data); +} + +static DRWSubdivCache *mesh_batch_cache_ensure_subdiv_cache(MeshBatchCache *mbc) +{ + DRWSubdivCache *subdiv_cache = mbc->subdiv_cache; + if (subdiv_cache == nullptr) { + subdiv_cache = static_cast<DRWSubdivCache *>( + MEM_callocN(sizeof(DRWSubdivCache), "DRWSubdivCache")); + } + mbc->subdiv_cache = subdiv_cache; + return subdiv_cache; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Subdivision grid traversal. + * + * Traverse the uniform subdivision grid over coarse faces and gather useful information for + * building the draw buffers on the GPU. We primarily gather the patch coordinates for all + * subdivision faces, as well as the original coarse indices for each subdivision element (vertex, + * face, or edge) which directly maps to its coarse counterpart (note that all subdivision faces + * map to a coarse face). This information will then be cached in #DRWSubdivCache for subsequent + * reevaluations, as long as the topology does not change. + * \{ */ + +struct DRWCacheBuildingContext { + const Mesh *coarse_mesh; + const SubdivToMeshSettings *settings; + + DRWSubdivCache *cache; + + /* Pointers into DRWSubdivCache buffers for easier access during traversal. */ + CompressedPatchCoord *patch_coords; + int *subdiv_loop_vert_index; + int *subdiv_loop_subdiv_vert_index; + int *subdiv_loop_edge_index; + int *subdiv_loop_poly_index; + int *point_indices; + + /* Temporary buffers used during traversal. */ + int *vert_origindex_map; + int *edge_origindex_map; + + /* Origindex layers from the mesh to directly look up during traversal the origindex from the + * base mesh for edit data so that we do not have to handle yet another GPU buffer and do this in + * the shaders. */ + int *v_origindex; + int *e_origindex; +}; + +static bool draw_subdiv_topology_info_cb(const SubdivForeachContext *foreach_context, + const int num_vertices, + const int num_edges, + const int num_loops, + const int num_polygons, + const int *subdiv_polygon_offset) +{ + if (num_loops == 0) { + return false; + } + + DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); + DRWSubdivCache *cache = ctx->cache; + + /* Set topology information. */ + cache->num_subdiv_edges = (uint)num_edges; + cache->num_subdiv_loops = (uint)num_loops; + cache->num_subdiv_verts = (uint)num_vertices; + cache->num_subdiv_quads = (uint)num_polygons; + cache->subdiv_polygon_offset = static_cast<int *>(MEM_dupallocN(subdiv_polygon_offset)); + + /* Initialize cache buffers, prefer dynamic usage so we can reuse memory on the host even after + * it was sent to the device, since we may use the data while building other buffers on the CPU + * side. */ + cache->patch_coords = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex( + cache->patch_coords, get_blender_patch_coords_format(), GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->patch_coords, cache->num_subdiv_loops); + + cache->verts_orig_index = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex( + cache->verts_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->verts_orig_index, cache->num_subdiv_loops); + + cache->edges_orig_index = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format_ex( + cache->edges_orig_index, get_origindex_format(), GPU_USAGE_DYNAMIC); + GPU_vertbuf_data_alloc(cache->edges_orig_index, cache->num_subdiv_loops); + + cache->subdiv_loop_subdiv_vert_index = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_subdiv_vert_index")); + + cache->subdiv_loop_poly_index = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_loops * sizeof(int), "subdiv_loop_poly_index")); + + cache->point_indices = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "point_indices")); + for (int i = 0; i < num_vertices; i++) { + cache->point_indices[i] = -1; + } + + /* Initialize context pointers and temporary buffers. */ + ctx->patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data(cache->patch_coords); + ctx->subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(cache->verts_orig_index); + ctx->subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(cache->edges_orig_index); + ctx->subdiv_loop_subdiv_vert_index = cache->subdiv_loop_subdiv_vert_index; + ctx->subdiv_loop_poly_index = cache->subdiv_loop_poly_index; + ctx->point_indices = cache->point_indices; + + ctx->v_origindex = static_cast<int *>( + CustomData_get_layer(&ctx->coarse_mesh->vdata, CD_ORIGINDEX)); + + ctx->e_origindex = static_cast<int *>( + CustomData_get_layer(&ctx->coarse_mesh->edata, CD_ORIGINDEX)); + + ctx->vert_origindex_map = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_verts * sizeof(int), "subdiv_vert_origindex_map")); + for (int i = 0; i < num_vertices; i++) { + ctx->vert_origindex_map[i] = -1; + } + + ctx->edge_origindex_map = static_cast<int *>( + MEM_mallocN(cache->num_subdiv_edges * sizeof(int), "subdiv_edge_origindex_map")); + for (int i = 0; i < num_edges; i++) { + ctx->edge_origindex_map[i] = -1; + } + + return true; +} + +static void draw_subdiv_vertex_corner_cb(const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int UNUSED(ptex_face_index), + const float UNUSED(u), + const float UNUSED(v), + const int coarse_vertex_index, + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int subdiv_vertex_index) +{ + BLI_assert(coarse_vertex_index != ORIGINDEX_NONE); + DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); + ctx->vert_origindex_map[subdiv_vertex_index] = coarse_vertex_index; +} + +static void draw_subdiv_vertex_edge_cb(const SubdivForeachContext *UNUSED(foreach_context), + void *UNUSED(tls_v), + const int UNUSED(ptex_face_index), + const float UNUSED(u), + const float UNUSED(v), + const int UNUSED(coarse_edge_index), + const int UNUSED(coarse_poly_index), + const int UNUSED(coarse_corner), + const int UNUSED(subdiv_vertex_index)) +{ + /* Required if SubdivForeachContext.vertex_corner is also set. */ +} + +static void draw_subdiv_edge_cb(const SubdivForeachContext *foreach_context, + void *UNUSED(tls), + const int coarse_edge_index, + const int subdiv_edge_index, + const int UNUSED(subdiv_v1), + const int UNUSED(subdiv_v2)) +{ + DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); + + int coarse_index = coarse_edge_index; + + if (coarse_index != -1) { + if (ctx->e_origindex) { + coarse_index = ctx->e_origindex[coarse_index]; + } + } + + ctx->edge_origindex_map[subdiv_edge_index] = coarse_index; +} + +static void draw_subdiv_loop_cb(const SubdivForeachContext *foreach_context, + void *UNUSED(tls_v), + const int ptex_face_index, + const float u, + const float v, + const int UNUSED(coarse_loop_index), + const int coarse_poly_index, + const int UNUSED(coarse_corner), + const int subdiv_loop_index, + const int subdiv_vertex_index, + const int subdiv_edge_index) +{ + DRWCacheBuildingContext *ctx = (DRWCacheBuildingContext *)(foreach_context->user_data); + ctx->patch_coords[subdiv_loop_index] = make_patch_coord(ptex_face_index, u, v); + + int coarse_vertex_index = ctx->vert_origindex_map[subdiv_vertex_index]; + + if (coarse_vertex_index != -1) { + if (ctx->v_origindex) { + coarse_vertex_index = ctx->v_origindex[coarse_vertex_index]; + } + + /* Double check as vorigindex may have modified the index. */ + if (coarse_vertex_index != -1) { + ctx->point_indices[coarse_vertex_index] = subdiv_loop_index; + } + } + + ctx->subdiv_loop_subdiv_vert_index[subdiv_loop_index] = subdiv_vertex_index; + /* For now index the subdiv_edge_index, it will be replaced by the actual coarse edge index + * at the end of the traversal as some edges are only then traversed. */ + ctx->subdiv_loop_edge_index[subdiv_loop_index] = subdiv_edge_index; + ctx->subdiv_loop_poly_index[subdiv_loop_index] = coarse_poly_index; + ctx->subdiv_loop_vert_index[subdiv_loop_index] = coarse_vertex_index; +} + +static void draw_subdiv_foreach_callbacks(SubdivForeachContext *foreach_context) +{ + memset(foreach_context, 0, sizeof(*foreach_context)); + foreach_context->topology_info = draw_subdiv_topology_info_cb; + foreach_context->loop = draw_subdiv_loop_cb; + foreach_context->edge = draw_subdiv_edge_cb; + foreach_context->vertex_corner = draw_subdiv_vertex_corner_cb; + foreach_context->vertex_edge = draw_subdiv_vertex_edge_cb; +} + +static void do_subdiv_traversal(DRWCacheBuildingContext *cache_building_context, Subdiv *subdiv) +{ + SubdivForeachContext foreach_context; + draw_subdiv_foreach_callbacks(&foreach_context); + foreach_context.user_data = cache_building_context; + + BKE_subdiv_foreach_subdiv_geometry(subdiv, + &foreach_context, + cache_building_context->settings, + cache_building_context->coarse_mesh); + + /* Now that traversal is done, we can set up the right original indices for the loop-to-edge map. + */ + for (int i = 0; i < cache_building_context->cache->num_subdiv_loops; i++) { + cache_building_context->subdiv_loop_edge_index[i] = + cache_building_context + ->edge_origindex_map[cache_building_context->subdiv_loop_edge_index[i]]; + } +} + +static GPUVertBuf *gpu_vertbuf_create_from_format(GPUVertFormat *format, uint len) +{ + GPUVertBuf *verts = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(verts, format); + GPU_vertbuf_data_alloc(verts, len); + return verts; +} + +/* Build maps to hold enough information to tell which face is adjacent to which vertex; those will + * be used for computing normals if limit surfaces are unavailable. */ +static void build_vertex_face_adjacency_maps(DRWSubdivCache *cache) +{ + /* +1 so that we do not require a special case for the last vertex, this extra offset will + * contain the total number of adjacent faces. */ + cache->subdiv_vertex_face_adjacency_offsets = gpu_vertbuf_create_from_format( + get_origindex_format(), cache->num_subdiv_verts + 1); + + int *vertex_offsets = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency_offsets); + memset(vertex_offsets, 0, sizeof(int) * cache->num_subdiv_verts + 1); + + for (int i = 0; i < cache->num_subdiv_loops; i++) { + vertex_offsets[cache->subdiv_loop_subdiv_vert_index[i]]++; + } + + int ofs = vertex_offsets[0]; + vertex_offsets[0] = 0; + for (uint i = 1; i < cache->num_subdiv_verts + 1; i++) { + int tmp = vertex_offsets[i]; + vertex_offsets[i] = ofs; + ofs += tmp; + } + + cache->subdiv_vertex_face_adjacency = gpu_vertbuf_create_from_format(get_origindex_format(), + cache->num_subdiv_loops); + int *adjacent_faces = (int *)GPU_vertbuf_get_data(cache->subdiv_vertex_face_adjacency); + int *tmp_set_faces = static_cast<int *>( + MEM_callocN(sizeof(int) * cache->num_subdiv_verts, "tmp subdiv vertex offset")); + + for (int i = 0; i < cache->num_subdiv_loops / 4; i++) { + for (int j = 0; j < 4; j++) { + const int subdiv_vertex = cache->subdiv_loop_subdiv_vert_index[i * 4 + j]; + int first_face_offset = vertex_offsets[subdiv_vertex] + tmp_set_faces[subdiv_vertex]; + adjacent_faces[first_face_offset] = i; + tmp_set_faces[subdiv_vertex] += 1; + } + } + + MEM_freeN(tmp_set_faces); +} + +static bool draw_subdiv_build_cache(DRWSubdivCache *cache, + Subdiv *subdiv, + Mesh *mesh_eval, + const Scene *scene, + const SubsurfModifierData *smd, + const bool is_final_render) +{ + const int level = get_render_subsurf_level(&scene->r, smd->levels, is_final_render); + SubdivToMeshSettings to_mesh_settings; + to_mesh_settings.resolution = (1 << level) + 1; + to_mesh_settings.use_optimal_display = false; + + if (cache->resolution != to_mesh_settings.resolution) { + /* Resolution changed, we need to rebuild, free any existing cached data. */ + draw_subdiv_cache_free(cache); + } + + /* If the resolution between the cache and the settings match for some reason, check if the patch + * coordinates were not already generated. Those coordinates are specific to the resolution, so + * they should be null either after initialization, or after freeing if the resolution (or some + * other subdivision setting) changed. + */ + if (cache->patch_coords != nullptr) { + return true; + } + + DRWCacheBuildingContext cache_building_context; + cache_building_context.coarse_mesh = mesh_eval; + cache_building_context.settings = &to_mesh_settings; + cache_building_context.cache = cache; + + do_subdiv_traversal(&cache_building_context, subdiv); + if (cache->num_subdiv_loops == 0) { + /* Either the traversal failed, or we have an empty mesh, either way we cannot go any further. + * The subdiv_polygon_offset cannot then be reliably stored in the cache, so free it directly. + */ + MEM_SAFE_FREE(cache->subdiv_polygon_offset); + return false; + } + + /* Build buffers for the PatchMap. */ + draw_patch_map_build(&cache->gpu_patch_map, subdiv); + + cache->face_ptex_offset = BKE_subdiv_face_ptex_offset_get(subdiv); + + // Build patch coordinates for all the face dots + cache->fdots_patch_coords = gpu_vertbuf_create_from_format(get_blender_patch_coords_format(), + mesh_eval->totpoly); + CompressedPatchCoord *blender_fdots_patch_coords = (CompressedPatchCoord *)GPU_vertbuf_get_data( + cache->fdots_patch_coords); + for (int i = 0; i < mesh_eval->totpoly; i++) { + const int ptex_face_index = cache->face_ptex_offset[i]; + if (mesh_eval->mpoly[i].totloop == 4) { + /* For quads, the center coordinate of the coarse face has `u = v = 0.5`. */ + blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 0.5f, 0.5f); + } + else { + /* For N-gons, since they are split into quads from the center, and since the center is + * chosen to be the top right corner of each quad, the center coordinate of the coarse face + * is any one of those top right corners with `u = v = 1.0`. */ + blender_fdots_patch_coords[i] = make_patch_coord(ptex_face_index, 1.0f, 1.0f); + } + } + + cache->resolution = to_mesh_settings.resolution; + + cache->subdiv_polygon_offset_buffer = draw_subdiv_build_origindex_buffer( + cache->subdiv_polygon_offset, mesh_eval->totpoly); + + cache->face_ptex_offset_buffer = draw_subdiv_build_origindex_buffer(cache->face_ptex_offset, + mesh_eval->totpoly + 1); + cache->num_coarse_poly = mesh_eval->totpoly; + cache->point_indices = cache_building_context.point_indices; + + build_vertex_face_adjacency_maps(cache); + + /* Cleanup. */ + MEM_freeN(cache_building_context.vert_origindex_map); + MEM_freeN(cache_building_context.edge_origindex_map); + + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name DRWSubdivUboStorage. + * + * Common uniforms for the various shaders. + * \{ */ + +struct DRWSubdivUboStorage { + /* Offsets in the buffers data where the source and destination data start. */ + int src_offset; + int dst_offset; + + /* Parameters for the DRWPatchMap. */ + int min_patch_face; + int max_patch_face; + int max_depth; + int patches_are_triangular; + + /* Coarse topology information. */ + int coarse_poly_count; + uint edge_loose_offset; + + /* Refined topology information. */ + uint num_subdiv_loops; + + /* Subdivision settings, is int in C but bool in the GLSL code, as there, bools have the same + * size as ints, so we should use int in C to ensure that the size of the structure is what GLSL + * expects. */ + int optimal_display; + + /* The sculpt mask data layer may be null. */ + int has_sculpt_mask; + + /* Masks for the extra coarse face data. */ + uint coarse_face_select_mask; + uint coarse_face_smooth_mask; + uint coarse_face_active_mask; + uint coarse_face_loopstart_mask; + + /* Number of elements to process in the compute shader (can be the coarse quad count, or the + * final vertex count, depending on which compute pass we do). This is used to early out in case + * of out of bond accesses as compute dispatch are of fixed size. */ + uint total_dispatch_size; +}; + +static_assert((sizeof(DRWSubdivUboStorage) % 16) == 0, + "DRWSubdivUboStorage is not padded to a multiple of the size of vec4"); + +static void draw_subdiv_init_ubo_storage(const DRWSubdivCache *cache, + DRWSubdivUboStorage *ubo, + const int src_offset, + const int dst_offset, + const uint total_dispatch_size, + const bool has_sculpt_mask) +{ + ubo->src_offset = src_offset; + ubo->dst_offset = dst_offset; + ubo->min_patch_face = cache->gpu_patch_map.min_patch_face; + ubo->max_patch_face = cache->gpu_patch_map.max_patch_face; + ubo->max_depth = cache->gpu_patch_map.max_depth; + ubo->patches_are_triangular = cache->gpu_patch_map.patches_are_triangular; + ubo->coarse_poly_count = cache->num_coarse_poly; + ubo->optimal_display = cache->optimal_display; + ubo->num_subdiv_loops = cache->num_subdiv_loops; + ubo->edge_loose_offset = cache->num_subdiv_loops * 2; + ubo->has_sculpt_mask = has_sculpt_mask; + ubo->coarse_face_smooth_mask = SUBDIV_COARSE_FACE_FLAG_SMOOTH_MASK; + ubo->coarse_face_select_mask = SUBDIV_COARSE_FACE_FLAG_SELECT_MASK; + ubo->coarse_face_active_mask = SUBDIV_COARSE_FACE_FLAG_ACTIVE_MASK; + ubo->coarse_face_loopstart_mask = SUBDIV_COARSE_FACE_LOOP_START_MASK; + ubo->total_dispatch_size = total_dispatch_size; +} + +static void draw_subdiv_ubo_update_and_bind(const DRWSubdivCache *cache, + GPUShader *shader, + const int src_offset, + const int dst_offset, + const uint total_dispatch_size, + const bool has_sculpt_mask = false) +{ + DRWSubdivUboStorage storage; + draw_subdiv_init_ubo_storage( + cache, &storage, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask); + + if (!cache->ubo) { + const_cast<DRWSubdivCache *>(cache)->ubo = GPU_uniformbuf_create_ex( + sizeof(DRWSubdivUboStorage), &storage, "DRWSubdivUboStorage"); + } + + GPU_uniformbuf_update(cache->ubo, &storage); + + const int location = GPU_shader_get_uniform_block(shader, "shader_data"); + GPU_uniformbuf_bind(cache->ubo, location); +} + +/** \} */ + +// -------------------------------------------------------- + +#define SUBDIV_LOCAL_WORK_GROUP_SIZE 64 +static uint get_dispatch_size(uint elements) +{ + return divide_ceil_u(elements, SUBDIV_LOCAL_WORK_GROUP_SIZE); +} + +/* Helper to ensure that the UBO is always initalized before dispatching computes and that the same + * number of elements that need to be processed is used for the UBO and the dispatch size. + * Use this instead of a raw call to #GPU_compute_dispatch. */ +static void drw_subdiv_compute_dispatch(const DRWSubdivCache *cache, + GPUShader *shader, + const int src_offset, + const int dst_offset, + uint total_dispatch_size, + const bool has_sculpt_mask = false) +{ + const uint max_res_x = static_cast<uint>(GPU_max_work_group_count(0)); + + const uint dispatch_size = get_dispatch_size(total_dispatch_size); + uint dispatch_rx = dispatch_size; + uint dispatch_ry = 1u; + if (dispatch_rx > max_res_x) { + /* Since there are some limitations with regards to the maximum work group size (could be as + * low as 64k elements per call), we split the number elements into a "2d" number, with the + * final index being computed as `res_x + res_y * max_work_group_size`. Even with a maximum + * work group size of 64k, that still leaves us with roughly `64k * 64k = 4` billion elements + * total, which should be enough. If not, we could also use the 3rd dimension. */ + /* TODO(fclem): We could dispatch fewer groups if we compute the prime factorization and + * get the smallest rect fitting the requirements. */ + dispatch_rx = dispatch_ry = ceilf(sqrtf(dispatch_size)); + /* Avoid a completely empty dispatch line caused by rounding. */ + if ((dispatch_rx * (dispatch_ry - 1)) >= dispatch_size) { + dispatch_ry -= 1; + } + } + + /* X and Y dimensions may have different limits so the above computation may not be right, but + * even with the standard 64k minimum on all dimensions we still have a lot of room. Therefore, + * we presume it all fits. */ + BLI_assert(dispatch_ry < static_cast<uint>(GPU_max_work_group_count(1))); + + draw_subdiv_ubo_update_and_bind( + cache, shader, src_offset, dst_offset, total_dispatch_size, has_sculpt_mask); + + GPU_compute_dispatch(shader, dispatch_rx, dispatch_ry, 1); +} + +void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, + GPUVertBuf *pos_nor, + const bool do_limit_normals) +{ + Subdiv *subdiv = cache->subdiv; + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + + OpenSubdiv_Buffer src_buffer_interface; + GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, + get_subdiv_vertex_format()); + evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); + + OpenSubdiv_Buffer patch_arrays_buffer_interface; + GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface, + get_patch_array_format()); + evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface); + + OpenSubdiv_Buffer patch_index_buffer_interface; + GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface, + get_patch_index_format()); + evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface); + + OpenSubdiv_Buffer patch_param_buffer_interface; + GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface, + get_patch_param_format()); + evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface); + + GPUShader *shader = get_patch_evaluation_shader( + do_limit_normals ? SHADER_PATCH_EVALUATION_LIMIT_NORMALS : SHADER_PATCH_EVALUATION); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(src_buffer, 0); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2); + GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3); + GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4); + GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5); + GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6); + GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7); + GPU_vertbuf_bind_as_ssbo(pos_nor, 8); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We + * also need it for subsequent compute shaders, so a barrier on the shader storage is also + * needed. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); + + GPU_vertbuf_discard(patch_index_buffer); + GPU_vertbuf_discard(patch_param_buffer); + GPU_vertbuf_discard(patch_arrays_buffer); + GPU_vertbuf_discard(src_buffer); +} + +void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, + GPUVertBuf *uvs, + const int face_varying_channel, + const int dst_offset) +{ + Subdiv *subdiv = cache->subdiv; + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + + OpenSubdiv_Buffer src_buffer_interface; + GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, get_uvs_format()); + evaluator->wrapFVarSrcBuffer(evaluator, face_varying_channel, &src_buffer_interface); + + OpenSubdiv_Buffer patch_arrays_buffer_interface; + GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface, + get_patch_array_format()); + evaluator->fillFVarPatchArraysBuffer( + evaluator, face_varying_channel, &patch_arrays_buffer_interface); + + OpenSubdiv_Buffer patch_index_buffer_interface; + GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface, + get_patch_index_format()); + evaluator->wrapFVarPatchIndexBuffer( + evaluator, face_varying_channel, &patch_index_buffer_interface); + + OpenSubdiv_Buffer patch_param_buffer_interface; + GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface, + get_patch_param_format()); + evaluator->wrapFVarPatchParamBuffer( + evaluator, face_varying_channel, &patch_param_buffer_interface); + + GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FVAR); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(src_buffer, 0); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2); + GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3); + GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4); + GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5); + GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6); + GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7); + GPU_vertbuf_bind_as_ssbo(uvs, 8); + + /* The buffer offset has the stride baked in (which is 2 as we have UVs) so remove the stride by + * dividing by 2 */ + const int src_offset = src_buffer_interface.buffer_offset / 2; + drw_subdiv_compute_dispatch(cache, shader, src_offset, dst_offset, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. + * Since it may also be used for computing UV stretches, we also need a barrier on the shader + * storage. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_SHADER_STORAGE); + + /* Cleanup. */ + GPU_shader_unbind(); + + GPU_vertbuf_discard(patch_index_buffer); + GPU_vertbuf_discard(patch_param_buffer); + GPU_vertbuf_discard(patch_arrays_buffer); + GPU_vertbuf_discard(src_buffer); +} + +void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, + GPUVertBuf *src_data, + GPUVertBuf *dst_data, + int dimensions, + int dst_offset) +{ + GPUShader *shader = nullptr; + + if (dimensions == 1) { + shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_1D, + "#define SUBDIV_POLYGON_OFFSET\n" + "#define DIMENSIONS 1\n"); + } + else if (dimensions == 2) { + shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_2D, + "#define SUBDIV_POLYGON_OFFSET\n" + "#define DIMENSIONS 2\n"); + } + else if (dimensions == 3) { + shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_3D, + "#define SUBDIV_POLYGON_OFFSET\n" + "#define DIMENSIONS 3\n"); + } + else if (dimensions == 4) { + shader = get_subdiv_shader(SHADER_COMP_CUSTOM_DATA_INTERP_4D, + "#define SUBDIV_POLYGON_OFFSET\n" + "#define DIMENSIONS 4\n" + "#define GPU_FETCH_U16_TO_FLOAT\n"); + } + else { + /* Crash if dimensions are not supported. */ + } + + GPU_shader_bind(shader); + + /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ + GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); + GPU_vertbuf_bind_as_ssbo(src_data, 1); + GPU_vertbuf_bind_as_ssbo(cache->face_ptex_offset_buffer, 2); + GPU_vertbuf_bind_as_ssbo(cache->patch_coords, 3); + GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 4); + GPU_vertbuf_bind_as_ssbo(dst_data, 5); + + drw_subdiv_compute_dispatch(cache, shader, 0, dst_offset, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache, + GPUVertBuf *mask_vbo, + GPUVertBuf *face_set_vbo, + GPUVertBuf *sculpt_data) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_SCULPT_DATA, nullptr); + GPU_shader_bind(shader); + + if (mask_vbo) { + GPU_vertbuf_bind_as_ssbo(mask_vbo, 0); + } + + GPU_vertbuf_bind_as_ssbo(face_set_vbo, 1); + GPU_vertbuf_bind_as_ssbo(sculpt_data, 2); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads, mask_vbo != nullptr); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache, + GPUVertBuf *pos_nor, + GPUVertBuf *face_adjacency_offsets, + GPUVertBuf *face_adjacency_lists, + GPUVertBuf *vertex_normals) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_ACCUMULATE, nullptr); + GPU_shader_bind(shader); + + int binding_point = 0; + + GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++); + GPU_vertbuf_bind_as_ssbo(face_adjacency_offsets, binding_point++); + GPU_vertbuf_bind_as_ssbo(face_adjacency_lists, binding_point++); + GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_verts); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We + * also need it for subsequent compute shaders, so a barrier on the shader storage is also + * needed. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_finalize_normals(const DRWSubdivCache *cache, + GPUVertBuf *vertex_normals, + GPUVertBuf *subdiv_loop_subdiv_vert_index, + GPUVertBuf *pos_nor) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_NORMALS_FINALIZE, nullptr); + GPU_shader_bind(shader); + + int binding_point = 0; + GPU_vertbuf_bind_as_ssbo(vertex_normals, binding_point++); + GPU_vertbuf_bind_as_ssbo(subdiv_loop_subdiv_vert_index, binding_point++); + GPU_vertbuf_bind_as_ssbo(pos_nor, binding_point++); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attrib array. We + * also need it for subsequent compute shaders, so a barrier on the shader storage is also + * needed. */ + GPU_memory_barrier(GPU_BARRIER_SHADER_STORAGE | GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, + GPUIndexBuf *subdiv_tris, + const int material_count) +{ + const bool do_single_material = material_count <= 1; + + const char *defines = "#define SUBDIV_POLYGON_OFFSET\n"; + if (do_single_material) { + defines = + "#define SUBDIV_POLYGON_OFFSET\n" + "#define SINGLE_MATERIAL\n"; + } + + GPUShader *shader = get_subdiv_shader( + do_single_material ? SHADER_BUFFER_TRIS : SHADER_BUFFER_TRIS_MULTIPLE_MATERIALS, defines); + GPU_shader_bind(shader); + + /* Outputs */ + GPU_indexbuf_bind_as_ssbo(subdiv_tris, 1); + + if (!do_single_material) { + GPU_vertbuf_bind_as_ssbo(cache->polygon_mat_offset, 2); + /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ + GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); + } + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates an index buffer, so we need to put a barrier on the element array. */ + GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache, + GPUVertBuf *fdots_pos, + GPUVertBuf *fdots_nor, + GPUIndexBuf *fdots_indices) +{ + Subdiv *subdiv = cache->subdiv; + OpenSubdiv_Evaluator *evaluator = subdiv->evaluator; + + OpenSubdiv_Buffer src_buffer_interface; + GPUVertBuf *src_buffer = create_buffer_and_interface(&src_buffer_interface, + get_subdiv_vertex_format()); + evaluator->wrapSrcBuffer(evaluator, &src_buffer_interface); + + OpenSubdiv_Buffer patch_arrays_buffer_interface; + GPUVertBuf *patch_arrays_buffer = create_buffer_and_interface(&patch_arrays_buffer_interface, + get_patch_array_format()); + opensubdiv_gpu_buffer_init(&patch_arrays_buffer_interface, patch_arrays_buffer); + evaluator->fillPatchArraysBuffer(evaluator, &patch_arrays_buffer_interface); + + OpenSubdiv_Buffer patch_index_buffer_interface; + GPUVertBuf *patch_index_buffer = create_buffer_and_interface(&patch_index_buffer_interface, + get_patch_index_format()); + evaluator->wrapPatchIndexBuffer(evaluator, &patch_index_buffer_interface); + + OpenSubdiv_Buffer patch_param_buffer_interface; + GPUVertBuf *patch_param_buffer = create_buffer_and_interface(&patch_param_buffer_interface, + get_patch_param_format()); + evaluator->wrapPatchParamBuffer(evaluator, &patch_param_buffer_interface); + + GPUShader *shader = get_patch_evaluation_shader(SHADER_PATCH_EVALUATION_FACE_DOTS); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(src_buffer, 0); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_handles, 1); + GPU_vertbuf_bind_as_ssbo(cache->gpu_patch_map.patch_map_quadtree, 2); + GPU_vertbuf_bind_as_ssbo(cache->fdots_patch_coords, 3); + GPU_vertbuf_bind_as_ssbo(cache->verts_orig_index, 4); + GPU_vertbuf_bind_as_ssbo(patch_arrays_buffer, 5); + GPU_vertbuf_bind_as_ssbo(patch_index_buffer, 6); + GPU_vertbuf_bind_as_ssbo(patch_param_buffer, 7); + GPU_vertbuf_bind_as_ssbo(fdots_pos, 8); + GPU_vertbuf_bind_as_ssbo(fdots_nor, 9); + GPU_indexbuf_bind_as_ssbo(fdots_indices, 10); + GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 11); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_coarse_poly); + + /* This generates two vertex buffers and an index buffer, so we need to put a barrier on the + * vertex attributes and element arrays. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY | GPU_BARRIER_ELEMENT_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); + + GPU_vertbuf_discard(patch_index_buffer); + GPU_vertbuf_discard(patch_param_buffer); + GPU_vertbuf_discard(patch_arrays_buffer); + GPU_vertbuf_discard(src_buffer); +} + +void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, GPUIndexBuf *lines_indices) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES, nullptr); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(cache->edges_orig_index, 0); + GPU_indexbuf_bind_as_ssbo(lines_indices, 1); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates an index buffer, so we need to put a barrier on the element array. */ + GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache, + GPUIndexBuf *lines_indices, + uint num_loose_edges) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LINES_LOOSE, "#define LINES_LOOSE\n"); + GPU_shader_bind(shader); + + GPU_indexbuf_bind_as_ssbo(lines_indices, 1); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, num_loose_edges); + + /* This generates an index buffer, so we need to put a barrier on the element array. */ + GPU_memory_barrier(GPU_BARRIER_ELEMENT_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache, + GPUVertBuf *pos_nor, + GPUVertBuf *edge_idx, + GPUVertBuf *edge_fac) +{ + /* No separate shader for the AMD driver case as we assume that the GPU will not change during + * the execution of the program. */ + const char *defines = GPU_crappy_amd_driver() ? "#define GPU_AMD_DRIVER_BYTE_BUG\n" : nullptr; + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_EDGE_FAC, defines); + GPU_shader_bind(shader); + + GPU_vertbuf_bind_as_ssbo(pos_nor, 0); + GPU_vertbuf_bind_as_ssbo(edge_idx, 1); + GPU_vertbuf_bind_as_ssbo(edge_fac, 2); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, + GPUVertBuf *pos_nor, + GPUVertBuf *lnor) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_LNOR, "#define SUBDIV_POLYGON_OFFSET\n"); + GPU_shader_bind(shader); + + /* Inputs */ + GPU_vertbuf_bind_as_ssbo(pos_nor, 1); + GPU_vertbuf_bind_as_ssbo(cache->extra_coarse_face_data, 2); + /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ + GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); + + /* Outputs */ + GPU_vertbuf_bind_as_ssbo(lnor, 3); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache, + GPUVertBuf *coarse_data, + GPUVertBuf *subdiv_data) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_AREA, + "#define SUBDIV_POLYGON_OFFSET\n"); + GPU_shader_bind(shader); + + /* Inputs */ + GPU_vertbuf_bind_as_ssbo(coarse_data, 1); + /* subdiv_polygon_offset is always at binding point 0 for each shader using it. */ + GPU_vertbuf_bind_as_ssbo(cache->subdiv_polygon_offset_buffer, 0); + + /* Outputs */ + GPU_vertbuf_bind_as_ssbo(subdiv_data, 2); + + drw_subdiv_compute_dispatch(cache, shader, 0, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache, + GPUVertBuf *pos_nor, + GPUVertBuf *uvs, + int uvs_offset, + GPUVertBuf *stretch_angles) +{ + GPUShader *shader = get_subdiv_shader(SHADER_BUFFER_UV_STRETCH_ANGLE, nullptr); + GPU_shader_bind(shader); + + /* Inputs */ + GPU_vertbuf_bind_as_ssbo(pos_nor, 0); + GPU_vertbuf_bind_as_ssbo(uvs, 1); + + /* Outputs */ + GPU_vertbuf_bind_as_ssbo(stretch_angles, 2); + + drw_subdiv_compute_dispatch(cache, shader, uvs_offset, 0, cache->num_subdiv_quads); + + /* This generates a vertex buffer, so we need to put a barrier on the vertex attribute array. */ + GPU_memory_barrier(GPU_BARRIER_VERTEX_ATTRIB_ARRAY); + + /* Cleanup. */ + GPU_shader_unbind(); +} + +/* -------------------------------------------------------------------- */ + +void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache, + MeshRenderData *mr, + const ToolSettings *toolsettings) +{ + Mesh *mesh = cache->mesh; + + /* Setup required data for loose geometry. */ + mr->me = mesh; + mr->medge = mesh->medge; + mr->mvert = mesh->mvert; + mr->mpoly = mesh->mpoly; + mr->mloop = mesh->mloop; + mr->vert_len = mesh->totvert; + mr->edge_len = mesh->totedge; + mr->poly_len = mesh->totpoly; + mr->loop_len = mesh->totloop; + mr->extract_type = MR_EXTRACT_MESH; + + /* MeshRenderData is only used for generating edit mode data here. */ + if (!cache->bm) { + return; + } + + BMesh *bm = cache->bm; + BM_mesh_elem_table_ensure(bm, BM_EDGE | BM_FACE | BM_VERT); + + mr->bm = bm; + mr->toolsettings = toolsettings; + mr->eed_act = BM_mesh_active_edge_get(bm); + mr->efa_act = BM_mesh_active_face_get(bm, false, true); + mr->eve_act = BM_mesh_active_vert_get(bm); + mr->crease_ofs = CustomData_get_offset(&bm->edata, CD_CREASE); + mr->bweight_ofs = CustomData_get_offset(&bm->edata, CD_BWEIGHT); +#ifdef WITH_FREESTYLE + mr->freestyle_edge_ofs = CustomData_get_offset(&bm->edata, CD_FREESTYLE_EDGE); + mr->freestyle_face_ofs = CustomData_get_offset(&bm->pdata, CD_FREESTYLE_FACE); +#endif + mr->v_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->vdata, CD_ORIGINDEX)); + mr->e_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->edata, CD_ORIGINDEX)); + mr->p_origindex = static_cast<int *>(CustomData_get_layer(&mr->me->pdata, CD_ORIGINDEX)); +} + +/** + * For material assignments we want indices for triangles that share a common material to be laid + * out contiguously in memory. To achieve this, we sort the indices based on which material the + * coarse polygon was assigned. The sort is performed by offsetting the loops indices so that they + * are directly assigned to the right sorted indices. + * + * \code{.unparsed} + * Here is a visual representation, considering four quads: + * +---------+---------+---------+---------+ + * | 3 2 | 7 6 | 11 10 | 15 14 | + * | | | | | + * | 0 1 | 4 5 | 8 9 | 12 13 | + * +---------+---------+---------+---------+ + * + * If the first and third quads have the same material, we should have: + * +---------+---------+---------+---------+ + * | 3 2 | 11 10 | 7 6 | 15 14 | + * | | | | | + * | 0 1 | 8 9 | 4 5 | 12 13 | + * +---------+---------+---------+---------+ + * + * So the offsets would be: + * +---------+---------+---------+---------+ + * | 0 0 | 4 4 | -4 -4 | 0 0 | + * | | | | | + * | 0 0 | 4 4 | -4 -4 | 0 0 | + * +---------+---------+---------+---------+ + * \endcode + * + * The offsets are computed not based on the loops indices, but on the number of subdivided + * polygons for each coarse polygon. We then only store a single offset for each coarse polygon, + * since all sub-faces are contiguous, they all share the same offset. + */ +static void draw_subdiv_cache_ensure_mat_offsets(DRWSubdivCache *cache, + Mesh *mesh_eval, + uint mat_len) +{ + draw_subdiv_cache_free_material_data(cache); + + const int number_of_quads = cache->num_subdiv_loops / 4; + + if (mat_len == 1) { + cache->mat_start = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end")); + cache->mat_end = static_cast<int *>(MEM_callocN(sizeof(int), "subdiv mat_end")); + cache->mat_start[0] = 0; + cache->mat_end[0] = number_of_quads; + return; + } + + /* Count number of subdivided polygons for each material. */ + int *mat_start = static_cast<int *>(MEM_callocN(sizeof(int) * mat_len, "subdiv mat_start")); + int *subdiv_polygon_offset = cache->subdiv_polygon_offset; + + // TODO: parallel_reduce? + for (int i = 0; i < mesh_eval->totpoly; i++) { + const MPoly *mpoly = &mesh_eval->mpoly[i]; + const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : + subdiv_polygon_offset[i + 1]; + const int quad_count = next_offset - subdiv_polygon_offset[i]; + const int mat_index = mpoly->mat_nr; + mat_start[mat_index] += quad_count; + } + + /* Accumulate offsets. */ + int ofs = mat_start[0]; + mat_start[0] = 0; + for (uint i = 1; i < mat_len; i++) { + int tmp = mat_start[i]; + mat_start[i] = ofs; + ofs += tmp; + } + + /* Compute per polygon offsets. */ + int *mat_end = static_cast<int *>(MEM_dupallocN(mat_start)); + int *per_polygon_mat_offset = static_cast<int *>( + MEM_mallocN(sizeof(int) * mesh_eval->totpoly, "per_polygon_mat_offset")); + + for (int i = 0; i < mesh_eval->totpoly; i++) { + const MPoly *mpoly = &mesh_eval->mpoly[i]; + const int mat_index = mpoly->mat_nr; + const int single_material_index = subdiv_polygon_offset[i]; + const int material_offset = mat_end[mat_index]; + const int next_offset = (i == mesh_eval->totpoly - 1) ? number_of_quads : + subdiv_polygon_offset[i + 1]; + const int quad_count = next_offset - subdiv_polygon_offset[i]; + mat_end[mat_index] += quad_count; + + per_polygon_mat_offset[i] = material_offset - single_material_index; + } + + cache->polygon_mat_offset = draw_subdiv_build_origindex_buffer(per_polygon_mat_offset, + mesh_eval->totpoly); + cache->mat_start = mat_start; + cache->mat_end = mat_end; + + MEM_freeN(per_polygon_mat_offset); +} + +static bool draw_subdiv_create_requested_buffers(const Scene *scene, + Object *ob, + Mesh *mesh, + struct MeshBatchCache *batch_cache, + MeshBufferCache *mbc, + const ToolSettings *toolsettings, + OpenSubdiv_EvaluatorCache *evaluator_cache) +{ + SubsurfModifierData *smd = BKE_object_get_last_subsurf_modifier(ob); + BLI_assert(smd); + + const bool is_final_render = DRW_state_is_scene_render(); + + SubdivSettings settings; + BKE_subsurf_modifier_subdiv_settings_init(&settings, smd, is_final_render); + + if (settings.level == 0) { + return false; + } + + Mesh *mesh_eval = mesh; + BMesh *bm = nullptr; + if (mesh->edit_mesh) { + mesh_eval = mesh->edit_mesh->mesh_eval_final; + bm = mesh->edit_mesh->bm; + } + + BKE_subsurf_modifier_ensure_runtime(smd); + + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure(smd, &settings, mesh_eval, true); + if (!subdiv) { + return false; + } + + if (!BKE_subdiv_eval_begin_from_mesh( + subdiv, mesh_eval, nullptr, SUBDIV_EVALUATOR_TYPE_GLSL_COMPUTE, evaluator_cache)) { + return false; + } + + DRWSubdivCache *draw_cache = mesh_batch_cache_ensure_subdiv_cache(batch_cache); + if (!draw_subdiv_build_cache(draw_cache, subdiv, mesh_eval, scene, smd, is_final_render)) { + return false; + } + + const bool optimal_display = (smd->flags & eSubsurfModifierFlag_ControlEdges); + + draw_cache->bm = bm; + draw_cache->mesh = mesh_eval; + draw_cache->subdiv = subdiv; + draw_cache->optimal_display = optimal_display; + draw_cache->num_subdiv_triangles = tris_count_from_number_of_loops(draw_cache->num_subdiv_loops); + /* We can only evaluate limit normals if the patches are adaptive. */ + draw_cache->do_limit_normals = settings.is_adaptive; + + if (DRW_ibo_requested(mbc->buff.ibo.tris)) { + draw_subdiv_cache_ensure_mat_offsets(draw_cache, mesh_eval, batch_cache->mat_len); + } + + draw_subdiv_cache_update_extra_coarse_face_data(draw_cache, mesh_eval); + + mesh_buffer_cache_create_requested_subdiv(batch_cache, mbc, draw_cache, toolsettings); + + return true; +} + +static OpenSubdiv_EvaluatorCache *g_evaluator_cache = nullptr; + +void DRW_create_subdivision(const Scene *scene, + Object *ob, + Mesh *mesh, + struct MeshBatchCache *batch_cache, + MeshBufferCache *mbc, + const ToolSettings *toolsettings) +{ + if (g_evaluator_cache == nullptr) { + g_evaluator_cache = openSubdiv_createEvaluatorCache(OPENSUBDIV_EVALUATOR_GLSL_COMPUTE); + } + +#undef TIME_SUBDIV + +#ifdef TIME_SUBDIV + const double begin_time = PIL_check_seconds_timer(); +#endif + + if (!draw_subdiv_create_requested_buffers( + scene, ob, mesh, batch_cache, mbc, toolsettings, g_evaluator_cache)) { + return; + } + +#ifdef TIME_SUBDIV + const double end_time = PIL_check_seconds_timer(); + fprintf(stderr, "Time to update subdivision: %f\n", end_time - begin_time); + fprintf(stderr, "Maximum FPS: %f\n", 1.0 / (end_time - begin_time)); +#endif +} + +void DRW_subdiv_free() +{ + for (int i = 0; i < NUM_SHADERS; ++i) { + GPU_shader_free(g_subdiv_shaders[i]); + } + + DRW_cache_free_old_subdiv(); + + if (g_evaluator_cache) { + openSubdiv_deleteEvaluatorCache(g_evaluator_cache); + g_evaluator_cache = nullptr; + } +} + +static LinkNode *gpu_subdiv_free_queue = nullptr; +static ThreadMutex gpu_subdiv_queue_mutex = BLI_MUTEX_INITIALIZER; + +void DRW_subdiv_cache_free(Subdiv *subdiv) +{ + BLI_mutex_lock(&gpu_subdiv_queue_mutex); + BLI_linklist_prepend(&gpu_subdiv_free_queue, subdiv); + BLI_mutex_unlock(&gpu_subdiv_queue_mutex); +} + +void DRW_cache_free_old_subdiv() +{ + if (gpu_subdiv_free_queue == nullptr) { + return; + } + + BLI_mutex_lock(&gpu_subdiv_queue_mutex); + + while (gpu_subdiv_free_queue != nullptr) { + Subdiv *subdiv = static_cast<Subdiv *>(BLI_linklist_pop(&gpu_subdiv_free_queue)); + /* Set the type to CPU so that we do actually free the cache. */ + subdiv->evaluator->type = OPENSUBDIV_EVALUATOR_CPU; + BKE_subdiv_free(subdiv); + } + + BLI_mutex_unlock(&gpu_subdiv_queue_mutex); +} diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 930fb6eabef..0bf6468f7cc 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -52,6 +52,7 @@ #include "BKE_pointcache.h" #include "BKE_pointcloud.h" #include "BKE_screen.h" +#include "BKE_subdiv_modifier.h" #include "BKE_volume.h" #include "DNA_camera_types.h" @@ -90,6 +91,7 @@ #include "draw_manager_testing.h" #include "draw_manager_text.h" #include "draw_shader.h" +#include "draw_subdivision.h" #include "draw_texture_pool.h" /* only for callbacks */ @@ -2975,6 +2977,8 @@ void DRW_engines_register(void) BKE_volume_batch_cache_dirty_tag_cb = DRW_volume_batch_cache_dirty_tag; BKE_volume_batch_cache_free_cb = DRW_volume_batch_cache_free; + + BKE_subsurf_modifier_free_gpu_cache_cb = DRW_subdiv_cache_free; } } diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index e71a1298812..f1c13bc039a 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -1364,14 +1364,15 @@ void DRW_shgroup_add_material_resources(DRWShadingGroup *grp, struct GPUMaterial if (tex->ima) { /* Image */ GPUTexture *gputex; + ImageUser *iuser = tex->iuser_available ? &tex->iuser : NULL; if (tex->tiled_mapping_name[0]) { - gputex = BKE_image_get_gpu_tiles(tex->ima, tex->iuser, NULL); + gputex = BKE_image_get_gpu_tiles(tex->ima, iuser, NULL); drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); - gputex = BKE_image_get_gpu_tilemap(tex->ima, tex->iuser, NULL); + gputex = BKE_image_get_gpu_tilemap(tex->ima, iuser, NULL); drw_shgroup_material_texture(grp, gputex, tex->tiled_mapping_name, tex->sampler_state); } else { - gputex = BKE_image_get_gpu_texture(tex->ima, tex->iuser, NULL); + gputex = BKE_image_get_gpu_texture(tex->ima, iuser, NULL); drw_shgroup_material_texture(grp, gputex, tex->sampler_name, tex->sampler_state); } } diff --git a/source/blender/draw/intern/draw_subdivision.h b/source/blender/draw/intern/draw_subdivision.h new file mode 100644 index 00000000000..d36bfe87689 --- /dev/null +++ b/source/blender/draw/intern/draw_subdivision.h @@ -0,0 +1,231 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_sys_types.h" + +struct BMesh; +struct GPUIndexBuf; +struct GPUUniformBuf; +struct GPUVertBuf; +struct Mesh; +struct MeshBatchCache; +struct MeshBufferCache; +struct MeshRenderData; +struct Object; +struct Scene; +struct Subdiv; +struct ToolSettings; + +/* -------------------------------------------------------------------- */ +/** \name DRWPatchMap + * + * This is a GPU version of the OpenSubDiv PatchMap. The quad tree and the patch handles are copied + * to GPU buffers in order to lookup the right patch for a given set of patch coordinates. + * \{ */ + +typedef struct DRWPatchMap { + struct GPUVertBuf *patch_map_handles; + struct GPUVertBuf *patch_map_quadtree; + int min_patch_face; + int max_patch_face; + int max_depth; + int patches_are_triangular; +} DRWPatchMap; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name DRWSubdivCache + * + * This holds the various buffers used to evaluate and render subdivision through OpenGL. + * \{ */ + +typedef struct DRWSubdivCache { + struct Mesh *mesh; + struct BMesh *bm; + struct Subdiv *subdiv; + bool optimal_display; + bool do_limit_normals; + + /* Coordinates used to evaluate patches for UVs, positions, and normals. */ + struct GPUVertBuf *patch_coords; + /* Coordinates used to evaluate patches for the face centers (or face dots) in edit-mode. */ + struct GPUVertBuf *fdots_patch_coords; + + /* Resolution used to generate the patch coordinates. */ + int resolution; + + /* Number of subdivided loops, also the number of patch coordinates since we have one coordinate + * but quad corner/vertex. */ + uint num_subdiv_loops; + uint num_subdiv_edges; + uint num_subdiv_triangles; + uint num_subdiv_verts; + uint num_subdiv_quads; + + /* Number of polygons in the coarse mesh, notably used to compute a coarse polygon index given a + * subdivision loop index. */ + int num_coarse_poly; + + /* Maps subdivision loop to subdivided vertex index. */ + int *subdiv_loop_subdiv_vert_index; + /* Maps subdivision loop to original coarse poly index. */ + int *subdiv_loop_poly_index; + + /* Indices of faces adjacent to the vertices, ordered by vertex index, with no particular + * winding. */ + struct GPUVertBuf *subdiv_vertex_face_adjacency; + /* The difference between value (i + 1) and (i) gives the number of faces adjacent to vertex (i). + */ + struct GPUVertBuf *subdiv_vertex_face_adjacency_offsets; + + /* Maps subdivision loop to original coarse vertex index, only really useful for edit mode. */ + struct GPUVertBuf *verts_orig_index; + /* Maps subdivision loop to original coarse edge index, only really useful for edit mode. */ + struct GPUVertBuf *edges_orig_index; + + /* Owned by #Subdiv. Indexed by coarse polygon index, difference between value (i + 1) and (i) + * gives the number of ptex faces for coarse polygon (i). */ + int *face_ptex_offset; + /* Vertex buffer for face_ptex_offset. */ + struct GPUVertBuf *face_ptex_offset_buffer; + + int *subdiv_polygon_offset; + struct GPUVertBuf *subdiv_polygon_offset_buffer; + + /* Contains the start loop index and the smooth flag for each coarse polygon. */ + struct GPUVertBuf *extra_coarse_face_data; + + /* Computed for ibo.points, one value per subdivided vertex, mapping coarse vertices -> + * subdivided loop */ + int *point_indices; + + /* Material offsets. */ + int *mat_start; + int *mat_end; + struct GPUVertBuf *polygon_mat_offset; + + DRWPatchMap gpu_patch_map; + + /* UBO to store settings for the various compute shaders. */ + struct GPUUniformBuf *ubo; +} DRWSubdivCache; + +/* Only frees the data of the cache, caller is responsible to free the cache itself if necessary. + */ +void draw_subdiv_cache_free(DRWSubdivCache *cache); + +/** \} */ + +void DRW_create_subdivision(const struct Scene *scene, + struct Object *ob, + struct Mesh *mesh, + struct MeshBatchCache *batch_cache, + struct MeshBufferCache *mbc, + const struct ToolSettings *toolsettings); + +void DRW_subdiv_cache_free(struct Subdiv *subdiv); + +void draw_subdiv_init_mesh_render_data(DRWSubdivCache *cache, + struct MeshRenderData *mr, + const struct ToolSettings *toolsettings); + +void draw_subdiv_init_origindex_buffer(struct GPUVertBuf *buffer, + int *vert_origindex, + uint num_loops, + uint loose_len); + +struct GPUVertBuf *draw_subdiv_build_origindex_buffer(int *vert_origindex, uint num_loops); + +/* Compute shader functions. */ + +void draw_subdiv_build_sculpt_data_buffer(const DRWSubdivCache *cache, + struct GPUVertBuf *mask_vbo, + struct GPUVertBuf *face_set_vbo, + struct GPUVertBuf *sculpt_data); + +void draw_subdiv_accumulate_normals(const DRWSubdivCache *cache, + struct GPUVertBuf *pos_nor, + struct GPUVertBuf *face_adjacency_offsets, + struct GPUVertBuf *face_adjacency_lists, + struct GPUVertBuf *vertex_normals); + +void draw_subdiv_finalize_normals(const DRWSubdivCache *cache, + struct GPUVertBuf *vertex_normals, + struct GPUVertBuf *subdiv_loop_subdiv_vert_index, + struct GPUVertBuf *pos_nor); + +void draw_subdiv_extract_pos_nor(const DRWSubdivCache *cache, + struct GPUVertBuf *pos_nor, + const bool do_limit_normals); + +void draw_subdiv_interp_custom_data(const DRWSubdivCache *cache, + struct GPUVertBuf *src_data, + struct GPUVertBuf *dst_data, + int dimensions, + int dst_offset); + +void draw_subdiv_extract_uvs(const DRWSubdivCache *cache, + struct GPUVertBuf *uvs, + const int face_varying_channel, + const int dst_offset); + +void draw_subdiv_build_edge_fac_buffer(const DRWSubdivCache *cache, + struct GPUVertBuf *pos_nor, + struct GPUVertBuf *edge_idx, + struct GPUVertBuf *edge_fac); + +void draw_subdiv_build_tris_buffer(const DRWSubdivCache *cache, + struct GPUIndexBuf *subdiv_tris, + const int material_count); + +void draw_subdiv_build_lines_buffer(const DRWSubdivCache *cache, + struct GPUIndexBuf *lines_indices); + +void draw_subdiv_build_lines_loose_buffer(const DRWSubdivCache *cache, + struct GPUIndexBuf *lines_indices, + uint num_loose_edges); + +void draw_subdiv_build_fdots_buffers(const DRWSubdivCache *cache, + struct GPUVertBuf *fdots_pos, + struct GPUVertBuf *fdots_nor, + struct GPUIndexBuf *fdots_indices); + +void draw_subdiv_build_lnor_buffer(const DRWSubdivCache *cache, + struct GPUVertBuf *pos_nor, + struct GPUVertBuf *lnor); + +void draw_subdiv_build_edituv_stretch_area_buffer(const DRWSubdivCache *cache, + struct GPUVertBuf *coarse_data, + struct GPUVertBuf *subdiv_data); + +void draw_subdiv_build_edituv_stretch_angle_buffer(const DRWSubdivCache *cache, + struct GPUVertBuf *pos_nor, + struct GPUVertBuf *uvs, + int uvs_offset, + struct GPUVertBuf *stretch_angles); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh.h b/source/blender/draw/intern/mesh_extractors/extract_mesh.h index 7d21804c08f..35cc2cf986e 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh.h +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh.h @@ -39,6 +39,8 @@ extern "C" { #endif +struct DRWSubdivCache; + #define MIN_RANGE_LEN 1024 /* ---------------------------------------------------------------------- */ @@ -203,6 +205,11 @@ typedef void(ExtractLVertMeshFn)(const MeshRenderData *mr, const MVert *mv, const int lvert_index, void *data); +typedef void(ExtractLooseGeomSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *data); typedef void(ExtractInitFn)(const MeshRenderData *mr, struct MeshBatchCache *cache, void *buffer, @@ -213,6 +220,18 @@ typedef void(ExtractFinishFn)(const MeshRenderData *mr, void *data); typedef void(ExtractTaskReduceFn)(void *userdata, void *task_userdata); +typedef void(ExtractInitSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *data); +typedef void(ExtractIterSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *data); +typedef void(ExtractFinishSubdivFn)(const struct DRWSubdivCache *subdiv_cache, + void *buf, + void *data); + typedef struct MeshExtract { /** Executed on main thread and return user data for iteration functions. */ ExtractInitFn *init; @@ -225,9 +244,14 @@ typedef struct MeshExtract { ExtractLEdgeMeshFn *iter_ledge_mesh; ExtractLVertBMeshFn *iter_lvert_bm; ExtractLVertMeshFn *iter_lvert_mesh; + ExtractLooseGeomSubdivFn *iter_loose_geom_subdiv; /** Executed on one worker thread after all elements iterations. */ ExtractTaskReduceFn *task_reduce; ExtractFinishFn *finish; + /** Executed on main thread for subdivision evaluation. */ + ExtractInitSubdivFn *init_subdiv; + ExtractIterSubdivFn *iter_subdiv; + ExtractFinishSubdivFn *finish_subdiv; /** Used to request common data. */ eMRDataType data_type; size_t data_size; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc index 4cc9a875f79..6a1691e8634 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_edituv.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Edit UV Triangles Indices @@ -94,6 +96,57 @@ static void extract_edituv_tris_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init(&data->elb, + GPU_PRIM_TRIS, + subdiv_cache->num_subdiv_triangles, + subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_tris_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + const uint loop_idx = i * 4; + const int poly_origindex = subdiv_loop_poly_index[loop_idx]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + edituv_tri_add(data, + BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 1, + loop_idx + 2); + + edituv_tri_add(data, + BM_elem_flag_test(efa, BM_ELEM_HIDDEN) != 0, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + loop_idx, + loop_idx + 2, + loop_idx + 3); + } +} + +static void extract_edituv_tris_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_tris() { MeshExtract extractor = {nullptr}; @@ -101,6 +154,9 @@ constexpr MeshExtract create_extractor_edituv_tris() extractor.iter_looptri_bm = extract_edituv_tris_iter_looptri_bm; extractor.iter_looptri_mesh = extract_edituv_tris_iter_looptri_mesh; extractor.finish = extract_edituv_tris_finish; + extractor.init_subdiv = extract_edituv_tris_init_subdiv; + extractor.iter_subdiv = extract_edituv_tris_iter_subdiv; + extractor.finish_subdiv = extract_edituv_tris_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -184,6 +240,56 @@ static void extract_edituv_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_LINES, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_lines_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + + uint start_loop_idx = i * 4; + uint end_loop_idx = (i + 1) * 4; + + const int poly_origindex = subdiv_loop_poly_index[start_loop_idx]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + for (uint loop_idx = start_loop_idx; loop_idx < end_loop_idx; loop_idx++) { + const int edge_origindex = subdiv_loop_edge_index[loop_idx]; + const bool real_edge = (edge_origindex != -1 && + mr->e_origindex[edge_origindex] != ORIGINDEX_NONE); + edituv_edge_add(data, + BM_elem_flag_test_bool(efa, BM_ELEM_HIDDEN) != 0 || !real_edge, + BM_elem_flag_test_bool(efa, BM_ELEM_SELECT) != 0, + loop_idx, + (loop_idx + 1 == end_loop_idx) ? start_loop_idx : (loop_idx + 1)); + } + } +} + +static void extract_edituv_lines_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_lines() { MeshExtract extractor = {nullptr}; @@ -191,6 +297,9 @@ constexpr MeshExtract create_extractor_edituv_lines() extractor.iter_poly_bm = extract_edituv_lines_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_lines_iter_poly_mesh; extractor.finish = extract_edituv_lines_finish; + extractor.init_subdiv = extract_edituv_lines_init_subdiv; + extractor.iter_subdiv = extract_edituv_lines_iter_subdiv; + extractor.finish_subdiv = extract_edituv_lines_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; @@ -268,6 +377,50 @@ static void extract_edituv_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(&data->elb, ibo); } +static void extract_edituv_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *tls_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(tls_data); + GPU_indexbuf_init( + &data->elb, GPU_PRIM_POINTS, subdiv_cache->num_subdiv_loops, subdiv_cache->num_subdiv_loops); + data->sync_selection = (mr->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; +} + +static void extract_edituv_points_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + const bool real_vert = (mr->extract_type == MR_EXTRACT_MAPPED && (mr->v_origindex) && + vert_origindex != -1 && + mr->v_origindex[vert_origindex] != ORIGINDEX_NONE); + edituv_point_add(data, + (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) || !real_vert, + BM_elem_flag_test(efa, BM_ELEM_SELECT) != 0, + i); + } +} + +static void extract_edituv_points_finish_subdiv(const struct DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + MeshExtract_EditUvElem_Data *data = static_cast<MeshExtract_EditUvElem_Data *>(_data); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(&data->elb, ibo); +} + constexpr MeshExtract create_extractor_edituv_points() { MeshExtract extractor = {nullptr}; @@ -275,6 +428,9 @@ constexpr MeshExtract create_extractor_edituv_points() extractor.iter_poly_bm = extract_edituv_points_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_points_iter_poly_mesh; extractor.finish = extract_edituv_points_finish; + extractor.init_subdiv = extract_edituv_points_init_subdiv; + extractor.iter_subdiv = extract_edituv_points_iter_subdiv; + extractor.finish_subdiv = extract_edituv_points_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUvElem_Data); extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc index 54f5611106f..3d9729dea56 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -155,6 +157,33 @@ static void extract_lines_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_lines_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + GPU_indexbuf_init_build_on_device(ibo, + subdiv_cache->num_subdiv_loops * 2 + mr->edge_loose_len * 2); + + draw_subdiv_build_lines_buffer(subdiv_cache, ibo); +} + +static void extract_lines_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + draw_subdiv_build_lines_loose_buffer(subdiv_cache, ibo, static_cast<uint>(loose_geom->edge_len)); +} + constexpr MeshExtract create_extractor_lines() { MeshExtract extractor = {nullptr}; @@ -163,6 +192,8 @@ constexpr MeshExtract create_extractor_lines() extractor.iter_poly_mesh = extract_lines_iter_poly_mesh; extractor.iter_ledge_bm = extract_lines_iter_ledge_bm; extractor.iter_ledge_mesh = extract_lines_iter_ledge_mesh; + extractor.init_subdiv = extract_lines_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_lines_loose_geom_subdiv; extractor.task_reduce = extract_lines_task_reduce; extractor.finish = extract_lines_finish; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc index e7dabfa9ee2..6855feb51ed 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_lines_adjacency.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -44,6 +45,18 @@ struct MeshExtract_LineAdjacency_Data { uint *vert_to_loop; }; +static void line_adjacency_data_init(MeshExtract_LineAdjacency_Data *data, + uint vert_len, + uint loop_len, + uint tess_edge_len) +{ + data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * vert_len, __func__)); + + GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, loop_len); + data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); + data->is_manifold = true; +} + static void extract_lines_adjacency_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *UNUSED(buf), @@ -55,11 +68,7 @@ static void extract_lines_adjacency_init(const MeshRenderData *mr, uint tess_edge_len = mr->loop_len + mr->tri_len - mr->poly_len; MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(tls_data); - data->vert_to_loop = static_cast<uint *>(MEM_callocN(sizeof(uint) * mr->vert_len, __func__)); - - GPU_indexbuf_init(&data->elb, GPU_PRIM_LINES_ADJ, tess_edge_len, mr->loop_len); - data->eh = BLI_edgehash_new_ex(__func__, tess_edge_len); - data->is_manifold = true; + line_adjacency_data_init(data, mr->vert_len, mr->loop_len, tess_edge_len); } BLI_INLINE void lines_adjacency_triangle( @@ -171,6 +180,56 @@ static void extract_lines_adjacency_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->vert_to_loop); } +static void extract_lines_adjacency_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buf), + void *_data) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + + /* For each polygon there is (loop + triangle - 1) edges. Since we only have quads, and a quad + * is split into 2 triangles, we have (loop + 2 - 1) = (loop + 1) edges for each quad, or in + * total: (number_of_loops + number_of_quads). */ + const uint tess_len = subdiv_cache->num_subdiv_loops + subdiv_cache->num_subdiv_quads; + line_adjacency_data_init( + data, tess_len, subdiv_cache->num_subdiv_verts, subdiv_cache->num_subdiv_loops); +} + +static void extract_lines_adjacency_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + void *_data) +{ + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + + for (uint i = 0; i < subdiv_cache->num_subdiv_quads; i++) { + const uint loop_index = i * 4; + const uint l0 = loop_index + 0; + const uint l1 = loop_index + 1; + const uint l2 = loop_index + 2; + const uint l3 = loop_index + 3; + + const uint v0 = subdiv_cache->subdiv_loop_subdiv_vert_index[l0]; + const uint v1 = subdiv_cache->subdiv_loop_subdiv_vert_index[l1]; + const uint v2 = subdiv_cache->subdiv_loop_subdiv_vert_index[l2]; + const uint v3 = subdiv_cache->subdiv_loop_subdiv_vert_index[l3]; + + lines_adjacency_triangle(v0, v1, v2, l0, l1, l2, data); + lines_adjacency_triangle(v0, v2, v3, l0, l2, l3, data); + } +} + +static void extract_lines_adjacency_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_data) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + MeshExtract_LineAdjacency_Data *data = static_cast<MeshExtract_LineAdjacency_Data *>(_data); + GPU_indexbuf_build_in_place(&data->elb, ibo); + BLI_edgehash_free(data->eh, nullptr); + MEM_freeN(data->vert_to_loop); +} + #undef NO_EDGE constexpr MeshExtract create_extractor_lines_adjacency() @@ -180,6 +239,9 @@ constexpr MeshExtract create_extractor_lines_adjacency() extractor.iter_looptri_bm = extract_lines_adjacency_iter_looptri_bm; extractor.iter_looptri_mesh = extract_lines_adjacency_iter_looptri_mesh; extractor.finish = extract_lines_adjacency_finish; + extractor.init_subdiv = extract_lines_adjacency_init_subdiv; + extractor.iter_subdiv = extract_lines_adjacency_iter_subdiv; + extractor.finish_subdiv = extract_lines_adjacency_finish_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_LineAdjacency_Data); extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc index 01e14a004ed..19167772a42 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_points.cc @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -155,6 +156,74 @@ static void extract_points_finish(const MeshRenderData *UNUSED(mr), GPU_indexbuf_build_in_place(elb, ibo); } +static void extract_points_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *UNUSED(cache), + void *UNUSED(buffer), + void *data) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + /* Copy the points as the data upload will free them. */ + elb->data = (uint *)MEM_dupallocN(subdiv_cache->point_indices); + elb->index_len = subdiv_cache->num_subdiv_verts; + elb->index_min = 0; + elb->index_max = subdiv_cache->num_subdiv_loops - 1; + elb->prim_type = GPU_PRIM_POINTS; +} + +static void extract_points_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *data) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(data); + + elb->data = static_cast<uint32_t *>( + MEM_reallocN(elb->data, sizeof(uint) * (subdiv_cache->num_subdiv_loops + loop_loose_len))); + + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + if (elb->data[loose_edge->v1] == -1u) { + elb->data[loose_edge->v1] = offset; + } + if (elb->data[loose_edge->v2] == -1u) { + elb->data[loose_edge->v2] = offset + 1; + } + elb->index_max += 2; + elb->index_len += 2; + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + if (elb->data[loose_geom->verts[i]] == -1u) { + elb->data[loose_geom->verts[i]] = offset; + } + elb->index_max += 1; + elb->index_len += 1; + offset += 1; + } +} + +static void extract_points_finish_subdiv(const DRWSubdivCache *UNUSED(subdiv_cache), + void *buf, + void *_userdata) +{ + GPUIndexBufBuilder *elb = static_cast<GPUIndexBufBuilder *>(_userdata); + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buf); + GPU_indexbuf_build_in_place(elb, ibo); +} + constexpr MeshExtract create_extractor_points() { MeshExtract extractor = {nullptr}; @@ -167,6 +236,9 @@ constexpr MeshExtract create_extractor_points() extractor.iter_lvert_mesh = extract_points_iter_lvert_mesh; extractor.task_reduce = extract_points_task_reduce; extractor.finish = extract_points_finish; + extractor.init_subdiv = extract_points_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_points_loose_geom_subdiv; + extractor.finish_subdiv = extract_points_finish_subdiv; extractor.use_threading = true; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(GPUIndexBufBuilder); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc index 54e733d3d86..b1ace8bc6c9 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_ibo_tris.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { static void extract_tris_mat_task_reduce(void *_userdata_to, void *_userdata_from) @@ -123,10 +125,37 @@ static void extract_tris_finish(const MeshRenderData *mr, } } +static void extract_tris_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUIndexBuf *ibo = static_cast<GPUIndexBuf *>(buffer); + /* Initialize the index buffer, it was already allocated, it will be filled on the device. */ + GPU_indexbuf_init_build_on_device(ibo, subdiv_cache->num_subdiv_triangles * 3); + + if (cache->tris_per_mat) { + for (int i = 0; i < cache->mat_len; i++) { + if (cache->tris_per_mat[i] == nullptr) { + cache->tris_per_mat[i] = GPU_indexbuf_calloc(); + } + + /* Multiply by 6 since we have 2 triangles per quad. */ + const int start = subdiv_cache->mat_start[i] * 6; + const int len = (subdiv_cache->mat_end[i] - subdiv_cache->mat_start[i]) * 6; + GPU_indexbuf_create_subrange_in_place(cache->tris_per_mat[i], ibo, start, len); + } + } + + draw_subdiv_build_tris_buffer(subdiv_cache, ibo, cache->mat_len); +} + constexpr MeshExtract create_extractor_tris() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_poly_bm = extract_tris_iter_poly_bm; extractor.iter_poly_mesh = extract_tris_iter_poly_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; @@ -214,6 +243,7 @@ constexpr MeshExtract create_extractor_tris_single_mat() { MeshExtract extractor = {nullptr}; extractor.init = extract_tris_single_mat_init; + extractor.init_subdiv = extract_tris_init_subdiv; extractor.iter_looptri_bm = extract_tris_single_mat_iter_looptri_bm; extractor.iter_looptri_mesh = extract_tris_single_mat_iter_looptri_mesh; extractor.task_reduce = extract_tris_mat_task_reduce; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc index 8a5a8134ca7..ea702e5efdd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_attributes.cc @@ -32,6 +32,7 @@ #include "BKE_attribute.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -153,7 +154,9 @@ static GPUVertCompType get_comp_type_for_type(CustomDataType type) static void init_vbo_for_attribute(const MeshRenderData *mr, GPUVertBuf *vbo, - const DRW_AttributeRequest &request) + const DRW_AttributeRequest &request, + bool build_on_device, + uint32_t len) { GPUVertCompType comp_type = get_comp_type_for_type(request.cd_type); GPUVertFetchMode fetch_mode = get_fetch_mode_for_type(request.cd_type); @@ -184,8 +187,13 @@ static void init_vbo_for_attribute(const MeshRenderData *mr, } } - GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, static_cast<uint32_t>(mr->loop_len)); + if (build_on_device) { + GPU_vertbuf_init_build_on_device(vbo, &format, len); + } + else { + GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_data_alloc(vbo, len); + } } template<typename AttributeType, typename VBOType> @@ -309,7 +317,7 @@ static void extract_attr_init(const MeshRenderData *mr, GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - init_vbo_for_attribute(mr, vbo, request); + init_vbo_for_attribute(mr, vbo, request, false, static_cast<uint32_t>(mr->loop_len)); /* TODO(kevindietrich) : float3 is used for scalar attributes as the implicit conversion done by * OpenGL to vec4 for a scalar `s` will produce a `vec4(s, 0, 0, 1)`. However, following the @@ -346,6 +354,68 @@ static void extract_attr_init(const MeshRenderData *mr, } } +static void extract_attr_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data), + int index) +{ + const DRW_MeshAttributes *attrs_used = &cache->attr_used; + const DRW_AttributeRequest &request = attrs_used->requests[index]; + + Mesh *coarse_mesh = subdiv_cache->mesh; + + const uint32_t dimensions = gpu_component_size_for_attribute_type(request.cd_type); + + /* Prepare VBO for coarse data. The compute shader only expects floats. */ + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + static GPUVertFormat coarse_format = {0}; + GPU_vertformat_attr_add(&coarse_format, "data", GPU_COMP_F32, dimensions, GPU_FETCH_FLOAT); + GPU_vertbuf_init_with_format_ex(src_data, &coarse_format, GPU_USAGE_STATIC); + GPU_vertbuf_data_alloc(src_data, static_cast<uint32_t>(coarse_mesh->totloop)); + + switch (request.cd_type) { + case CD_PROP_BOOL: { + extract_attr_generic<bool, float3>(mr, src_data, request); + break; + } + case CD_PROP_INT32: { + extract_attr_generic<int32_t, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT: { + extract_attr_generic<float, float3>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT2: { + extract_attr_generic<float2>(mr, src_data, request); + break; + } + case CD_PROP_FLOAT3: { + extract_attr_generic<float3>(mr, src_data, request); + break; + } + case CD_PROP_COLOR: { + extract_attr_generic<MPropCol, gpuMeshCol>(mr, src_data, request); + break; + } + default: { + BLI_assert(false); + } + } + + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + init_vbo_for_attribute(mr, dst_buffer, request, true, subdiv_cache->num_subdiv_loops); + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data( + subdiv_cache, src_data, dst_buffer, static_cast<int>(dimensions), 0); + + GPU_vertbuf_discard(src_data); +} + /* Wrappers around extract_attr_init so we can pass the index of the attribute that we want to * extract. The overall API does not allow us to pass this in a convenient way. */ #define EXTRACT_INIT_WRAPPER(index) \ @@ -353,6 +423,14 @@ static void extract_attr_init(const MeshRenderData *mr, const MeshRenderData *mr, struct MeshBatchCache *cache, void *buf, void *tls_data) \ { \ extract_attr_init(mr, cache, buf, tls_data, index); \ + } \ + static void extract_attr_init_subdiv##index(const DRWSubdivCache *subdiv_cache, \ + const MeshRenderData *mr, \ + struct MeshBatchCache *cache, \ + void *buf, \ + void *tls_data) \ + { \ + extract_attr_init_subdiv(subdiv_cache, mr, cache, buf, tls_data, index); \ } EXTRACT_INIT_WRAPPER(0) @@ -371,10 +449,12 @@ EXTRACT_INIT_WRAPPER(12) EXTRACT_INIT_WRAPPER(13) EXTRACT_INIT_WRAPPER(14) -template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn) +template<int index> +constexpr MeshExtract create_extractor_attr(ExtractInitFn fn, ExtractInitSubdivFn subdiv_fn) { MeshExtract extractor = {nullptr}; extractor.init = fn; + extractor.init_subdiv = subdiv_fn; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; @@ -388,7 +468,8 @@ template<int index> constexpr MeshExtract create_extractor_attr(ExtractInitFn fn extern "C" { #define CREATE_EXTRACTOR_ATTR(index) \ - blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index) + blender::draw::create_extractor_attr<index>(blender::draw::extract_attr_init##index, \ + blender::draw::extract_attr_init_subdiv##index) const MeshExtract extract_attr[GPU_MAX_ATTR] = { CREATE_EXTRACTOR_ATTR(0), diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc index 2e2444a8e3d..5ee34d7fdb2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edge_fac.cc @@ -25,6 +25,7 @@ #include "GPU_capabilities.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -216,6 +217,86 @@ static void extract_edge_fac_finish(const MeshRenderData *mr, MEM_SAFE_FREE(data->edge_loop_count); } +/* Different function than the one used for the non-subdivision case, as we directly take care of + * the buggy AMD driver case. */ +static GPUVertFormat *get_subdiv_edge_fac_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + if (GPU_crappy_amd_driver()) { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + else { + GPU_vertformat_attr_add(&format, "wd", GPU_COMP_U8, 1, GPU_FETCH_INT_TO_FLOAT_UNIT); + } + } + return &format; +} + +static void extract_edge_fac_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *edge_idx = cache->final.buff.vbo.edge_idx; + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPU_vertbuf_init_build_on_device( + vbo, get_subdiv_edge_fac_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + /* Create a temporary buffer for the edge original indices if it was not requested. */ + const bool has_edge_idx = edge_idx != nullptr; + GPUVertBuf *loop_edge_idx = nullptr; + if (has_edge_idx) { + loop_edge_idx = edge_idx; + } + else { + loop_edge_idx = GPU_vertbuf_calloc(); + draw_subdiv_init_origindex_buffer( + loop_edge_idx, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + 0); + } + + draw_subdiv_build_edge_fac_buffer(subdiv_cache, pos_nor, loop_edge_idx, vbo); + + if (!has_edge_idx) { + GPU_vertbuf_discard(loop_edge_idx); + } +} + +static void extract_edge_fac_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + if (loose_geom->edge_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + /* Make sure buffer is active for sending loose data. */ + GPU_vertbuf_use(vbo); + + uint offset = subdiv_cache->num_subdiv_loops; + for (int i = 0; i < loose_geom->edge_len; i++) { + if (GPU_crappy_amd_driver()) { + float loose_edge_fac[2] = {1.0f, 1.0f}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(float), sizeof(loose_edge_fac), loose_edge_fac); + } + else { + char loose_edge_fac[2] = {255, 255}; + GPU_vertbuf_update_sub(vbo, offset * sizeof(char), sizeof(loose_edge_fac), loose_edge_fac); + } + + offset += 2; + } +} + constexpr MeshExtract create_extractor_edge_fac() { MeshExtract extractor = {nullptr}; @@ -224,6 +305,8 @@ constexpr MeshExtract create_extractor_edge_fac() extractor.iter_poly_mesh = extract_edge_fac_iter_poly_mesh; extractor.iter_ledge_bm = extract_edge_fac_iter_ledge_bm; extractor.iter_ledge_mesh = extract_edge_fac_iter_ledge_mesh; + extractor.init_subdiv = extract_edge_fac_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_fac_loose_geom_subdiv; extractor.finish = extract_edge_fac_finish; extractor.data_type = MR_DATA_POLY_NOR; extractor.data_size = sizeof(MeshExtract_EdgeFac_Data); diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc index 5232346e51e..0b4172dfb28 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edit_data.cc @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -107,19 +109,25 @@ static void mesh_render_data_vert_flag(const MeshRenderData *mr, } } -static void extract_edit_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static GPUVertFormat *get_edit_data_format() { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ GPU_vertformat_attr_add(&format, "data", GPU_COMP_U8, 4, GPU_FETCH_INT); GPU_vertformat_alias_add(&format, "flag"); } - GPU_vertbuf_init_with_format(vbo, &format); + return &format; +} + +static void extract_edit_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_edit_data_format(); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->loop_len + mr->loop_loose_len); EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); *(EditLoopData **)tls_data = vbo_data; @@ -240,6 +248,80 @@ static void extract_edit_data_iter_lvert_mesh(const MeshRenderData *mr, } } +static void extract_edit_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPU_vertbuf_init_with_format(vbo, get_edit_data_format()); + GPU_vertbuf_data_alloc(vbo, subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + EditLoopData *vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); + *(EditLoopData **)data = vbo_data; +} + +static void extract_edit_data_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + EditLoopData *vbo_data = *(EditLoopData **)_data; + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + + EditLoopData *edit_loop_data = &vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + if (vert_origindex != -1) { + const BMVert *eve = bm_original_vert_get(mr, vert_origindex); + if (eve) { + mesh_render_data_vert_flag(mr, eve, edit_loop_data); + } + } + + if (edge_origindex != -1) { + const BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + if (eed) { + mesh_render_data_edge_flag(mr, eed, edit_loop_data); + } + } + + BMFace *efa = bm_original_face_get(mr, poly_origindex); + /* The -1 parameter is for edit_uvs, which we don't do here. */ + mesh_render_data_face_flag(mr, efa, -1, edit_loop_data); + } +} + +static void extract_edit_data_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + const MeshExtractLooseGeom *loose_geom, + void *UNUSED(buffer), + void *_data) +{ + if (loose_geom->edge_len == 0) { + return; + } + + EditLoopData *vbo_data = *(EditLoopData **)_data; + + for (int ledge_index = 0; ledge_index < loose_geom->edge_len; ledge_index++) { + const int offset = subdiv_cache->num_subdiv_loops + ledge_index * 2; + EditLoopData *data = &vbo_data[offset]; + memset(data, 0, sizeof(EditLoopData)); + BMEdge *eed = bm_original_edge_get(mr, loose_geom->edges[ledge_index]); + mesh_render_data_edge_flag(mr, eed, &data[0]); + data[1] = data[0]; + mesh_render_data_vert_flag(mr, eed->v1, &data[0]); + mesh_render_data_vert_flag(mr, eed->v2, &data[1]); + } +} + constexpr MeshExtract create_extractor_edit_data() { MeshExtract extractor = {nullptr}; @@ -250,6 +332,9 @@ constexpr MeshExtract create_extractor_edit_data() extractor.iter_ledge_mesh = extract_edit_data_iter_ledge_mesh; extractor.iter_lvert_bm = extract_edit_data_iter_lvert_bm; extractor.iter_lvert_mesh = extract_edit_data_iter_lvert_mesh; + extractor.init_subdiv = extract_edit_data_init_subdiv; + extractor.iter_subdiv = extract_edit_data_iter_subdiv; + extractor.iter_loose_geom_subdiv = extract_edit_data_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(EditLoopData *); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc index b8494428eed..067d482bc2b 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_data.cc @@ -25,6 +25,8 @@ #include "draw_cache_impl.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -36,12 +38,11 @@ struct MeshExtract_EditUVData_Data { int cd_ofs; }; -static void extract_edituv_data_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static void extract_edituv_data_init_common(const MeshRenderData *mr, + GPUVertBuf *vbo, + MeshExtract_EditUVData_Data *data, + uint loop_len) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { /* WARNING: Adjust #EditLoopData struct accordingly. */ @@ -50,15 +51,23 @@ static void extract_edituv_data_init(const MeshRenderData *mr, } GPU_vertbuf_init_with_format(vbo, &format); - GPU_vertbuf_data_alloc(vbo, mr->loop_len); + GPU_vertbuf_data_alloc(vbo, loop_len); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - - MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); data->vbo_data = (EditLoopData *)GPU_vertbuf_get_data(vbo); data->cd_ofs = CustomData_get_offset(cd_ldata, CD_MLOOPUV); } +static void extract_edituv_data_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, mr->loop_len); +} + static void extract_edituv_data_iter_poly_bm(const MeshRenderData *mr, const BMFace *f, const int UNUSED(f_index), @@ -119,12 +128,54 @@ static void extract_edituv_data_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_edituv_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(tls_data); + extract_edituv_data_init_common(mr, vbo, data, subdiv_cache->num_subdiv_loops); +} + +static void extract_edituv_data_iter_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + void *_data) +{ + MeshExtract_EditUVData_Data *data = static_cast<MeshExtract_EditUVData_Data *>(_data); + int *subdiv_loop_vert_index = (int *)GPU_vertbuf_get_data(subdiv_cache->verts_orig_index); + int *subdiv_loop_edge_index = (int *)GPU_vertbuf_get_data(subdiv_cache->edges_orig_index); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int vert_origindex = subdiv_loop_vert_index[i]; + const int edge_origindex = subdiv_loop_edge_index[i]; + const int poly_origindex = subdiv_loop_poly_index[i]; + + EditLoopData *edit_loop_data = &data->vbo_data[i]; + memset(edit_loop_data, 0, sizeof(EditLoopData)); + + BMFace *efa = bm_original_face_get(mr, poly_origindex); + + if (vert_origindex != -1 && edge_origindex != -1) { + BMEdge *eed = bm_original_edge_get(mr, edge_origindex); + /* Loop on an edge endpoint. */ + BMLoop *l = BM_face_edge_share_loop(efa, eed); + mesh_render_data_loop_flag(mr, l, data->cd_ofs, edit_loop_data); + mesh_render_data_loop_edge_flag(mr, l, data->cd_ofs, edit_loop_data); + } + } +} + constexpr MeshExtract create_extractor_edituv_data() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_data_init; extractor.iter_poly_bm = extract_edituv_data_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_data_iter_poly_mesh; + extractor.init_subdiv = extract_edituv_data_init_subdiv; + extractor.iter_subdiv = extract_edituv_data_iter_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_EditUVData_Data); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc index a947d98f955..0ea4ef5d5db 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_angle.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -213,12 +215,69 @@ static void extract_edituv_stretch_angle_iter_poly_mesh(const MeshRenderData *mr } } +static GPUVertFormat *get_edituv_stretch_angle_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + /* Waning: adjust #UVStretchAngle struct accordingly. */ + GPU_vertformat_attr_add(&format, "angle", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "uv_angles", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + } + return &format; +} + +static void extract_edituv_stretch_angle_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(tls_data)) +{ + GPUVertBuf *refined_vbo = static_cast<GPUVertBuf *>(buffer); + + GPU_vertbuf_init_build_on_device( + refined_vbo, get_edituv_stretch_angle_format_subdiv(), subdiv_cache->num_subdiv_loops); + + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + GPUVertBuf *uvs = cache->final.buff.vbo.uv; + + /* UVs are stored contiguouly so we need to compute the offset in the UVs buffer for the active + * UV layer. */ + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_MESH) ? &mr->me->ldata : &mr->bm->ldata; + + uint32_t uv_layers = cache->cd_used.uv; + /* HACK to fix T68857 */ + if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { + int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); + if (layer != -1) { + uv_layers |= (1 << layer); + } + } + + int uvs_offset = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { + break; + } + + uvs_offset += 1; + } + } + + /* The data is at `offset * num loops`, and we have 2 values per index. */ + uvs_offset *= subdiv_cache->num_subdiv_loops * 2; + + draw_subdiv_build_edituv_stretch_angle_buffer( + subdiv_cache, pos_nor, uvs, uvs_offset, refined_vbo); +} + constexpr MeshExtract create_extractor_edituv_edituv_stretch_angle() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_stretch_angle_init; extractor.iter_poly_bm = extract_edituv_stretch_angle_iter_poly_bm; extractor.iter_poly_mesh = extract_edituv_stretch_angle_iter_poly_mesh; + extractor.init_subdiv = extract_edituv_stretch_angle_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_StretchAngle_Data); extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc index 3db8cd79af5..3b40b3115f5 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_edituv_stretch_area.cc @@ -27,6 +27,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -63,14 +65,12 @@ BLI_INLINE float area_ratio_to_stretch(float ratio, float tot_ratio, float inv_t return (ratio > 1.0f) ? (1.0f / ratio) : ratio; } -static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(data)) +static void compute_area_ratio(const MeshRenderData *mr, + float *r_area_ratio, + float &r_tot_area, + float &r_tot_uv_area) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); float tot_area = 0.0f, tot_uv_area = 0.0f; - float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); if (mr->extract_type == MR_EXTRACT_BMESH) { CustomData *cd_ldata = &mr->bm->ldata; @@ -84,7 +84,7 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float uvarea = BM_face_calc_area_uv(efa, uv_ofs); tot_area += area; tot_uv_area += uvarea; - area_ratio[f] = area_ratio_get(area, uvarea); + r_area_ratio[f] = area_ratio_get(area, uvarea); } } else { @@ -96,12 +96,22 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, float uvarea = BKE_mesh_calc_poly_uv_area(mp, uv_data); tot_area += area; tot_uv_area += uvarea; - area_ratio[mp_index] = area_ratio_get(area, uvarea); + r_area_ratio[mp_index] = area_ratio_get(area, uvarea); } } - cache->tot_area = tot_area; - cache->tot_uv_area = tot_uv_area; + r_tot_area = tot_area; + r_tot_uv_area = tot_uv_area; +} + +static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + float *area_ratio = static_cast<float *>(MEM_mallocN(sizeof(float) * mr->poly_len, __func__)); + compute_area_ratio(mr, area_ratio, cache->tot_area, cache->tot_uv_area); /* Convert in place to avoid an extra allocation */ uint16_t *poly_stretch = (uint16_t *)area_ratio; @@ -135,11 +145,46 @@ static void extract_edituv_stretch_area_finish(const MeshRenderData *mr, MEM_freeN(area_ratio); } +static void extract_edituv_stretch_area_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + + /* Initialise final buffer. */ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "ratio", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + + GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + /* Initialize coarse data buffer. */ + + GPUVertBuf *coarse_data = GPU_vertbuf_calloc(); + + /* We use the same format as we just copy data around. */ + GPU_vertbuf_init_with_format(coarse_data, &format); + GPU_vertbuf_data_alloc(coarse_data, mr->loop_len); + + compute_area_ratio(mr, + static_cast<float *>(GPU_vertbuf_get_data(coarse_data)), + cache->tot_area, + cache->tot_uv_area); + + draw_subdiv_build_edituv_stretch_area_buffer(subdiv_cache, coarse_data, vbo); + + GPU_vertbuf_discard(coarse_data); +} + constexpr MeshExtract create_extractor_edituv_stretch_area() { MeshExtract extractor = {nullptr}; extractor.init = extract_edituv_stretch_area_init; extractor.finish = extract_edituv_stretch_area_finish; + extractor.init_subdiv = extract_edituv_stretch_area_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc index 33f9180e122..f65159f9b95 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_fdots_pos.cc @@ -23,24 +23,40 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ /** \name Extract Face-dots positions * \{ */ -static void extract_fdots_pos_init(const MeshRenderData *mr, - struct MeshBatchCache *UNUSED(cache), - void *buf, - void *tls_data) +static GPUVertFormat *get_fdots_pos_format() { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); static GPUVertFormat format = {0}; if (format.attr_len == 0) { GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); } + return &format; +} + +static GPUVertFormat *get_fdots_nor_format_subdiv() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "norAndFlag", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + } + return &format; +} - GPU_vertbuf_init_with_format(vbo, &format); +static void extract_fdots_pos_init(const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buf, + void *tls_data) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat *format = get_fdots_pos_format(); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->poly_len); void *vbo_data = GPU_vertbuf_get_data(vbo); *(float(**)[3])tls_data = static_cast<float(*)[3]>(vbo_data); @@ -97,10 +113,30 @@ static void extract_fdots_pos_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_fdots_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + /* We "extract" positions, normals, and indices at once. */ + GPUVertBuf *fdots_pos_vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *fdots_nor_vbo = cache->final.buff.vbo.fdots_nor; + GPUIndexBuf *fdots_pos_ibo = cache->final.buff.ibo.fdots; + + GPU_vertbuf_init_build_on_device( + fdots_nor_vbo, get_fdots_nor_format_subdiv(), subdiv_cache->num_coarse_poly); + GPU_vertbuf_init_build_on_device( + fdots_pos_vbo, get_fdots_pos_format(), subdiv_cache->num_coarse_poly); + GPU_indexbuf_init_build_on_device(fdots_pos_ibo, subdiv_cache->num_coarse_poly); + draw_subdiv_build_fdots_buffers(subdiv_cache, fdots_pos_vbo, fdots_nor_vbo, fdots_pos_ibo); +} + constexpr MeshExtract create_extractor_fdots_pos() { MeshExtract extractor = {nullptr}; extractor.init = extract_fdots_pos_init; + extractor.init_subdiv = extract_fdots_init_subdiv; extractor.iter_poly_bm = extract_fdots_pos_iter_poly_bm; extractor.iter_poly_mesh = extract_fdots_pos_iter_poly_mesh; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc index 3c3ac7a7a0a..d30c38ef050 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_lnor.cc @@ -23,6 +23,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -107,10 +109,34 @@ static void extract_lnor_iter_poly_mesh(const MeshRenderData *mr, } } +static GPUVertFormat *get_subdiv_lnor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_lnor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertBuf *pos_nor = cache->final.buff.vbo.pos_nor; + BLI_assert(pos_nor); + GPU_vertbuf_init_build_on_device(vbo, get_subdiv_lnor_format(), subdiv_cache->num_subdiv_loops); + draw_subdiv_build_lnor_buffer(subdiv_cache, pos_nor, vbo); +} + constexpr MeshExtract create_extractor_lnor() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_init; + extractor.init_subdiv = extract_lnor_init_subdiv; extractor.iter_poly_bm = extract_lnor_iter_poly_bm; extractor.iter_poly_mesh = extract_lnor_iter_poly_mesh; extractor.data_type = MR_DATA_LOOP_NOR; @@ -210,6 +236,7 @@ constexpr MeshExtract create_extractor_lnor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_lnor_hq_init; + extractor.init_subdiv = extract_lnor_init_subdiv; extractor.iter_poly_bm = extract_lnor_hq_iter_poly_bm; extractor.iter_poly_mesh = extract_lnor_hq_iter_poly_mesh; extractor.data_type = MR_DATA_LOOP_NOR; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc index eb9a138590c..00ed4ca6359 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_pos_nor.cc @@ -25,6 +25,8 @@ #include "extract_mesh.h" +#include "draw_subdivision.h" + namespace blender::draw { /* ---------------------------------------------------------------------- */ @@ -194,6 +196,123 @@ static void extract_pos_nor_finish(const MeshRenderData *UNUSED(mr), MEM_freeN(data->normals); } +static GPUVertFormat *get_pos_nor_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "vnor"); + } + return &format; +} + +static GPUVertFormat *get_normals_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "nor", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "lnor"); + } + return &format; +} + +static void extract_pos_nor_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const bool do_limit_normals = subdiv_cache->do_limit_normals; + + /* Initialize the vertex buffer, it was already allocated. */ + GPU_vertbuf_init_build_on_device( + vbo, get_pos_nor_format(), subdiv_cache->num_subdiv_loops + mr->loop_loose_len); + + draw_subdiv_extract_pos_nor(subdiv_cache, vbo, do_limit_normals); + + if (!do_limit_normals) { + /* We cannot evaluate vertex normals using the limit surface, so compute them manually. */ + GPUVertBuf *subdiv_loop_subdiv_vert_index = draw_subdiv_build_origindex_buffer( + subdiv_cache->subdiv_loop_subdiv_vert_index, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *vertex_normals = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + vertex_normals, get_normals_format(), subdiv_cache->num_subdiv_verts); + + draw_subdiv_accumulate_normals(subdiv_cache, + vbo, + subdiv_cache->subdiv_vertex_face_adjacency_offsets, + subdiv_cache->subdiv_vertex_face_adjacency, + vertex_normals); + + draw_subdiv_finalize_normals(subdiv_cache, vertex_normals, subdiv_loop_subdiv_vert_index, vbo); + + GPU_vertbuf_discard(vertex_normals); + GPU_vertbuf_discard(subdiv_loop_subdiv_vert_index); + } +} + +static void extract_pos_nor_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + const MVert *coarse_verts = coarse_mesh->mvert; + uint offset = subdiv_cache->num_subdiv_loops; + + /* TODO(kevindietrich) : replace this when compressed normals are supported. */ + struct SubdivPosNorLoop { + float pos[3]; + float nor[3]; + float flag; + }; + + SubdivPosNorLoop edge_data[2]; + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + const MVert *loose_vert1 = &coarse_verts[loose_edge->v1]; + const MVert *loose_vert2 = &coarse_verts[loose_edge->v2]; + + copy_v3_v3(edge_data[0].pos, loose_vert1->co); + normal_short_to_float_v3(edge_data[0].nor, loose_vert1->no); + edge_data[0].flag = 0.0f; + + copy_v3_v3(edge_data[1].pos, loose_vert2->co); + normal_short_to_float_v3(edge_data[1].nor, loose_vert2->no); + edge_data[1].flag = 0.0f; + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop) * 2, &edge_data); + + offset += 2; + } + + SubdivPosNorLoop vert_data; + vert_data.flag = 0.0f; + for (int i = 0; i < loose_geom->vert_len; i++) { + const MVert *loose_vertex = &coarse_verts[loose_geom->verts[i]]; + + copy_v3_v3(vert_data.pos, loose_vertex->co); + normal_short_to_float_v3(vert_data.nor, loose_vertex->no); + + GPU_vertbuf_update_sub( + vbo, offset * sizeof(SubdivPosNorLoop), sizeof(SubdivPosNorLoop), &vert_data); + + offset += 1; + } +} + constexpr MeshExtract create_extractor_pos_nor() { MeshExtract extractor = {nullptr}; @@ -205,6 +324,8 @@ constexpr MeshExtract create_extractor_pos_nor() extractor.iter_lvert_bm = extract_pos_nor_iter_lvert_bm; extractor.iter_lvert_mesh = extract_pos_nor_iter_lvert_mesh; extractor.finish = extract_pos_nor_finish; + extractor.init_subdiv = extract_pos_nor_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_pos_nor_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(MeshExtract_PosNor_Data); extractor.use_threading = true; @@ -391,6 +512,7 @@ constexpr MeshExtract create_extractor_pos_nor_hq() { MeshExtract extractor = {nullptr}; extractor.init = extract_pos_nor_hq_init; + extractor.init_subdiv = extract_pos_nor_init_subdiv; extractor.iter_poly_bm = extract_pos_nor_hq_iter_poly_bm; extractor.iter_poly_mesh = extract_pos_nor_hq_iter_poly_mesh; extractor.iter_ledge_bm = extract_pos_nor_hq_iter_ledge_bm; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc index fd91bc5258f..753fbe7e0e2 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_sculpt_data.cc @@ -27,6 +27,7 @@ #include "BKE_paint.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -35,13 +36,23 @@ namespace blender::draw { /** \name Extract Sculpt Data * \{ */ +static GPUVertFormat *get_sculpt_data_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + return &format; +} + static void extract_sculpt_data_init(const MeshRenderData *mr, struct MeshBatchCache *UNUSED(cache), void *buf, void *UNUSED(tls_data)) { GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; + GPUVertFormat *format = get_sculpt_data_format(); CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; CustomData *cd_vdata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->vdata : &mr->me->vdata; @@ -50,12 +61,7 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "fset", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); - GPU_vertformat_attr_add(&format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); - } - - GPU_vertbuf_init_with_format(vbo, &format); + GPU_vertbuf_init_with_format(vbo, format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); struct gpuSculptData { @@ -121,10 +127,99 @@ static void extract_sculpt_data_init(const MeshRenderData *mr, } } +static void extract_sculpt_data_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + struct MeshBatchCache *UNUSED(cache), + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + Mesh *coarse_mesh = mr->me; + CustomData *cd_vdata = &coarse_mesh->vdata; + CustomData *cd_pdata = &coarse_mesh->pdata; + + /* First, interpolate mask if available. */ + GPUVertBuf *mask_vbo = nullptr; + GPUVertBuf *subdiv_mask_vbo = nullptr; + float *cd_mask = (float *)CustomData_get_layer(cd_vdata, CD_PAINT_MASK); + + if (cd_mask) { + GPUVertFormat mask_format = {0}; + GPU_vertformat_attr_add(&mask_format, "msk", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + + mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(mask_vbo, &mask_format); + GPU_vertbuf_data_alloc(mask_vbo, coarse_mesh->totloop); + float *v_mask = static_cast<float *>(GPU_vertbuf_get_data(mask_vbo)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + *v_mask++ = cd_mask[ml->v]; + } + } + + subdiv_mask_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_build_on_device( + subdiv_mask_vbo, &mask_format, subdiv_cache->num_subdiv_loops); + + draw_subdiv_interp_custom_data(subdiv_cache, mask_vbo, subdiv_mask_vbo, 1, 0); + } + + /* Then, gather face sets. */ + GPUVertFormat face_set_format = {0}; + GPU_vertformat_attr_add(&face_set_format, "msk", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + + GPUVertBuf *face_set_vbo = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(face_set_vbo, &face_set_format); + GPU_vertbuf_data_alloc(face_set_vbo, subdiv_cache->num_subdiv_loops); + + struct gpuFaceSet { + uint8_t color[4]; + }; + + gpuFaceSet *face_sets = (gpuFaceSet *)GPU_vertbuf_get_data(face_set_vbo); + int *cd_face_set = (int *)CustomData_get_layer(cd_pdata, CD_SCULPT_FACE_SETS); + + GPUVertFormat *format = get_sculpt_data_format(); + GPU_vertbuf_init_build_on_device(vbo, format, subdiv_cache->num_subdiv_loops); + int *subdiv_loop_poly_index = subdiv_cache->subdiv_loop_poly_index; + + for (uint i = 0; i < subdiv_cache->num_subdiv_loops; i++) { + const int mp_index = subdiv_loop_poly_index[i]; + + uchar face_set_color[4] = {UCHAR_MAX, UCHAR_MAX, UCHAR_MAX, UCHAR_MAX}; + if (cd_face_set) { + const int face_set_id = cd_face_set[mp_index]; + /* Skip for the default color Face Set to render it white. */ + if (face_set_id != coarse_mesh->face_sets_color_default) { + BKE_paint_face_set_overlay_color_get( + face_set_id, coarse_mesh->face_sets_color_seed, face_set_color); + } + } + copy_v3_v3_uchar(face_sets->color, face_set_color); + face_sets++; + } + + /* Finally, interleave mask and face sets. */ + draw_subdiv_build_sculpt_data_buffer(subdiv_cache, subdiv_mask_vbo, face_set_vbo, vbo); + + if (mask_vbo) { + GPU_vertbuf_discard(mask_vbo); + GPU_vertbuf_discard(subdiv_mask_vbo); + } + GPU_vertbuf_discard(face_set_vbo); +} + constexpr MeshExtract create_extractor_sculpt_data() { MeshExtract extractor = {nullptr}; extractor.init = extract_sculpt_data_init; + extractor.init_subdiv = extract_sculpt_data_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc index 5ac30dd3be9..33c27b45627 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_select_idx.cc @@ -21,6 +21,7 @@ * \ingroup draw */ +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -196,12 +197,104 @@ static void extract_vert_idx_iter_lvert_mesh(const MeshRenderData *mr, (*(uint32_t **)data)[offset + lvert_index] = v_orig; } +static void extract_vert_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + /* Each element points to an element in the ibo.points. */ + draw_subdiv_init_origindex_buffer(vbo, + subdiv_cache->subdiv_loop_subdiv_vert_index, + subdiv_cache->num_subdiv_loops, + mr->loop_loose_len); +} + +static void extract_vert_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + const Mesh *coarse_mesh = subdiv_cache->mesh; + const MEdge *coarse_edges = coarse_mesh->medge; + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + const MEdge *loose_edge = &coarse_edges[loose_geom->edges[i]]; + vert_idx_data[offset] = loose_edge->v1; + vert_idx_data[offset + 1] = loose_edge->v2; + offset += 2; + } + + for (int i = 0; i < loose_geom->vert_len; i++) { + vert_idx_data[offset] = loose_geom->verts[i]; + offset += 1; + } +} + +static void extract_edge_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *mr, + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, + static_cast<int *>(GPU_vertbuf_get_data(subdiv_cache->edges_orig_index)), + subdiv_cache->num_subdiv_loops, + mr->edge_loose_len * 2); +} + +static void extract_edge_idx_loose_geom_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + const MeshExtractLooseGeom *loose_geom, + void *buffer, + void *UNUSED(data)) +{ + const int loop_loose_len = loose_geom->edge_len + loose_geom->vert_len; + if (loop_loose_len == 0) { + return; + } + + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + uint *vert_idx_data = (uint *)GPU_vertbuf_get_data(vbo); + uint offset = subdiv_cache->num_subdiv_loops; + + for (int i = 0; i < loose_geom->edge_len; i++) { + vert_idx_data[offset] = loose_geom->edges[i]; + vert_idx_data[offset + 1] = loose_geom->edges[i]; + offset += 2; + } +} + +static void extract_poly_idx_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + MeshBatchCache *UNUSED(cache), + void *buf, + void *UNUSED(data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + draw_subdiv_init_origindex_buffer( + vbo, subdiv_cache->subdiv_loop_poly_index, subdiv_cache->num_subdiv_loops, 0); +} + constexpr MeshExtract create_extractor_poly_idx() { MeshExtract extractor = {nullptr}; extractor.init = extract_select_idx_init; extractor.iter_poly_bm = extract_poly_idx_iter_poly_bm; extractor.iter_poly_mesh = extract_poly_idx_iter_poly_mesh; + extractor.init_subdiv = extract_poly_idx_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -217,6 +310,8 @@ constexpr MeshExtract create_extractor_edge_idx() extractor.iter_poly_mesh = extract_edge_idx_iter_poly_mesh; extractor.iter_ledge_bm = extract_edge_idx_iter_ledge_bm; extractor.iter_ledge_mesh = extract_edge_idx_iter_ledge_mesh; + extractor.init_subdiv = extract_edge_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_edge_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; @@ -234,6 +329,8 @@ constexpr MeshExtract create_extractor_vert_idx() extractor.iter_ledge_mesh = extract_vert_idx_iter_ledge_mesh; extractor.iter_lvert_bm = extract_vert_idx_iter_lvert_bm; extractor.iter_lvert_mesh = extract_vert_idx_iter_lvert_mesh; + extractor.init_subdiv = extract_vert_idx_init_subdiv; + extractor.iter_loose_geom_subdiv = extract_vert_idx_loose_geom_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = sizeof(uint32_t *); extractor.use_threading = true; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc index af279b08a59..6e9d8ef6926 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_uv.cc @@ -23,6 +23,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -31,25 +32,27 @@ namespace blender::draw { /** \name Extract UV layers * \{ */ -static void extract_uv_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the vertex format to be used for UVs. Return true if any UV layer is + * found, false otherwise. */ +static bool mesh_extract_uv_format_init(GPUVertFormat *format, + struct MeshBatchCache *cache, + CustomData *cd_ldata, + eMRExtractType extract_type, + uint32_t &r_uv_layers) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + GPU_vertformat_deinterleave(format); - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; uint32_t uv_layers = cache->cd_used.uv; /* HACK to fix T68857 */ - if (mr->extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { + if (extract_type == MR_EXTRACT_BMESH && cache->cd_used.edit_uv == 1) { int layer = CustomData_get_active_layer(cd_ldata, CD_MLOOPUV); if (layer != -1) { uv_layers |= (1 << layer); } } + r_uv_layers = uv_layers; + for (int i = 0; i < MAX_MTFACE; i++) { if (uv_layers & (1 << i)) { char attr_name[32], attr_safe_name[GPU_MAX_SAFE_ATTR_NAME]; @@ -58,30 +61,47 @@ static void extract_uv_init(const MeshRenderData *mr, GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); /* UV layer name. */ BLI_snprintf(attr_name, sizeof(attr_name), "u%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_vertformat_attr_add(format, attr_name, GPU_COMP_F32, 2, GPU_FETCH_FLOAT); /* Auto layer name. */ BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); + GPU_vertformat_alias_add(format, attr_name); /* Active render layer name. */ if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "u"); + GPU_vertformat_alias_add(format, "u"); } /* Active display layer name. */ if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "au"); + GPU_vertformat_alias_add(format, "au"); /* Alias to `pos` for edit uvs. */ - GPU_vertformat_alias_add(&format, "pos"); + GPU_vertformat_alias_add(format, "pos"); } /* Stencil mask uv layer name. */ if (i == CustomData_get_stencil_layer(cd_ldata, CD_MLOOPUV)) { - GPU_vertformat_alias_add(&format, "mu"); + GPU_vertformat_alias_add(format, "mu"); } } } + if (format->attr_len == 0) { + GPU_vertformat_attr_add(format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + return false; + } + + return true; +} + +static void extract_uv_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; int v_len = mr->loop_len; - if (format.attr_len == 0) { - GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + uint32_t uv_layers = cache->cd_used.uv; + if (!mesh_extract_uv_format_init(&format, cache, cd_ldata, mr->extract_type, uv_layers)) { /* VBO will not be used, only allocate minimum of memory. */ v_len = 1; } @@ -116,10 +136,45 @@ static void extract_uv_init(const MeshRenderData *mr, } } +static void extract_uv_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + GPUVertFormat format = {0}; + + uint v_len = subdiv_cache->num_subdiv_loops; + uint uv_layers; + if (!mesh_extract_uv_format_init( + &format, cache, &coarse_mesh->ldata, MR_EXTRACT_MESH, uv_layers)) { + // TODO(kevindietrich): handle this more gracefully. + v_len = 1; + } + + GPU_vertbuf_init_build_on_device(vbo, &format, v_len); + + if (uv_layers == 0) { + return; + } + + /* Index of the UV layer in the compact buffer. Used UV layers are stored in a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (uv_layers & (1 << i)) { + const int offset = (int)subdiv_cache->num_subdiv_loops * pack_layer_index++; + draw_subdiv_extract_uvs(subdiv_cache, vbo, i, offset); + } + } +} + constexpr MeshExtract create_extractor_uv() { MeshExtract extractor = {nullptr}; extractor.init = extract_uv_init; + extractor.init_subdiv = extract_uv_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc index f8878eb2617..a0307b9b2cd 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_vcol.cc @@ -25,6 +25,7 @@ #include "BLI_string.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -33,17 +34,14 @@ namespace blender::draw { /** \name Extract VCol * \{ */ -static void extract_vcol_init(const MeshRenderData *mr, - struct MeshBatchCache *cache, - void *buf, - void *UNUSED(tls_data)) +/* Initialize the common vertex format for vcol for coarse and subdivided meshes. */ +static void init_vcol_format(GPUVertFormat *format, + const MeshBatchCache *cache, + CustomData *cd_ldata) { - GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); - GPUVertFormat format = {0}; - GPU_vertformat_deinterleave(&format); + GPU_vertformat_deinterleave(format); - CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; - uint32_t vcol_layers = cache->cd_used.vcol; + const uint32_t vcol_layers = cache->cd_used.vcol; for (int i = 0; i < MAX_MCOL; i++) { if (vcol_layers & (1 << i)) { @@ -52,31 +50,56 @@ static void extract_vcol_init(const MeshRenderData *mr, GPU_vertformat_safe_attr_name(layer_name, attr_safe_name, GPU_MAX_SAFE_ATTR_NAME); BLI_snprintf(attr_name, sizeof(attr_name), "c%s", attr_safe_name); - GPU_vertformat_attr_add(&format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); + GPU_vertformat_attr_add(format, attr_name, GPU_COMP_U16, 4, GPU_FETCH_INT_TO_FLOAT_UNIT); if (i == CustomData_get_render_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "c"); + GPU_vertformat_alias_add(format, "c"); } if (i == CustomData_get_active_layer(cd_ldata, CD_MLOOPCOL)) { - GPU_vertformat_alias_add(&format, "ac"); + GPU_vertformat_alias_add(format, "ac"); } /* Gather number of auto layers. */ /* We only do `vcols` that are not overridden by `uvs`. */ if (CustomData_get_named_layer_index(cd_ldata, CD_MLOOPUV, layer_name) == -1) { BLI_snprintf(attr_name, sizeof(attr_name), "a%s", attr_safe_name); - GPU_vertformat_alias_add(&format, attr_name); + GPU_vertformat_alias_add(format, attr_name); } } } +} + +/* Vertex format for vertex colors, only used during the coarse data upload for the subdivision + * case. */ +static GPUVertFormat *get_coarse_vcol_format() +{ + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "cCol", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + GPU_vertformat_alias_add(&format, "c"); + GPU_vertformat_alias_add(&format, "ac"); + } + return &format; +} + +using gpuMeshVcol = struct gpuMeshVcol { + ushort r, g, b, a; +}; + +static void extract_vcol_init(const MeshRenderData *mr, + struct MeshBatchCache *cache, + void *buf, + void *UNUSED(tls_data)) +{ + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buf); + GPUVertFormat format = {0}; + CustomData *cd_ldata = (mr->extract_type == MR_EXTRACT_BMESH) ? &mr->bm->ldata : &mr->me->ldata; + const uint32_t vcol_layers = cache->cd_used.vcol; + init_vcol_format(&format, cache, cd_ldata); GPU_vertbuf_init_with_format(vbo, &format); GPU_vertbuf_data_alloc(vbo, mr->loop_len); - using gpuMeshVcol = struct gpuMeshVcol { - ushort r, g, b, a; - }; - gpuMeshVcol *vcol_data = (gpuMeshVcol *)GPU_vertbuf_get_data(vbo); for (int i = 0; i < MAX_MCOL; i++) { @@ -111,10 +134,64 @@ static void extract_vcol_init(const MeshRenderData *mr, } } +static void extract_vcol_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + GPUVertBuf *dst_buffer = static_cast<GPUVertBuf *>(buffer); + Mesh *coarse_mesh = subdiv_cache->mesh; + + GPUVertFormat format = {0}; + init_vcol_format(&format, cache, &coarse_mesh->ldata); + + GPU_vertbuf_init_build_on_device(dst_buffer, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *src_data = GPU_vertbuf_calloc(); + /* Dynamic as we upload and interpolate layers one at a time. */ + GPU_vertbuf_init_with_format_ex(src_data, get_coarse_vcol_format(), GPU_USAGE_DYNAMIC); + + GPU_vertbuf_data_alloc(src_data, coarse_mesh->totloop); + + gpuMeshVcol *mesh_vcol = (gpuMeshVcol *)GPU_vertbuf_get_data(src_data); + + const CustomData *cd_ldata = &coarse_mesh->ldata; + + const uint vcol_layers = cache->cd_used.vcol; + + /* Index of the vertex color layer in the compact buffer. Used vertex color layers are stored in + * a single buffer. */ + int pack_layer_index = 0; + for (int i = 0; i < MAX_MTFACE; i++) { + if (vcol_layers & (1 << i)) { + /* Include stride in offset, we use a stride of 2 since colors are packed into 2 uints. */ + const int dst_offset = (int)subdiv_cache->num_subdiv_loops * 2 * pack_layer_index++; + const MLoopCol *mloopcol = (MLoopCol *)CustomData_get_layer_n(cd_ldata, CD_MLOOPCOL, i); + + gpuMeshVcol *vcol = mesh_vcol; + + for (int ml_index = 0; ml_index < coarse_mesh->totloop; ml_index++, vcol++, mloopcol++) { + vcol->r = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->r]); + vcol->g = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->g]); + vcol->b = unit_float_to_ushort_clamp(BLI_color_from_srgb_table[mloopcol->b]); + vcol->a = unit_float_to_ushort_clamp(mloopcol->a * (1.0f / 255.0f)); + } + + /* Ensure data is uploaded properly. */ + GPU_vertbuf_tag_dirty(src_data); + draw_subdiv_interp_custom_data(subdiv_cache, src_data, dst_buffer, 4, dst_offset); + } + } + + GPU_vertbuf_discard(src_data); +} + constexpr MeshExtract create_extractor_vcol() { MeshExtract extractor = {nullptr}; extractor.init = extract_vcol_init; + extractor.init_subdiv = extract_vcol_init_subdiv; extractor.data_type = MR_DATA_NONE; extractor.data_size = 0; extractor.use_threading = false; diff --git a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc index bdb1410a755..bb8853b8154 100644 --- a/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc +++ b/source/blender/draw/intern/mesh_extractors/extract_mesh_vbo_weights.cc @@ -25,6 +25,7 @@ #include "BKE_deform.h" +#include "draw_subdivision.h" #include "extract_mesh.h" namespace blender::draw { @@ -167,10 +168,57 @@ static void extract_weights_iter_poly_mesh(const MeshRenderData *mr, } } +static void extract_weights_init_subdiv(const DRWSubdivCache *subdiv_cache, + const MeshRenderData *UNUSED(mr), + struct MeshBatchCache *cache, + void *buffer, + void *UNUSED(data)) +{ + Mesh *coarse_mesh = subdiv_cache->mesh; + GPUVertBuf *vbo = static_cast<GPUVertBuf *>(buffer); + + static GPUVertFormat format = {0}; + if (format.attr_len == 0) { + GPU_vertformat_attr_add(&format, "weight", GPU_COMP_F32, 1, GPU_FETCH_FLOAT); + } + GPU_vertbuf_init_build_on_device(vbo, &format, subdiv_cache->num_subdiv_loops); + + GPUVertBuf *coarse_weights = GPU_vertbuf_calloc(); + GPU_vertbuf_init_with_format(coarse_weights, &format); + GPU_vertbuf_data_alloc(coarse_weights, coarse_mesh->totloop); + float *coarse_weights_data = static_cast<float *>(GPU_vertbuf_get_data(coarse_weights)); + + const DRW_MeshWeightState *wstate = &cache->weight_state; + const MDeformVert *dverts = static_cast<const MDeformVert *>( + CustomData_get_layer(&coarse_mesh->vdata, CD_MDEFORMVERT)); + + for (int i = 0; i < coarse_mesh->totpoly; i++) { + const MPoly *mpoly = &coarse_mesh->mpoly[i]; + + for (int loop_index = mpoly->loopstart; loop_index < mpoly->loopstart + mpoly->totloop; + loop_index++) { + const MLoop *ml = &coarse_mesh->mloop[loop_index]; + + if (dverts != nullptr) { + const MDeformVert *dvert = &dverts[ml->v]; + coarse_weights_data[loop_index] = evaluate_vertex_weight(dvert, wstate); + } + else { + coarse_weights_data[loop_index] = evaluate_vertex_weight(nullptr, wstate); + } + } + } + + draw_subdiv_interp_custom_data(subdiv_cache, coarse_weights, vbo, 1, 0); + + GPU_vertbuf_discard(coarse_weights); +} + constexpr MeshExtract create_extractor_weights() { MeshExtract extractor = {nullptr}; extractor.init = extract_weights_init; + extractor.init_subdiv = extract_weights_init_subdiv; extractor.iter_poly_bm = extract_weights_iter_poly_bm; extractor.iter_poly_mesh = extract_weights_iter_poly_mesh; extractor.data_type = MR_DATA_NONE; diff --git a/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl new file mode 100644 index 00000000000..36c3970d9a0 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_custom_data_interp_comp.glsl @@ -0,0 +1,230 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly restrict buffer sourceBuffer +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint src_data[]; +#else + float src_data[]; +#endif +}; + +layout(std430, binding = 2) readonly restrict buffer facePTexOffset +{ + uint face_ptex_offset[]; +}; + +layout(std430, binding = 3) readonly restrict buffer patchCoords +{ + BlenderPatchCoord patch_coords[]; +}; + +layout(std430, binding = 4) readonly restrict buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; + +layout(std430, binding = 5) writeonly restrict buffer destBuffer +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint dst_data[]; +#else + float dst_data[]; +#endif +}; + +struct Vertex { + float vertex_data[DIMENSIONS]; +}; + +void clear(inout Vertex v) +{ + for (int i = 0; i < DIMENSIONS; i++) { + v.vertex_data[i] = 0.0; + } +} + +Vertex read_vertex(uint index) +{ + Vertex result; +#ifdef GPU_FETCH_U16_TO_FLOAT + uint base_index = index * 2; + if (DIMENSIONS == 4) { + uint xy = src_data[base_index]; + uint zw = src_data[base_index + 1]; + + float x = float((xy >> 16) & 0xffff) / 65535.0; + float y = float(xy & 0xffff) / 65535.0; + float z = float((zw >> 16) & 0xffff) / 65535.0; + float w = float(zw & 0xffff) / 65535.0; + + result.vertex_data[0] = x; + result.vertex_data[1] = y; + result.vertex_data[2] = z; + result.vertex_data[3] = w; + } + else { + /* This case is unsupported for now. */ + clear(result); + } +#else + uint base_index = index * DIMENSIONS; + for (int i = 0; i < DIMENSIONS; i++) { + result.vertex_data[i] = src_data[base_index + i]; + } +#endif + return result; +} + +void write_vertex(uint index, Vertex v) +{ +#ifdef GPU_FETCH_U16_TO_FLOAT + uint base_index = dst_offset + index * 2; + if (DIMENSIONS == 4) { + uint x = uint(v.vertex_data[0] * 65535.0); + uint y = uint(v.vertex_data[1] * 65535.0); + uint z = uint(v.vertex_data[2] * 65535.0); + uint w = uint(v.vertex_data[3] * 65535.0); + + uint xy = x << 16 | y; + uint zw = z << 16 | w; + + dst_data[base_index] = xy; + dst_data[base_index + 1] = zw; + } + else { + /* This case is unsupported for now. */ + dst_data[base_index] = 0; + } +#else + uint base_index = dst_offset + index * DIMENSIONS; + for (int i = 0; i < DIMENSIONS; i++) { + dst_data[base_index + i] = v.vertex_data[i]; + } +#endif +} + +Vertex interp_vertex(Vertex v0, Vertex v1, Vertex v2, Vertex v3, vec2 uv) +{ + Vertex result; + for (int i = 0; i < DIMENSIONS; i++) { + float e = mix(v0.vertex_data[i], v1.vertex_data[i], uv.x); + float f = mix(v2.vertex_data[i], v3.vertex_data[i], uv.x); + result.vertex_data[i] = mix(e, f, uv.y); + } + return result; +} + +void add_with_weight(inout Vertex v0, Vertex v1, float weight) +{ + for (int i = 0; i < DIMENSIONS; i++) { + v0.vertex_data[i] += v1.vertex_data[i] * weight; + } +} + +Vertex average(Vertex v0, Vertex v1) +{ + Vertex result; + for (int i = 0; i < DIMENSIONS; i++) { + result.vertex_data[i] = (v0.vertex_data[i] + v1.vertex_data[i]) * 0.5; + } + return result; +} + +uint get_vertex_count(uint coarse_polygon) +{ + uint number_of_patches = face_ptex_offset[coarse_polygon + 1] - face_ptex_offset[coarse_polygon]; + if (number_of_patches == 1) { + /* If there is only one patch for the current coarse polygon, then it is a quad. */ + return 4; + } + /* Otherwise, the number of patches is the number of vertices. */ + return number_of_patches; +} + +uint get_polygon_corner_index(uint coarse_polygon, uint patch_index) +{ + uint patch_offset = face_ptex_offset[coarse_polygon]; + return patch_index - patch_offset; +} + +uint get_loop_start(uint coarse_polygon) +{ + return extra_coarse_face_data[coarse_polygon] & coarse_face_loopstart_mask; +} + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + /* Find which coarse polygon we came from. */ + uint coarse_polygon = coarse_polygon_index_from_subdiv_quad_index(quad_index, coarse_poly_count); + uint loop_start = get_loop_start(coarse_polygon); + + /* Find the number of vertices for the coarse polygon. */ + Vertex v0, v1, v2, v3; + clear(v0); + clear(v1); + clear(v2); + clear(v3); + + uint number_of_vertices = get_vertex_count(coarse_polygon); + if (number_of_vertices == 4) { + /* Interpolate the src data. */ + v0 = read_vertex(loop_start + 0); + v1 = read_vertex(loop_start + 1); + v2 = read_vertex(loop_start + 2); + v3 = read_vertex(loop_start + 3); + } + else { + /* Interpolate the src data for the center. */ + uint loop_end = loop_start + number_of_vertices - 1; + Vertex center_value; + clear(center_value); + + float weight = 1.0 / float(number_of_vertices); + + for (uint l = loop_start; l < loop_end; l++) { + add_with_weight(center_value, read_vertex(l), weight); + } + + /* Interpolate between the previous and next corner for the middle values for the edges. */ + uint patch_index = uint(patch_coords[start_loop_index].patch_index); + uint current_coarse_corner = get_polygon_corner_index(coarse_polygon, patch_index); + uint next_coarse_corner = (current_coarse_corner + 1) % number_of_vertices; + uint prev_coarse_corner = (current_coarse_corner + number_of_vertices - 1) % + number_of_vertices; + + v0 = read_vertex(loop_start); + v1 = average(v0, read_vertex(loop_start + next_coarse_corner)); + v3 = average(v0, read_vertex(loop_start + prev_coarse_corner)); + + /* Interpolate between the current value, and the ones for the center and mid-edges. */ + v2 = center_value; + } + + /* Do a linear interpolation of the data based on the UVs for each loop of this subdivided quad. + */ + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + BlenderPatchCoord co = patch_coords[loop_index]; + vec2 uv = decode_uv(co.encoded_uv); + /* NOTE: v2 and v3 are reversed to stay consistent with the interpolation weight on the x-axis: + * + * v3 +-----+ v2 + * | | + * | | + * v0 +-----+ v1 + * + * otherwise, weight would be `1.0 - uv.x` for `v2 <-> v3`, but `uv.x` for `v0 <-> v1`. + */ + Vertex result = interp_vertex(v0, v1, v3, v2, uv); + write_vertex(loop_index, result); + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl new file mode 100644 index 00000000000..f11c0f6427e --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_lines_comp.glsl @@ -0,0 +1,57 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputEdgeOrigIndex +{ + int input_origindex[]; +}; + +layout(std430, binding = 1) writeonly buffer outputLinesIndices +{ + uint output_lines[]; +}; + +#ifndef LINES_LOOSE +void emit_line(uint line_offset, uint start_loop_index, uint corner_index) +{ + uint vertex_index = start_loop_index + corner_index; + + if (input_origindex[vertex_index] == ORIGINDEX_NONE && optimal_display) { + output_lines[line_offset + 0] = 0xffffffff; + output_lines[line_offset + 1] = 0xffffffff; + } + else { + /* Mod 4 so we loop back at the first vertex on the last loop index (3). */ + uint next_vertex_index = start_loop_index + (corner_index + 1) % 4; + + output_lines[line_offset + 0] = vertex_index; + output_lines[line_offset + 1] = next_vertex_index; + } +} +#endif + +void main() +{ + uint index = get_global_invocation_index(); + if (index >= total_dispatch_size) { + return; + } + +#ifdef LINES_LOOSE + /* In the loose lines case, we execute for each line, with two vertices per line. */ + uint line_offset = edge_loose_offset + index * 2; + uint loop_index = num_subdiv_loops + index * 2; + output_lines[line_offset] = loop_index; + output_lines[line_offset + 1] = loop_index + 1; +#else + /* We execute for each quad, so the start index of the loop is quad_index * 4. */ + uint start_loop_index = index * 4; + /* We execute for each quad, so the start index of the line is quad_index * 8 (with 2 vertices + * per line). */ + uint start_line_index = index * 8; + + for (int i = 0; i < 4; i++) { + emit_line(start_line_index + i * 2, start_loop_index, i); + } +#endif +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl new file mode 100644 index 00000000000..3257ebdae17 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_ibo_tris_comp.glsl @@ -0,0 +1,43 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +/* Generate triangles from subdivision quads indices. */ + +layout(std430, binding = 1) writeonly buffer outputTriangles +{ + uint output_tris[]; +}; + +#ifndef SINGLE_MATERIAL +layout(std430, binding = 2) readonly buffer inputPolygonMatOffset +{ + int polygon_mat_offset[]; +}; +#endif + +void main() +{ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint loop_index = quad_index * 4; + +#ifdef SINGLE_MATERIAL + uint triangle_loop_index = quad_index * 6; +#else + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + int mat_offset = polygon_mat_offset[coarse_quad_index]; + + int triangle_loop_index = (int(quad_index) + mat_offset) * 6; +#endif + + output_tris[triangle_loop_index + 0] = loop_index + 0; + output_tris[triangle_loop_index + 1] = loop_index + 1; + output_tris[triangle_loop_index + 2] = loop_index + 2; + output_tris[triangle_loop_index + 3] = loop_index + 0; + output_tris[triangle_loop_index + 4] = loop_index + 2; + output_tris[triangle_loop_index + 5] = loop_index + 3; +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_lib.glsl b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl new file mode 100644 index 00000000000..005561964b8 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_lib.glsl @@ -0,0 +1,176 @@ + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +/* Uniform block for #DRWSubivUboStorage. */ +layout(std140) uniform shader_data +{ + /* Offsets in the buffers data where the source and destination data start. */ + int src_offset; + int dst_offset; + + /* Parameters for the DRWPatchMap. */ + int min_patch_face; + int max_patch_face; + int max_depth; + int patches_are_triangular; + + /* Coarse topology information. */ + int coarse_poly_count; + uint edge_loose_offset; + + /* Subdiv topology information. */ + uint num_subdiv_loops; + + /* Subdivision settings. */ + bool optimal_display; + + /* Sculpt data. */ + bool has_sculpt_mask; + + /* Masks for the extra coarse face data. */ + uint coarse_face_select_mask; + uint coarse_face_smooth_mask; + uint coarse_face_active_mask; + uint coarse_face_loopstart_mask; + + /* Total number of elements to process. */ + uint total_dispatch_size; +}; + +uint get_global_invocation_index() +{ + uint invocations_per_row = gl_WorkGroupSize.x * gl_NumWorkGroups.x; + return gl_GlobalInvocationID.x + gl_GlobalInvocationID.y * invocations_per_row; +} + +/* Structure for #CompressedPatchCoord. */ +struct BlenderPatchCoord { + int patch_index; + uint encoded_uv; +}; + +vec2 decode_uv(uint encoded_uv) +{ + float u = float((encoded_uv >> 16) & 0xFFFFu) / 65535.0; + float v = float(encoded_uv & 0xFFFFu) / 65535.0; + return vec2(u, v); +} + +/* This structure is a carbon copy of OpenSubDiv's PatchTable::PatchHandle. */ +struct PatchHandle { + int array_index; + int patch_index; + int vertex_index; +}; + +/* This structure is a carbon copy of OpenSubDiv's PatchCoord. */ +struct PatchCoord { + int array_index; + int patch_index; + int vertex_index; + float u; + float v; +}; + +/* This structure is a carbon copy of OpenSubDiv's PatchCoord.QuadNode. + * Each child is a bitfield. */ +struct QuadNode { + uvec4 child; +}; + +bool is_set(uint i) +{ + /* QuadNode.Child.isSet is the first bit of the bitfield. */ + return (i & 0x1u) != 0; +} + +bool is_leaf(uint i) +{ + /* QuadNode.Child.isLeaf is the second bit of the bitfield. */ + return (i & 0x2u) != 0; +} + +uint get_index(uint i) +{ + /* QuadNode.Child.index is made of the remaining bits. */ + return (i >> 2) & 0x3FFFFFFFu; +} + +/* Duplicate of #PosNorLoop from the mesh extract CPU code. + * We do not use a vec3 for the position as it will be padded to a vec4 which is incompatible with + * the format. */ +struct PosNorLoop { + float x, y, z; + /* TODO(kevindietrich) : figure how to compress properly as GLSL does not have char/short types, + * bit operations get tricky. */ + float nx, ny, nz; + float flag; +}; + +vec3 get_vertex_pos(PosNorLoop vertex_data) +{ + return vec3(vertex_data.x, vertex_data.y, vertex_data.z); +} + +vec3 get_vertex_nor(PosNorLoop vertex_data) +{ + return vec3(vertex_data.nx, vertex_data.ny, vertex_data.nz); +} + +void set_vertex_pos(inout PosNorLoop vertex_data, vec3 pos) +{ + vertex_data.x = pos.x; + vertex_data.y = pos.y; + vertex_data.z = pos.z; +} + +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor, uint flag) +{ + vertex_data.nx = nor.x; + vertex_data.ny = nor.y; + vertex_data.nz = nor.z; + vertex_data.flag = float(flag); +} + +/* Set the vertex normal but preserve the existing flag. This is for when we compute manually the + * vertex normals when we cannot use the limit surface, in which case the flag and the normal are + * set by two separate compute pass. */ +void set_vertex_nor(inout PosNorLoop vertex_data, vec3 nor) +{ + set_vertex_nor(vertex_data, nor, 0); +} + +#define ORIGINDEX_NONE -1 + +#ifdef SUBDIV_POLYGON_OFFSET +layout(std430, binding = 0) readonly buffer inputSubdivPolygonOffset +{ + uint subdiv_polygon_offset[]; +}; + +/* Given the index of the subdivision quad, return the index of the corresponding coarse polygon. + * This uses subdiv_polygon_offset and since it is a growing list of offsets, we can use binary + * search to locate the right index. */ +uint coarse_polygon_index_from_subdiv_quad_index(uint subdiv_quad_index, uint coarse_poly_count) +{ + uint first = 0; + uint last = coarse_poly_count; + + while (first != last) { + uint middle = (first + last) / 2; + + if (subdiv_polygon_offset[middle] < subdiv_quad_index) { + first = middle + 1; + } + else { + last = middle; + } + } + + if (subdiv_polygon_offset[first] == subdiv_quad_index) { + return first; + } + + return first - 1; +} +#endif diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl new file mode 100644 index 00000000000..575090472b1 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_normals_accumulate_comp.glsl @@ -0,0 +1,56 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer faceAdjacencyOffsets +{ + uint face_adjacency_offsets[]; +}; + +layout(std430, binding = 2) readonly buffer faceAdjacencyLists +{ + uint face_adjacency_lists[]; +}; + +layout(std430, binding = 3) writeonly buffer vertexNormals +{ + vec3 normals[]; +}; + +void main() +{ + uint vertex_index = get_global_invocation_index(); + if (vertex_index >= total_dispatch_size) { + return; + } + + uint first_adjacent_face_offset = face_adjacency_offsets[vertex_index]; + uint number_of_adjacent_faces = face_adjacency_offsets[vertex_index + 1] - + first_adjacent_face_offset; + + vec3 accumulated_normal = vec3(0.0); + + /* For each adjacent face. */ + for (uint i = 0; i < number_of_adjacent_faces; i++) { + uint adjacent_face = face_adjacency_lists[first_adjacent_face_offset + i]; + uint start_loop_index = adjacent_face * 4; + + /* Compute face normal. */ + vec3 adjacent_verts[3]; + for (uint j = 0; j < 3; j++) { + adjacent_verts[j] = get_vertex_pos(pos_nor[start_loop_index + j]); + } + + vec3 face_normal = normalize( + cross(adjacent_verts[1] - adjacent_verts[0], adjacent_verts[2] - adjacent_verts[0])); + accumulated_normal += face_normal; + } + + float weight = 1.0 / float(number_of_adjacent_faces); + vec3 normal = normalize(accumulated_normal); + normals[vertex_index] = normal; +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl new file mode 100644 index 00000000000..84cd65d4161 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_normals_finalize_comp.glsl @@ -0,0 +1,34 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputNormals +{ + vec3 vertex_normals[]; +}; + +layout(std430, binding = 1) readonly buffer inputSubdivVertLoopMap +{ + uint vert_loop_map[]; +}; + +layout(std430, binding = 2) buffer outputPosNor +{ + PosNorLoop pos_nor[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (int i = 0; i < 4; i++) { + uint subdiv_vert_index = vert_loop_map[start_loop_index + i]; + vec3 nor = vertex_normals[subdiv_vert_index]; + set_vertex_nor(pos_nor[start_loop_index + i], nor); + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl new file mode 100644 index 00000000000..5dd7decf663 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_patch_evaluation_comp.glsl @@ -0,0 +1,416 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +/* Source buffer. */ +layout(std430, binding = 0) buffer src_buffer +{ + float srcVertexBuffer[]; +}; + +/* #DRWPatchMap */ +layout(std430, binding = 1) readonly buffer inputPatchHandles +{ + PatchHandle input_patch_handles[]; +}; + +layout(std430, binding = 2) readonly buffer inputQuadNodes +{ + QuadNode quad_nodes[]; +}; + +layout(std430, binding = 3) readonly buffer inputPatchCoords +{ + BlenderPatchCoord patch_coords[]; +}; + +layout(std430, binding = 4) readonly buffer inputVertOrigIndices +{ + int input_vert_origindex[]; +}; + +/* Patch buffers. */ +layout(std430, binding = 5) buffer patchArray_buffer +{ + OsdPatchArray patchArrayBuffer[]; +}; + +layout(std430, binding = 6) buffer patchIndex_buffer +{ + int patchIndexBuffer[]; +}; + +layout(std430, binding = 7) buffer patchParam_buffer +{ + OsdPatchParam patchParamBuffer[]; +}; + + /* Output buffer(s). */ + +#if defined(FVAR_EVALUATION) +layout(std430, binding = 8) writeonly buffer outputFVarData +{ + vec2 output_fvar[]; +}; +#elif defined(FDOTS_EVALUATION) +/* For face dots, we build the position, normals, and index buffers in one go. */ + +/* vec3 is padded to vec4, but the format used for fdots does not have any padding. */ +struct FDotVert { + float x, y, z; +}; + +/* Same here, do not use vec3. */ +struct FDotNor { + float x, y, z; + float flag; +}; + +layout(std430, binding = 8) writeonly buffer outputVertices +{ + FDotVert output_verts[]; +}; + +layout(std430, binding = 9) writeonly buffer outputNormals +{ + FDotNor output_nors[]; +}; + +layout(std430, binding = 10) writeonly buffer outputFdotsIndices +{ + uint output_indices[]; +}; + +layout(std430, binding = 11) readonly buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; +#else +layout(std430, binding = 8) writeonly buffer outputVertexData +{ + PosNorLoop output_verts[]; +}; +#endif + +vec2 read_vec2(int index) +{ + vec2 result; + result.x = srcVertexBuffer[index * 2]; + result.y = srcVertexBuffer[index * 2 + 1]; + return result; +} + +vec3 read_vec3(int index) +{ + vec3 result; + result.x = srcVertexBuffer[index * 3]; + result.y = srcVertexBuffer[index * 3 + 1]; + result.z = srcVertexBuffer[index * 3 + 2]; + return result; +} + +OsdPatchArray GetPatchArray(int arrayIndex) +{ + return patchArrayBuffer[arrayIndex]; +} + +OsdPatchParam GetPatchParam(int patchIndex) +{ + return patchParamBuffer[patchIndex]; +} + +/* ------------------------------------------------------------------------------ + * Patch Coordinate lookup. Return an OsdPatchCoord for the given patch_index and uvs. + * This code is a port of the OpenSubdiv PatchMap lookup code. + */ + +PatchHandle bogus_patch_handle() +{ + PatchHandle ret; + ret.array_index = -1; + ret.vertex_index = -1; + ret.patch_index = -1; + return ret; +} + +int transformUVToQuadQuadrant(float median, inout float u, inout float v) +{ + int uHalf = (u >= median) ? 1 : 0; + if (uHalf != 0) + u -= median; + + int vHalf = (v >= median) ? 1 : 0; + if (vHalf != 0) + v -= median; + + return (vHalf << 1) | uHalf; +} + +int transformUVToTriQuadrant(float median, inout float u, inout float v, inout bool rotated) +{ + + if (!rotated) { + if (u >= median) { + u -= median; + return 1; + } + if (v >= median) { + v -= median; + return 2; + } + if ((u + v) >= median) { + rotated = true; + return 3; + } + return 0; + } + else { + if (u < median) { + v -= median; + return 1; + } + if (v < median) { + u -= median; + return 2; + } + u -= median; + v -= median; + if ((u + v) < median) { + rotated = false; + return 3; + } + return 0; + } +} + +PatchHandle find_patch(int face_index, float u, float v) +{ + if (face_index < min_patch_face || face_index > max_patch_face) { + return bogus_patch_handle(); + } + + QuadNode node = quad_nodes[face_index - min_patch_face]; + + if (!is_set(node.child[0])) { + return bogus_patch_handle(); + } + + float median = 0.5; + bool tri_rotated = false; + + for (int depth = 0; depth <= max_depth; ++depth, median *= 0.5) { + int quadrant = (patches_are_triangular != 0) ? + transformUVToTriQuadrant(median, u, v, tri_rotated) : + transformUVToQuadQuadrant(median, u, v); + + if (is_leaf(node.child[quadrant])) { + return input_patch_handles[get_index(node.child[quadrant])]; + } + + node = quad_nodes[get_index(node.child[quadrant])]; + } +} + +OsdPatchCoord bogus_patch_coord(int face_index, float u, float v) +{ + OsdPatchCoord coord; + coord.arrayIndex = 0; + coord.patchIndex = face_index; + coord.vertIndex = 0; + coord.s = u; + coord.t = v; + return coord; +} + +OsdPatchCoord GetPatchCoord(int face_index, float u, float v) +{ + PatchHandle patch_handle = find_patch(face_index, u, v); + + if (patch_handle.array_index == -1) { + return bogus_patch_coord(face_index, u, v); + } + + OsdPatchCoord coord; + coord.arrayIndex = patch_handle.array_index; + coord.patchIndex = patch_handle.patch_index; + coord.vertIndex = patch_handle.vertex_index; + coord.s = u; + coord.t = v; + return coord; +} + +/* ------------------------------------------------------------------------------ + * Patch evaluation. Note that the 1st and 2nd derivatives are always computed, although we + * only return and use the 1st derivatives if adaptive patches are used. This could + * perhaps be optimized. + */ + +#if defined(FVAR_EVALUATION) +void evaluate_patches_limits(int patch_index, float u, float v, inout vec2 dst) +{ + OsdPatchCoord coord = GetPatchCoord(patch_index, u, v); + OsdPatchArray array = GetPatchArray(coord.arrayIndex); + OsdPatchParam param = GetPatchParam(coord.patchIndex); + + int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc; + + float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; + int nPoints = OsdEvaluatePatchBasis( + patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv); + + int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase); + + for (int cv = 0; cv < nPoints; ++cv) { + int index = patchIndexBuffer[indexBase + cv]; + vec2 src_fvar = read_vec2(src_offset + index); + dst += src_fvar * wP[cv]; + } +} +#else +void evaluate_patches_limits( + int patch_index, float u, float v, inout vec3 dst, inout vec3 du, inout vec3 dv) +{ + OsdPatchCoord coord = GetPatchCoord(patch_index, u, v); + OsdPatchArray array = GetPatchArray(coord.arrayIndex); + OsdPatchParam param = GetPatchParam(coord.patchIndex); + + int patchType = OsdPatchParamIsRegular(param) ? array.regDesc : array.desc; + + float wP[20], wDu[20], wDv[20], wDuu[20], wDuv[20], wDvv[20]; + int nPoints = OsdEvaluatePatchBasis( + patchType, param, coord.s, coord.t, wP, wDu, wDv, wDuu, wDuv, wDvv); + + int indexBase = array.indexBase + array.stride * (coord.patchIndex - array.primitiveIdBase); + + for (int cv = 0; cv < nPoints; ++cv) { + int index = patchIndexBuffer[indexBase + cv]; + vec3 src_vertex = read_vec3(index); + + dst += src_vertex * wP[cv]; + du += src_vertex * wDu[cv]; + dv += src_vertex * wDv[cv]; + } +} +#endif + +/* ------------------------------------------------------------------------------ + * Entry point. + */ + +#if defined(FVAR_EVALUATION) +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + vec2 fvar = vec2(0.0); + + BlenderPatchCoord patch_co = patch_coords[loop_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, fvar); + output_fvar[dst_offset + loop_index] = fvar; + } +} +#elif defined(FDOTS_EVALUATION) +bool is_face_selected(uint coarse_quad_index) +{ + return (extra_coarse_face_data[coarse_quad_index] & coarse_face_select_mask) != 0; +} + +bool is_face_active(uint coarse_quad_index) +{ + return (extra_coarse_face_data[coarse_quad_index] & coarse_face_active_mask) != 0; +} + +float get_face_flag(uint coarse_quad_index) +{ + if (is_face_active(coarse_quad_index)) { + return -1.0; + } + + if (is_face_selected(coarse_quad_index)) { + return 1.0; + } + + return 0.0; +} + +void main() +{ + /* We execute for each coarse quad. */ + uint coarse_quad_index = get_global_invocation_index(); + if (coarse_quad_index >= total_dispatch_size) { + return; + } + + BlenderPatchCoord patch_co = patch_coords[coarse_quad_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + vec3 pos = vec3(0.0); + vec3 du = vec3(0.0); + vec3 dv = vec3(0.0); + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv); + vec3 nor = normalize(cross(du, dv)); + + FDotVert vert; + vert.x = pos.x; + vert.y = pos.y; + vert.z = pos.z; + + FDotNor fnor; + fnor.x = nor.x; + fnor.y = nor.y; + fnor.z = nor.z; + fnor.flag = get_face_flag(coarse_quad_index); + + output_verts[coarse_quad_index] = vert; + output_nors[coarse_quad_index] = fnor; + output_indices[coarse_quad_index] = coarse_quad_index; +} +#else +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + vec3 pos = vec3(0.0); + vec3 du = vec3(0.0); + vec3 dv = vec3(0.0); + + BlenderPatchCoord patch_co = patch_coords[loop_index]; + vec2 uv = decode_uv(patch_co.encoded_uv); + + evaluate_patches_limits(patch_co.patch_index, uv.x, uv.y, pos, du, dv); + +# if defined(LIMIT_NORMALS) + vec3 nor = normalize(cross(du, dv)); +# else + /* This will be computed later. */ + vec3 nor = vec3(0.0); +# endif + + int origindex = input_vert_origindex[loop_index]; + uint flag = 0; + if (origindex == -1) { + flag = -1; + } + + PosNorLoop vertex_data; + set_vertex_pos(vertex_data, pos); + set_vertex_nor(vertex_data, nor, flag); + output_verts[loop_index] = vertex_data; + } +} +#endif diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl new file mode 100644 index 00000000000..6c76cd41ca4 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edge_fac_comp.glsl @@ -0,0 +1,97 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer inputEdgeIndex +{ + uint input_edge_index[]; +}; + +layout(std430, binding = 2) writeonly buffer outputEdgeFactors +{ +#ifdef GPU_AMD_DRIVER_BYTE_BUG + float output_edge_fac[]; +#else + uint output_edge_fac[]; +#endif +}; + +void write_vec4(uint index, vec4 edge_facs) +{ +#ifdef GPU_AMD_DRIVER_BYTE_BUG + for (uint i = 0; i < 4; i++) { + output_edge_fac[index + i] = edge_facs[i]; + } +#else + /* Use same scaling as in extract_edge_fac_iter_poly_mesh. */ + uint a = uint(clamp(edge_facs.x * 253.0 + 1.0, 0.0, 255.0)); + uint b = uint(clamp(edge_facs.y * 253.0 + 1.0, 0.0, 255.0)); + uint c = uint(clamp(edge_facs.z * 253.0 + 1.0, 0.0, 255.0)); + uint d = uint(clamp(edge_facs.w * 253.0 + 1.0, 0.0, 255.0)); + uint packed_edge_fac = a << 24 | b << 16 | c << 8 | d; + output_edge_fac[index] = packed_edge_fac; +#endif +} + +/* From extract_mesh_vbo_edge_fac.cc, keep in sync! */ +float loop_edge_factor_get(vec3 f_no, vec3 v_co, vec3 v_no, vec3 v_next_co) +{ + vec3 evec = v_next_co - v_co; + vec3 enor = normalize(cross(v_no, evec)); + float d = abs(dot(enor, f_no)); + /* Re-scale to the slider range. */ + d *= (1.0 / 0.065); + return clamp(d, 0.0, 1.0); +} + +float compute_line_factor(uint start_loop_index, uint corner_index, vec3 face_normal) +{ + uint vertex_index = start_loop_index + corner_index; + uint edge_index = input_edge_index[vertex_index]; + + if (edge_index == -1 && optimal_display) { + return 0.0; + } + + /* Mod 4 so we loop back at the first vertex on the last loop index (3), but only the corner + * index needs to be wrapped. */ + uint next_vertex_index = start_loop_index + (corner_index + 1) % 4; + vec3 vertex_pos = get_vertex_pos(pos_nor[vertex_index]); + vec3 vertex_nor = get_vertex_nor(pos_nor[vertex_index]); + vec3 next_vertex_pos = get_vertex_pos(pos_nor[next_vertex_index]); + return loop_edge_factor_get(face_normal, vertex_pos, vertex_nor, next_vertex_pos); +} + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + /* First compute the face normal, we need it to compute the bihedral edge angle. */ + vec3 v0 = get_vertex_pos(pos_nor[start_loop_index + 0]); + vec3 v1 = get_vertex_pos(pos_nor[start_loop_index + 1]); + vec3 v2 = get_vertex_pos(pos_nor[start_loop_index + 2]); + vec3 face_normal = normalize(cross(v1 - v0, v2 - v0)); + + vec4 edge_facs = vec4(0.0); + for (int i = 0; i < 4; i++) { + edge_facs[i] = compute_line_factor(start_loop_index, i, face_normal); + } + +#ifdef GPU_AMD_DRIVER_BYTE_BUG + write_vec4(start_loop_index, edge_facs); +#else + /* When packed into bytes, the index is the same as for the quad. */ + write_vec4(quad_index, edge_facs); +#endif +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl new file mode 100644 index 00000000000..ea73b9482d3 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_angle_comp.glsl @@ -0,0 +1,80 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 0) readonly buffer inputVerts +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 1) readonly buffer inputUVs +{ + vec2 uvs[]; +}; + +/* Mirror of #UVStretchAngle in the C++ code, but using floats until proper data compression + * is implemented for all subdivision data. */ +struct UVStretchAngle { + float angle; + float uv_angle0; + float uv_angle1; +}; + +layout(std430, binding = 2) writeonly buffer outputStretchAngles +{ + UVStretchAngle uv_stretches[]; +}; + +#define M_PI 3.1415926535897932 +#define M_1_PI 0.31830988618379067154 + +/* Adapted from BLI_math_vector.h */ +float angle_normalized_v3v3(vec3 v1, vec3 v2) +{ + /* this is the same as acos(dot_v3v3(v1, v2)), but more accurate */ + bool q = (dot(v1, v2) >= 0.0); + vec3 v = (q) ? (v1 - v2) : (v1 + v2); + float a = 2.0 * asin(length(v) / 2.0); + return (q) ? a : M_PI - a; +} + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint i = 0; i < 4; i++) { + uint cur_loop_index = start_loop_index + i; + uint next_loop_index = start_loop_index + (i + 1) % 4; + uint prev_loop_index = start_loop_index + (i + 3) % 4; + + /* Compute 2d edge vectors from UVs. */ + vec2 cur_uv = uvs[src_offset + cur_loop_index]; + vec2 next_uv = uvs[src_offset + next_loop_index]; + vec2 prev_uv = uvs[src_offset + prev_loop_index]; + + vec2 norm_uv_edge0 = normalize(prev_uv - cur_uv); + vec2 norm_uv_edge1 = normalize(cur_uv - next_uv); + + /* Compute 3d edge vectors from positions. */ + vec3 cur_pos = get_vertex_pos(pos_nor[cur_loop_index]); + vec3 next_pos = get_vertex_pos(pos_nor[next_loop_index]); + vec3 prev_pos = get_vertex_pos(pos_nor[prev_loop_index]); + + vec3 norm_pos_edge0 = normalize(prev_pos - cur_pos); + vec3 norm_pos_edge1 = normalize(cur_pos - next_pos); + + /* Compute stretches, this logic is adapted from #edituv_get_edituv_stretch_angle. + * Keep in sync! */ + UVStretchAngle stretch; + stretch.uv_angle0 = atan(norm_uv_edge0.y, norm_uv_edge0.x) * M_1_PI; + stretch.uv_angle1 = atan(norm_uv_edge1.y, norm_uv_edge1.x) * M_1_PI; + stretch.angle = angle_normalized_v3v3(norm_pos_edge0, norm_pos_edge1) * M_1_PI; + + uv_stretches[cur_loop_index] = stretch; + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl new file mode 100644 index 00000000000..e897fb3f3c0 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_edituv_strech_area_comp.glsl @@ -0,0 +1,31 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly buffer inputCoarseData +{ + float coarse_stretch_area[]; +}; + +layout(std430, binding = 2) writeonly buffer outputSubdivData +{ + float subdiv_stretch_area[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + + for (int i = 0; i < 4; i++) { + subdiv_stretch_area[start_loop_index + i] = coarse_stretch_area[coarse_quad_index]; + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl new file mode 100644 index 00000000000..41a8df3cf82 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_lnor_comp.glsl @@ -0,0 +1,52 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +layout(std430, binding = 1) readonly buffer inputVertexData +{ + PosNorLoop pos_nor[]; +}; + +layout(std430, binding = 2) readonly buffer extraCoarseFaceData +{ + uint extra_coarse_face_data[]; +}; + +layout(std430, binding = 3) writeonly buffer outputLoopNormals +{ + vec3 output_lnor[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + /* The start index of the loop is quad_index * 4. */ + uint start_loop_index = quad_index * 4; + + uint coarse_quad_index = coarse_polygon_index_from_subdiv_quad_index(quad_index, + coarse_poly_count); + + if ((extra_coarse_face_data[coarse_quad_index] & coarse_face_smooth_mask) != 0) { + /* Face is smooth, use vertex normals. */ + for (int i = 0; i < 4; i++) { + PosNorLoop pos_nor_loop = pos_nor[start_loop_index + i]; + output_lnor[start_loop_index + i] = get_vertex_nor(pos_nor_loop); + } + } + else { + /* Face is flat shaded, compute flat face normal from an inscribed triangle. */ + vec3 verts[3]; + for (int i = 0; i < 3; i++) { + verts[i] = get_vertex_pos(pos_nor[start_loop_index + i]); + } + + vec3 face_normal = normalize(cross(verts[1] - verts[0], verts[2] - verts[0])); + for (int i = 0; i < 4; i++) { + output_lnor[start_loop_index + i] = face_normal; + } + } +} diff --git a/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl new file mode 100644 index 00000000000..7182ce57ad3 --- /dev/null +++ b/source/blender/draw/intern/shaders/common_subdiv_vbo_sculpt_data_comp.glsl @@ -0,0 +1,47 @@ + +/* To be compile with common_subdiv_lib.glsl */ + +struct SculptData { + uint face_set_color; + float mask; +}; + +layout(std430, binding = 0) readonly restrict buffer sculptMask +{ + float sculpt_mask[]; +}; + +layout(std430, binding = 1) readonly restrict buffer faceSetColor +{ + uint face_set_color[]; +}; + +layout(std430, binding = 2) writeonly restrict buffer sculptData +{ + SculptData sculpt_data[]; +}; + +void main() +{ + /* We execute for each quad. */ + uint quad_index = get_global_invocation_index(); + if (quad_index >= total_dispatch_size) { + return; + } + + uint start_loop_index = quad_index * 4; + + for (uint loop_index = start_loop_index; loop_index < start_loop_index + 4; loop_index++) { + SculptData data; + data.face_set_color = face_set_color[loop_index]; + + if (has_sculpt_mask) { + data.mask = sculpt_mask[loop_index]; + } + else { + data.mask = 0.0; + } + + sculpt_data[loop_index] = data; + } +} diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index f509898f2ee..bdcbac80699 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -879,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = { }; /* Filtering callback for driver mapping types enum */ -static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, - PointerRNA *UNUSED(owner_ptr), - PropertyRNA *UNUSED(owner_prop), - bool *r_free) +static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C, + PointerRNA *UNUSED(owner_ptr), + PropertyRNA *UNUSED(owner_prop), + bool *r_free) { EnumPropertyItem *input = prop_driver_create_mapping_types; EnumPropertyItem *item = NULL; @@ -961,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ } if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; if (path) { @@ -1039,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot) 0, "Mapping Type", "Method used to match target and driven properties"); - RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf); + RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf); } /* Add Driver Button Operator ------------------------ */ @@ -1055,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent * if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { /* 1) Create a new "empty" driver for this property */ - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; bool changed = false; @@ -1115,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op) } if (ptr.owner_id && ptr.data && prop) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0); @@ -1200,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op) UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* only copy the driver for the button that this was involved for */ @@ -1244,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* only copy the driver for the button that this was involved for */ diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index dc5d71b5a1e..8aac1e9b779 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -345,6 +345,71 @@ static bool find_fcurve_segment(FCurve *fcu, return in_segment; } +/* Return a list of FCurveSegment with a start index and a length. + * A segment is a continuous selection of keyframes. + * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected. + * The caller is responsible for freeing the memory. */ +ListBase find_fcurve_segments(FCurve *fcu) +{ + ListBase segments = {NULL, NULL}; + int segment_start_idx = 0; + int segment_len = 0; + int current_index = 0; + + while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) { + FCurveSegment *segment; + segment = MEM_callocN(sizeof(*segment), "FCurveSegment"); + segment->start_index = segment_start_idx; + segment->length = segment_len; + BLI_addtail(&segments, segment); + current_index = segment_start_idx + segment_len; + } + return segments; +} + +static BezTriple fcurve_segment_start_get(FCurve *fcu, int index) +{ + BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index]; + return start_bezt; +} + +static BezTriple fcurve_segment_end_get(FCurve *fcu, int index) +{ + BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1]; + return end_bezt; +} + +/* ---------------- */ + +void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor) +{ + const float blend_factor = fabs(factor * 2 - 1); + BezTriple target_bezt; + /* Find which key to blend towards. */ + if (factor < 0.5f) { + target_bezt = fcurve_segment_start_get(fcu, segment->start_index); + } + else { + target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length); + } + /* Blend each key individually. */ + for (int i = segment->start_index; i < segment->start_index + segment->length; i++) { + fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor); + } +} + +/* ---------------- */ + +void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor) +{ + BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index); + BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length); + + for (int i = segment->start_index; i < segment->start_index + segment->length; i++) { + fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor); + } +} + /* ---------------- */ /* Check if the keyframe interpolation type is supported */ @@ -440,15 +505,12 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max) fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG; } - /* Only decimate the individual selected curve segments. */ - int segment_start_idx = 0; - int segment_len = 0; - int current_index = 0; - - while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) { - decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max); - current_index = segment_start_idx + segment_len; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + decimate_fcurve_segment( + fcu, segment->start_index, segment->length, remove_ratio, error_sq_max); } + BLI_freelistN(&segments); uint old_totvert = fcu->totvert; fcu->bezt = NULL; diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 772fe8f3196..8bd6c9f54fd 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn) bArmature *arm = ob->data; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone && (pchan->bone->layer & arm->layer)) { + if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) { if (pchan->bone->layer & arm->layer_protected) { if (pchan->bone->flag & BONE_SELECTED) { break; diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 646356e7a45..dc96c777be0 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld, else if (pchan->bone) { /* only ok if bone is visible and selected */ if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 && - (pchan->bone->layer & arm->layer)) { + BKE_pose_is_layer_visible(arm, pchan)) { ok = 1; } } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 17347aa57fe..0b889149f9d 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -746,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); bool changed = false; - pchan_act = BKE_pose_channel_active(ob); + pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (pchan_act == NULL) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc index 4107d28b5e3..a9c6e3798c9 100644 --- a/source/blender/editors/asset/intern/asset_indexer.cc +++ b/source/blender/editors/asset/intern/asset_indexer.cc @@ -145,7 +145,7 @@ struct AssetEntryReader { /** * \brief Lookup table containing the elements of the entry. */ - ObjectValue::Lookup lookup; + DictionaryValue::Lookup lookup; StringRefNull get_name_with_idcode() const { @@ -153,7 +153,7 @@ struct AssetEntryReader { } public: - AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup()) + AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup()) { } @@ -204,7 +204,7 @@ struct AssetEntryReader { void add_tags_to_meta_data(AssetMetaData *asset_data) const { - const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); + const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); if (value_ptr == nullptr) { return; } @@ -220,10 +220,10 @@ struct AssetEntryReader { struct AssetEntryWriter { private: - ObjectValue::Items &attributes; + DictionaryValue::Items &attributes; public: - AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements()) + AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements()) { } @@ -301,7 +301,7 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result, /* TODO: asset_data.IDProperties */ } -static void init_value_from_file_indexer_entries(ObjectValue &result, +static void init_value_from_file_indexer_entries(DictionaryValue &result, const FileIndexerEntries &indexer_entries) { ArrayValue *entries = new ArrayValue(); @@ -313,7 +313,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result, if (indexer_entry->datablock_info.asset_data == nullptr) { continue; } - ObjectValue *entry_value = new ObjectValue(); + DictionaryValue *entry_value = new DictionaryValue(); AssetEntryWriter entry(*entry_value); init_value_from_file_indexer_entry(entry, indexer_entry); items.append_as(entry_value); @@ -326,7 +326,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result, return; } - ObjectValue::Items &attributes = result.elements(); + DictionaryValue::Items &attributes = result.elements(); attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries)); } @@ -366,10 +366,10 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, } static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, - const ObjectValue &value) + const DictionaryValue &value) { - const ObjectValue::Lookup attributes = value.create_lookup(); - const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); + const DictionaryValue::Lookup attributes = value.create_lookup(); + const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); BLI_assert(entries_value != nullptr); if (entries_value == nullptr) { @@ -379,7 +379,7 @@ static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, int num_entries_read = 0; const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements(); for (ArrayValue::Item element : elements) { - const AssetEntryReader asset_entry(*element->as_object_value()); + const AssetEntryReader asset_entry(*element->as_dictionary_value()); FileIndexerEntry *entry = static_cast<FileIndexerEntry *>( MEM_callocN(sizeof(FileIndexerEntry), __func__)); @@ -534,9 +534,9 @@ struct AssetIndex { /** * `blender::io::serialize::Value` representing the contents of an index file. * - * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't - * represent an object. In case corrupted files are detected the `get_version` would return - * `UNKNOWN_VERSION`. + * Value is used over #DictionaryValue as the contents of the index could be corrupted and + * doesn't represent an object. In case corrupted files are detected the `get_version` would + * return `UNKNOWN_VERSION`. */ std::unique_ptr<Value> contents; @@ -546,8 +546,8 @@ struct AssetIndex { */ AssetIndex(const FileIndexerEntries &indexer_entries) { - std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>(); - ObjectValue::Items &root_attributes = root->elements(); + std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>(); + DictionaryValue::Items &root_attributes = root->elements(); root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION))); init_value_from_file_indexer_entries(*root, indexer_entries); @@ -564,12 +564,12 @@ struct AssetIndex { int get_version() const { - const ObjectValue *root = contents->as_object_value(); + const DictionaryValue *root = contents->as_dictionary_value(); if (root == nullptr) { return UNKNOWN_VERSION; } - const ObjectValue::Lookup attributes = root->create_lookup(); - const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); + const DictionaryValue::Lookup attributes = root->create_lookup(); + const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); if (version_value == nullptr) { return UNKNOWN_VERSION; } @@ -588,7 +588,7 @@ struct AssetIndex { */ int extract_into(FileIndexerEntries &indexer_entries) const { - const ObjectValue *root = contents->as_object_value(); + const DictionaryValue *root = contents->as_dictionary_value(); const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root); return num_entries_read; } @@ -742,16 +742,15 @@ static void update_index(const char *filename, FileIndexerEntries *entries, void static void *init_user_data(const char *root_directory, size_t root_directory_maxlen) { - AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW( - AssetLibraryIndex, - StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen))); + AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>( + __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen))); library_index->init_unused_index_files(); return library_index; } static void free_user_data(void *user_data) { - OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex); + MEM_delete((AssetLibraryIndex *)user_data); } static void filelist_finished(void *user_data) diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index e4edff19a21..f7755aa9fea 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -934,10 +934,10 @@ static bool has_external_files(Main *bmain, struct ReportList *reports) BKE_reportf( callback_info.reports, RPT_ERROR, - "Unable to copy bundle due to %ld external dependencies; more details on the console", - callback_info.external_files.size()); - printf("Unable to copy bundle due to %ld external dependencies:\n", - callback_info.external_files.size()); + "Unable to copy bundle due to %zu external dependencies; more details on the console", + (size_t)callback_info.external_files.size()); + printf("Unable to copy bundle due to %zu external dependencies:\n", + (size_t)callback_info.external_files.size()); for (const std::string &path : callback_info.external_files) { printf(" \"%s\"\n", path.c_str()); } diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index f136c08f129..8790c907f05 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -88,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle) } BLI_assert(handle->file_data->asset_data != nullptr); return reinterpret_cast<AssetTempIDConsumer *>( - OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle)); + MEM_new<AssetTemporaryIDConsumer>(__func__, *handle)); } void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer) { - OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer); + MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer)); + *consumer = nullptr; } ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_, diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 3705ea38e11..ae00fc41f40 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); immUniformColor3fvAlpha(ink, ink[3]); immBegin(GPU_PRIM_POINTS, 1); - immVertex2fv(pos, &pt->x); + immVertex2fv(pos, pt->m_xy); } else { float oldpressure = points[0].pressure; @@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, if (fabsf(pt->pressure - oldpressure) > 0.2f) { /* need to have 2 points to avoid immEnd assert error */ if (draw_points < 2) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); } immEnd(); @@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); draw_points++; } @@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, } /* now the point we want */ - immVertex2fv(pos, &pt->x); + immVertex2fv(pos, pt->m_xy); draw_points++; } /* need to have 2 points to avoid immEnd assert error */ if (draw_points < 2) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); } } @@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, if ((sflag & GP_STROKE_USE_ARROW_END) && (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { float end[2]; - copy_v2_fl2(end, points[1].x, points[1].y); + copy_v2_v2(end, points[1].m_xy); annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style); } /* Draw starting arrow stroke. */ if ((sflag & GP_STROKE_USE_ARROW_START) && (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { float start[2]; - copy_v2_fl2(start, points[0].x, points[0].y); + copy_v2_v2(start, points[0].m_xy); annotation_draw_stroke_arrow_buffer( pos, start, runtime.arrow_start, runtime.arrow_start_style); } diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index fbc44ed58d8..196cd1028ea 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -426,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx) /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - copy_v2_v2(a, &pta->x); + copy_v2_v2(a, pta->m_xy); madd_v2_v2fl(sco, a, average_fac); } if (ptb) { - copy_v2_v2(b, &ptb->x); + copy_v2_v2(b, ptb->m_xy); madd_v2_v2fl(sco, b, average_fac); } if (ptc) { - copy_v2_v2(c, &ptc->x); + copy_v2_v2(c, ptc->m_xy); madd_v2_v2fl(sco, c, average_fac); } if (ptd) { - copy_v2_v2(d, &ptd->x); + copy_v2_v2(d, ptd->m_xy); madd_v2_v2fl(sco, d, average_fac); } /* Based on influence factor, blend between original and optimal smoothed coordinate */ interp_v2_v2v2(c, c, sco, inf); - copy_v2_v2(&ptc->x, c); + copy_v2_v2(ptc->m_xy, c); } static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8], @@ -492,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point, case GP_STROKE_ARROWSTYLE_CLOSED: mul_v2_fl(norm_dir, arrow_length); if (point != NULL) { - add_v2_v2(&point->x, norm_dir); - copy_v2_v2(corner, &point->x); + add_v2_v2(point->m_xy, norm_dir); + copy_v2_v2(corner, point->m_xy); } annotation_stroke_arrow_calc_points_segment(stroke_points, corner, @@ -507,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point, case GP_STROKE_ARROWSTYLE_SQUARE: mul_v2_fl(norm_dir, arrow_length * 1.5f); if (point != NULL) { - add_v2_v2(&point->x, norm_dir); - copy_v2_v2(corner, &point->x); + add_v2_v2(point->m_xy, norm_dir); + copy_v2_v2(corner, point->m_xy); } annotation_stroke_arrow_calc_points_segment(stroke_points, corner, @@ -544,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -560,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -573,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p, if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) { /* Store start and end point coords for arrows. */ float end[2]; - copy_v2_v2(end, &pt->x); + copy_v2_v2(end, pt->m_xy); pt = ((tGPspoint *)(gpd->runtime.sbuffer)); float start[2]; - copy_v2_v2(start, &pt->x); + copy_v2_v2(start, pt->m_xy); /* Arrow end corner. */ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) { @@ -609,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); pt->pressure = pressure; /* Unused for annotations, but initialize for easier conversions to GP Object. */ pt->strength = 1.0f; @@ -636,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)gpd->runtime.sbuffer; /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -678,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, } /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL); + annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL); /* copy pressure and time */ pts->pressure = pt->pressure; @@ -717,8 +717,8 @@ static void annotation_stroke_arrow_init_point( { /* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */ const float real_co[2] = {co[co_idx], co[co_idx + 1]}; - copy_v2_v2(&ptc->x, real_co); - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + copy_v2_v2(ptc->m_xy, real_co); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); } @@ -885,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -903,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); /* Convert screen-coordinates to appropriate coordinates (and store them). */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* Copy pressure and time. */ pt->pressure = ptc->pressure; @@ -926,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) /* End point. */ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ @@ -947,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) /* Start point. */ ptc = runtime.sbuffer; - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ @@ -961,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -981,7 +981,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) const ViewDepths *depths = p->depths; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1041,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -1811,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) /* Rope Simple. */ immUniformColor4f(color[0], color[1], color[2], 0.8f); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin); + immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin); immVertex2f(pos, x, y); immEnd(); @@ -2575,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve */ if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) { /* Change to whatever region is now under the mouse */ - ARegion *current_region = BKE_area_find_region_xy( - p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy); if (current_region) { /* Assume that since we found the cursor in here, it is in bounds diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index bea8126cfcc..916aa8184aa 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1468,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven static int gpencil_layer_change_exec(bContext *C, wmOperator *op) { bGPdata *gpd = CTX_data_gpencil_data(C); + if (gpd == NULL) { + return OPERATOR_CANCELLED; + } + bGPDlayer *gpl = NULL; int layer_num = RNA_enum_get(op->ptr, "layer"); diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index c3af28d4382..541b6673cb6 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1072,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf) /* First set in blue the perimeter. */ for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) { - int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x; + int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0]; set_pixel(ibuf, image_idx, blue_col); } @@ -1393,7 +1393,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { int mval_i[2]; - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1437,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf) while (!BLI_stack_is_empty(tgpf->stack)) { int v[2]; BLI_stack_pop(tgpf->stack, &v); - copy_v2fl_v2i(&point2D->x, v); + copy_v2fl_v2i(point2D->m_xy, v); /* shift points to center of pixel */ - add_v2_fl(&point2D->x, 0.5f); + add_v2_fl(point2D->m_xy, 0.5f); point2D->pressure = 1.0f; point2D->strength = 1.0f; point2D->time = 0.0f; @@ -2108,8 +2108,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) /* first time the event is not enabled to show help lines. */ if ((tgpf->oldkey != -1) || (!help_lines)) { - ARegion *region = BKE_area_find_region_xy( - CTX_wm_area(C), RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy); if (region) { bool in_bounds = false; /* Perform bounds check */ @@ -2126,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f); tGPspoint point2D; bGPDspoint *pt = &tgpf->gps_mouse->points[0]; - copy_v2fl_v2i(&point2D.x, tgpf->mouse); + copy_v2fl_v2i(point2D.m_xy, tgpf->mouse); gpencil_stroke_convertcoords_tpoint( tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x); diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index 11e02b9832f..efe29e852f2 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene /* Add active object. In some files this could not be in selected array. */ Object *obact = CTX_data_active_object(C); + if (obact == NULL) { + return false; + } if (obact->type == OB_MESH) { elem = MEM_callocN(sizeof(GpBakeOb), __func__); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index dabe2050b28..b52d4a410ec 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -493,7 +493,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit /* Mouse movement in ints -> floats. */ if (gpd->runtime.sbuffer_used > 1) { tGPspoint *pt_prev = pt - 1; - sub_v2_v2v2(mvec, &pt->x, &pt_prev->x); + sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy); normalize_v2(mvec); /* Rotate mvec by 90 degrees... */ float angle = angle_v2v2(mvec, axis); @@ -502,7 +502,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit mvec[1] *= sin(angle); /* Scale by displacement amount, and apply. */ - madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f); + madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f); } } @@ -520,8 +520,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const /* Apply to first point (only if there are 2 points because before no data to do it ) */ if (gpd->runtime.sbuffer_used == 1) { - mvec[0] = (mval[0] - (pt - 1)->x); - mvec[1] = (mval[1] - (pt - 1)->y); + sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy); normalize_v2(mvec); /* uses > 1.0f to get a smooth transition in first point */ @@ -533,8 +532,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const /* apply from second point */ if (gpd->runtime.sbuffer_used >= 1) { - mvec[0] = (mval[0] - (pt - 1)->x); - mvec[1] = (mval[1] - (pt - 1)->y); + sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy); normalize_v2(mvec); fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ @@ -581,25 +579,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx) /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - copy_v2_v2(a, &pta->x); + copy_v2_v2(a, pta->m_xy); madd_v2_v2fl(sco, a, average_fac); pressure += pta->pressure * average_fac; strength += pta->strength * average_fac; } if (ptb) { - copy_v2_v2(b, &ptb->x); + copy_v2_v2(b, ptb->m_xy); madd_v2_v2fl(sco, b, average_fac); pressure += ptb->pressure * average_fac; strength += ptb->strength * average_fac; } if (ptc) { - copy_v2_v2(c, &ptc->x); + copy_v2_v2(c, ptc->m_xy); madd_v2_v2fl(sco, c, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } if (ptd) { - copy_v2_v2(d, &ptd->x); + copy_v2_v2(d, ptd->m_xy); madd_v2_v2fl(sco, d, average_fac); pressure += ptd->pressure * average_fac; strength += ptd->strength * average_fac; @@ -609,7 +607,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx) * for Guide mode. */ if (!guide->use_guide) { interp_v2_v2v2(c, c, sco, inf); - copy_v2_v2(&ptc->x, c); + copy_v2_v2(ptc->m_xy, c); } /* Interpolate pressure. */ ptc->pressure = interpf(ptc->pressure, pressure, inf); @@ -646,37 +644,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx, /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - madd_v2_v2fl(sco, &pta->x, average_fac); + madd_v2_v2fl(sco, pta->m_xy, average_fac); pressure += pta->pressure * average_fac; strength += pta->strength * average_fac; } else { - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } if (ptb) { - madd_v2_v2fl(sco, &ptb->x, average_fac); + madd_v2_v2fl(sco, ptb->m_xy, average_fac); pressure += ptb->pressure * average_fac; strength += ptb->strength * average_fac; } else { - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; - madd_v2_v2fl(sco, &ptd->x, average_fac); + madd_v2_v2fl(sco, ptd->m_xy, average_fac); pressure += ptd->pressure * average_fac; strength += ptd->strength * average_fac; /* Based on influence factor, blend between original and optimal smoothed coordinate. */ - interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf); + interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf); /* Interpolate pressure. */ ptc->pressure = interpf(ptc->pressure, pressure, inf); @@ -738,7 +736,8 @@ static void gpencil_apply_randomness(tGPsdata *p, /* Apply randomness to uv texture rotation. */ if ((brush_settings->uv_random > 0.0f) && (uv)) { if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) { - float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f - + float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) * + 2.0f - 1.0f; value = rand * M_PI_2 * brush_settings->uv_random; } @@ -778,7 +777,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -794,7 +793,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -825,7 +824,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt->strength = brush_settings->draw_strength; pt->pressure = 1.0f; pt->uv_rot = 0.0f; - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* pressure */ if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) { @@ -1013,7 +1012,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; @@ -1047,7 +1046,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1); /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; @@ -1100,7 +1099,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) int i; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1171,7 +1170,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -1283,7 +1282,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) /* Join with existing strokes. */ if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) { - if (gps->prev != NULL) { + if ((gps->prev != NULL) || (gps->next != NULL)) { BKE_gpencil_stroke_boundingbox_calc(gps); float diff_mat[4][4], ctrl1[2], ctrl2[2]; BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat); @@ -1567,6 +1566,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } bGPDspoint npt; + gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + + gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); + if (pt0) { gpencil_point_to_parent_space(pt0, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]); @@ -1576,12 +1581,6 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, copy_v2_v2_int(pc0, pc1); } - gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); - gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - - gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); - gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); - /* Check that point segment of the boundbox of the eraser stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) || ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || @@ -2798,14 +2797,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; if (p->paintmode != GP_PAINTMODE_ERASER) { - ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy); } } else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) && (gpd->runtime.sbuffer_used > 0)) { pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; if (p->paintmode != GP_PAINTMODE_ERASER) { - ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy); } } } @@ -3303,8 +3302,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi /* angle vector of the brush with full thickness */ const float v0[2] = {cos(angle), sin(angle)}; - mvec[0] = pt->x - pt_prev->x; - mvec[1] = pt->y - pt_prev->y; + sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy); normalize_v2(mvec); fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ @@ -3355,11 +3353,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment * for arc curve. */ float v_prev[2], v_cur[2], v_half[2]; - sub_v2_v2v2(v_cur, mval, &pt_prev->x); + sub_v2_v2v2(v_cur, mval, pt_prev->m_xy); - sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x); - interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f); - sub_v2_v2(v_half, &pt_prev->x); + sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy); + interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f); + sub_v2_v2(v_half, pt_prev->m_xy); /* If angle is too sharp undo all changes and return. */ const float min_angle = DEG2RADF(120.0f); @@ -3378,14 +3376,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment /* Calc the position of the control point. */ float ctl[2]; - add_v2_v2v2(ctl, &pt_prev->x, v_prev); + add_v2_v2v2(ctl, pt_prev->m_xy, v_prev); float step = M_PI_2 / (float)(segments + 1); float a = step; float midpoint[2], start[2], end[2], cp1[2], corner[2]; - mid_v2_v2v2(midpoint, &pt_prev->x, mval); - copy_v2_v2(start, &pt_prev->x); + mid_v2_v2v2(midpoint, pt_prev->m_xy, mval); + copy_v2_v2(start, pt_prev->m_xy); copy_v2_v2(end, mval); copy_v2_v2(cp1, ctl); @@ -3396,8 +3394,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment tGPspoint *pt_step = pt_prev; for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); - pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); + pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); + pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); /* Set pressure and strength equals to previous. It will be smoothed later. */ pt->pressure = pt_prev->pressure; @@ -3460,8 +3458,8 @@ static void gpencil_add_guide_points(const tGPsdata *p, for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a); - gpencil_snap_to_guide(p, guide, &pt->x); + gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a); + gpencil_snap_to_guide(p, guide, pt->m_xy); a += step; /* Set pressure and strength equals to previous. It will be smoothed later. */ @@ -3477,8 +3475,8 @@ static void gpencil_add_guide_points(const tGPsdata *p, for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - interp_v2_v2v2(&pt->x, start, end, a); - gpencil_snap_to_guide(p, guide, &pt->x); + interp_v2_v2v2(pt->m_xy, start, end, a); + gpencil_snap_to_guide(p, guide, pt->m_xy); a += step; /* Set pressure and strength equals to previous. It will be smoothed later. */ @@ -3681,8 +3679,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) */ if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) { /* Change to whatever region is now under the mouse */ - ARegion *current_region = BKE_area_find_region_xy( - p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy); if (current_region) { /* Assume that since we found the cursor in here, it is in bounds diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 8157e9d8fe7..2715491414a 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi Scene *scene = tgpi->scene; char status_str[UI_MAX_DRAW_STR]; char msg_str[UI_MAX_DRAW_STR]; + const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2; if (tgpi->type == GP_STROKE_LINE) { BLI_strncpy(msg_str, @@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], @@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->end[0], (int)tgpi->end[1]); } @@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], @@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D if (tgpi->tot_edges == 1) { for (int j = 0; j < 4; j++) { tGPspoint *p2d = &points2D[j]; - copy_v2_v2(&p2d->x, coords[j]); + copy_v2_v2(p2d->m_xy, coords[j]); } } else { @@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D float a = 0.0f; for (int k = 0; k < tgpi->tot_edges; k++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a); + interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a); a += step; i++; } @@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a); + interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a); a += step; } @@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); - p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); + p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); + p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); a += step; } float color[4]; @@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a); + interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a); a += step; } float color[4]; @@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - p2d->x = (center[0] + cosf(a) * radius[0]); - p2d->y = (center[1] + sinf(a) * radius[1]); + p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]); + p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]); a += step; } float color[4]; @@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth); if (tgpi->type == GP_STROKE_BOX) { - tgpi->tot_edges--; gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges); } else { @@ -801,7 +801,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) const ViewDepths *depths = tgpi->depths; tGPspoint *ptc = &points2D[0]; for (int i = 0; i < gps->totpoints; i++, ptc++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { @@ -894,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* Store original points */ float tmp_xyp[2]; - copy_v2_v2(tmp_xyp, &p2d->x); + copy_v2_v2(tmp_xyp, p2d->m_xy); /* calc pressure */ float curve_pressure = 1.0; @@ -926,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* vector */ float mvec[2], svec[2]; if (i > 0) { - mvec[0] = (p2d->x - (p2d - 1)->x); - mvec[1] = (p2d->y - (p2d - 1)->y); + sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy); normalize_v2(mvec); } else { @@ -942,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) else { mul_v2_fl(svec, fac); } - add_v2_v2(&p2d->x, svec); + add_v2_v2(p2d->m_xy, svec); } /* color strength */ @@ -992,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } } - copy_v2_v2(&tpt->x, &p2d->x); + copy_v2_v2(tpt->m_xy, p2d->m_xy); tpt->pressure = pressure; tpt->strength = strength; @@ -1064,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } /* Restore original points */ - copy_v2_v2(&p2d->x, tmp_xyp); + copy_v2_v2(p2d->m_xy, tmp_xyp); } /* store cps and convert coords */ @@ -1254,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) tgpi->tot_stored_edges = 0; tgpi->subdiv = RNA_int_get(op->ptr, "subdivision"); - RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2); + RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2); tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); tgpi->flag = IDLE; tgpi->lock_axis = ts->gp_sculpt.lock_axis; @@ -1617,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset) for (int i = 0; i < gps->totpoints; i++) { tGPspoint *p2d = &points2D[i]; - add_v2_v2(&p2d->x, move); + add_v2_v2(p2d->m_xy, move); } add_v2_v2(tgpi->start, move); @@ -1720,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELUPMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges + 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); gpencil_primitive_update(C, op, tgpi); } @@ -1730,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELDOWNMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges - 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); gpencil_primitive_update(C, op, tgpi); } @@ -1886,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELUPMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges + 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); /* update screen */ @@ -1898,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELDOWNMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges - 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); /* update screen */ @@ -2038,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t RNA_def_property_flag(prop, PROP_SKIP_SAVE); /* Internal prop. */ - prop = RNA_def_int(ot->srna, - "edges", - MIN_EDGES, - MIN_EDGES, - MAX_EDGES, - "Edges", - "Number of points by edge", - MIN_EDGES, - MAX_EDGES); + prop = RNA_def_int( + ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape"); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index f082af979a1..81a844cf6e1 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -870,7 +870,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene, } int mval_i[2]; - round_v2i_v2fl(mval_i, &point2D->x); + round_v2i_v2fl(mval_i, point2D->m_xy); if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) { /* projecting onto 3D-Geometry @@ -878,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene, */ } else { - float mval_f[2] = {point2D->x, point2D->y}; + float mval_f[2] = {UNPACK2(point2D->m_xy)}; float mval_prj[2]; float rvec[3], dvec[3]; float zfac; @@ -2020,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region, const float origin[3], float out[3]) { - float mval_f[2] = {(float)point2D->x, (float)point2D->y}; + float mval_f[2] = {UNPACK2(point2D->m_xy)}; float mval_prj[2]; float rvec[3], dvec[3]; float zfac; @@ -2808,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random( if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128; - int ix = (int)(tpt->x * seed); - int iy = (int)(tpt->y * seed); + int ix = (int)(tpt->m_xy[0] * seed); + int iy = (int)(tpt->m_xy[1] * seed); int iz = ix + iy * seed; float hsv[3]; float factor_value[3]; diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 99164bbe439..5e50a17e80a 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode { */ typedef struct tGPspoint { /** Coordinates x and y of cursor (in relative to area). */ - float x, y; + float m_xy[2]; /** Pressure of tablet at this point. */ float pressure; /** Pressure of tablet at this point for alpha factor. */ diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index bafe68bd28d..c54fb93e495 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -380,10 +380,21 @@ bool delete_fcurve_keys(struct FCurve *fcu); void clear_fcurve_keys(struct FCurve *fcu); void duplicate_fcurve_keys(struct FCurve *fcu); +typedef struct FCurveSegment { + struct FCurveSegment *next, *prev; + int start_index, length; +} FCurveSegment; +ListBase find_fcurve_segments(struct FCurve *fcu); void clean_fcurve(struct bAnimContext *ac, struct bAnimListElem *ale, float thresh, bool cleardefault); +void blend_to_neighbor_fcurve_segment(struct FCurve *fcu, + struct FCurveSegment *segment, + const float factor); +void breakdown_fcurve_segment(struct FCurve *fcu, + struct FCurveSegment *segment, + const float factor); bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max); /** * Use a weighted moving-means method to reduce intensity of fluctuations. diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 5bac452c7c9..db1ba80dd3c 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -100,7 +100,7 @@ void ED_node_socket_draw(struct bNodeSocket *sock, float scale); void ED_node_tree_update(const struct bContext *C); void ED_node_tag_update_id(struct ID *id); -void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); + /** * Sort nodes by selection: unselected nodes first, then selected, * then the active node at the very end. Relative order is kept intact. @@ -152,6 +152,26 @@ void ED_node_set_active(struct Main *bmain, bool *r_active_texture_changed); /** + * Call after one or more node trees have been changed and tagged accordingly. + * + * This function will make sure that other parts of Blender update accordingly. For example, if the + * node group interface changed, parent node groups have to be updated as well. + * + * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph + * relation updates have to be triggered by the caller. + * + * \param C: Context if available. This can be null. + * \param bmain: Main whose data-blocks should be updated based on the changes. + * \param ntree: Under some circumstances the caller knows that only one node tree has + * changed since the last update. In this case the function may be able to skip scanning #bmain + * for other things that have to be changed. It may still scan #bmain if the interface of the + * node tree has changed. + */ +void ED_node_tree_propagate_change(const struct bContext *C, + struct Main *bmain, + struct bNodeTree *ntree); + +/** * \param scene_owner: is the owner of the job, * we don't use it for anything else currently so could also be a void pointer, * but for now keep it an 'Scene' for consistency. diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index f60d62ed384..b91569cee03 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -23,6 +23,7 @@ #pragma once +#include "DNA_ID_enums.h" #include "DNA_vec_types.h" #ifdef __cplusplus @@ -41,7 +42,6 @@ struct bContext; struct bScreen; struct wmWindow; struct wmWindowManager; -enum eIconSizes; /* render_ops.c */ @@ -100,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C, struct MTex *slot, int sizex, int sizey, - int method); + ePreviewRenderMethod method); void ED_preview_icon_render(const struct bContext *C, struct Scene *scene, struct ID *id, diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9df5b17975a..cee323bd5c9 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -982,21 +982,6 @@ uiBut *uiDefButF(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefButBitF(uiBlock *block, - int type, - int bit, - int retval, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefButI(uiBlock *block, int type, int retval, @@ -1154,35 +1139,6 @@ uiBut *uiDefIconBut(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconButF(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconButI(uiBlock *block, int type, int retval, @@ -1241,20 +1197,6 @@ uiBut *uiDefIconButBitS(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconButC(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, @@ -1356,22 +1298,6 @@ uiBut *uiDefIconTextButF(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconTextButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, @@ -1387,84 +1313,6 @@ uiBut *uiDefIconTextButI(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconTextButBitI(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - int *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButS(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButBitS(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButC(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButBitC(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, @@ -2196,6 +2044,7 @@ uiLayout *UI_block_layout(uiBlock *block, const struct uiStyle *style); void UI_block_layout_set_current(uiBlock *block, uiLayout *layout); void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y); +bool UI_block_layout_needs_resolving(const uiBlock *block); /** * Used for property search when the layout process needs to be cancelled in order to avoid * computing the locations for buttons, but the layout items created while adding the buttons @@ -2544,11 +2393,42 @@ void uiTemplateComponentMenu(uiLayout *layout, const char *propname, const char *name); void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]); + +/** + * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which + * do not have their own dedicated template functions. + */ void uiTemplateCacheFile(uiLayout *layout, const struct bContext *C, struct PointerRNA *ptr, const char *propname); +/** + * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter. + * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not + * initialized. + */ +bool uiTemplateCacheFilePointer(struct PointerRNA *ptr, + const char *propname, + struct PointerRNA *r_file_ptr); + +/** + * Draw the velocity related properties of the CacheFile. + */ +void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr); + +/** + * Draw the render procedural related properties of the CacheFile. + */ +void uiTemplateCacheFileProcedural(uiLayout *layout, + const struct bContext *C, + struct PointerRNA *fileptr); + +/** + * Draw the time related properties of the CacheFile. + */ +void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr); + /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" enum uiTemplateListFlags { diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index df508b87ce4..a275a59a4e7 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -4943,38 +4943,6 @@ uiBut *uiDefButF(uiBlock *block, a2, tip); } -uiBut *uiDefButBitF(uiBlock *block, - int type, - int bit, - int retval, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefButI(uiBlock *block, int type, int retval, @@ -5295,68 +5263,6 @@ static uiBut *uiDefIconButBit(uiBlock *block, tip); } -uiBut *uiDefIconButF(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconBut(block, - type | UI_BUT_POIN_FLOAT, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconButI(uiBlock *block, int type, int retval, @@ -5481,36 +5387,6 @@ uiBut *uiDefIconButBitS(uiBlock *block, a2, tip); } -uiBut *uiDefIconButC(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconBut(block, - type | UI_BUT_POIN_CHAR, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, @@ -5640,44 +5516,6 @@ uiBut *uiDefIconTextBut(uiBlock *block, but->drawflag |= UI_BUT_ICON_LEFT; return but; } -static uiBut *uiDefIconTextButBit(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - void *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - const int bitIdx = findBitIndex(bit); - if (bitIdx == -1) { - return NULL; - } - return uiDefIconTextBut(block, - type | UI_BUT_POIN_BIT | bitIdx, - retval, - icon, - str, - x, - y, - width, - height, - poin, - min, - max, - a1, - a2, - tip); -} - uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, @@ -5710,40 +5548,6 @@ uiBut *uiDefIconTextButF(uiBlock *block, a2, tip); } -uiBut *uiDefIconTextButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, @@ -5776,172 +5580,6 @@ uiBut *uiDefIconTextButI(uiBlock *block, a2, tip); } -uiBut *uiDefIconTextButBitI(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - int *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_INT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButS(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextBut(block, - type | UI_BUT_POIN_SHORT, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButBitS(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_SHORT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButC(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextBut(block, - type | UI_BUT_POIN_CHAR, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButBitC(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_CHAR, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 27fa2e5a22f..fd03cc5e12c 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -146,8 +146,8 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); - const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); + const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy); uiBut *but = ui_but_find_mouse_over(region, event); @@ -163,13 +163,13 @@ void datadropper_win_area_find( bScreen *screen = CTX_wm_screen(C); *r_win = CTX_wm_window(C); - *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]); + *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval); if (*r_area == NULL) { wmWindowManager *wm = CTX_wm_manager(C); *r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval); if (*r_win) { screen = WM_window_get_active_screen(*r_win); - *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]); + *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval); } } else if (mval != r_mval) { diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 0ac6ea4021b..52730096b2f 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -263,32 +263,32 @@ static bool eyedropper_cryptomatte_sample_fl( } bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) { + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); + if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) { return false; } - ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (!region) { return false; } int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; ED_space_image_get_position(sima, region, mval, fpos); break; } case SPACE_NODE: { Main *bmain = CTX_data_main(C); - SpaceNode *snode = sa->spacedata.first; + SpaceNode *snode = area->spacedata.first; ED_space_node_get_position(bmain, snode, region, mval, fpos); break; } case SPACE_CLIP: { - SpaceClip *sc = sa->spacedata.first; + SpaceClip *sc = area->spacedata.first; ED_space_clip_get_position(sc, region, mval, fpos); break; } @@ -337,7 +337,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) if (area) { if (area->spacetype == SPACE_IMAGE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceImage *sima = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; @@ -348,7 +348,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) } } else if (area->spacetype == SPACE_NODE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceNode *snode = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; @@ -359,7 +359,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) } } else if (area->spacetype == SPACE_CLIP) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceClip *sc = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index 261aa997d06..cf53ef0ec75 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -162,7 +162,7 @@ static void datadropper_id_sample_pt( if (area) { if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (region) { const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; Base *base; diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 4172c474f4a..8c6b0ac9cfe 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt( { /* we could use some clever */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); Scene *scene = CTX_data_scene(C); ScrArea *area_prev = CTX_wm_area(C); @@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt( if (area) { if (area->spacetype == SPACE_VIEW3D) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (region) { struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); View3D *v3d = area->spacedata.first; diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c index ccf0e727da8..6fe930b74d2 100644 --- a/source/blender/editors/interface/interface_eyedropper_driver.c +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); /* ... and destination */ - char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); + char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop); /* Now create driver(s) */ if (target_path && dst_path) { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index d720b52a59e..659ac0ae899 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -3495,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) ui_but_update(but); - /* Popup blocks don't support moving after creation, so don't change the view for them. */ - if (!data->searchbox) { + /* Make sure the edited button is in view. */ + if (data->searchbox) { + /* Popup blocks don't support moving after creation, so don't change the view for them. */ + } + else if (UI_block_layout_needs_resolving(but->block)) { + /* Layout isn't resolved yet (may happen when activating while drawing through + * #UI_but_active_only()), so can't move it into view yet. This causes + * #ui_but_update_view_for_active() to run after the layout is resolved. */ + but->changed = true; + } + else { UI_but_ensure_in_view(C, data->region, but); } diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index cbdb284c66b..98fcb36b778 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -5661,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y) } } +bool UI_block_layout_needs_resolving(const uiBlock *block) +{ + return !BLI_listbase_is_empty(&block->layouts); +} + void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr) { uiBlock *block = layout->root->block; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 61869f3da41..f7424066ad8 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -1023,8 +1023,8 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, return false; } - /* Skip non-existing properties on link. This was previously covered with the lprop != prop check - * but we are now more permissive when it comes to ID properties, see below. */ + /* Skip non-existing properties on link. This was previously covered with the `lprop != prop` + * check but we are now more permissive when it comes to ID properties, see below. */ if (lprop == NULL) { return false; } @@ -1033,19 +1033,19 @@ bool UI_context_copy_to_selected_check(PointerRNA *ptr, return false; } - /* Check property pointers matching - * For ID properties, these pointers match - * - if the property is API defined on an existing class (and they are equally named) - * - never for ID properties on specific ID (even if they are equally named) - * - never for NodesModifierSettings properties (even if they are equally named) + /* Check property pointers matching. + * For ID properties, these pointers match: + * - If the property is API defined on an existing class (and they are equally named). + * - Never for ID properties on specific ID (even if they are equally named). + * - Never for NodesModifierSettings properties (even if they are equally named). * * Be permissive on ID properties in the following cases: - * - NodesModifierSettings properties - * - (special check: only if the nodegroup matches, since the 'Input_n' properties are name - * based and similar on potentionally very different nodegroups) + * - #NodesModifierSettings properties + * - (special check: only if the node-group matches, since the 'Input_n' properties are name + * based and similar on potentially very different node-groups). * - ID properties on specific ID - * - (no special check, copying seems OK [even if type does not match -- does not do anything - * then]) + * - (no special check, copying seems OK [even if type does not match -- does not do anything + * then]) */ bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop); if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) && @@ -1753,9 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev bScreen *screen = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *region_prev = CTX_wm_region(C); - ARegion *region = screen ? BKE_screen_find_region_xy( - screen, RGN_TYPE_ANY, event->xy[0], event->xy[1]) : - NULL; + ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL; if (region == NULL) { region = region_prev; diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index f4c99fb3c16..e27dd2a7981 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -725,7 +725,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, region->type = &type; /* create searchbox data */ - uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__); + uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__); /* set font, get bb */ data->fstyle = style->widget; /* copy struct */ @@ -1021,7 +1021,7 @@ void ui_but_search_refresh(uiButSearch *search_but) return; } - uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__); + uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__); /* setup search struct */ items->maxitem = 10; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b8026cbb40c..00e9a75848a 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2672,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); short proxy_protected, xco = 0, yco = 0; // int rb_col; // UNUSED @@ -6395,21 +6395,93 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4]) /** \name Cache File Template * \{ */ -void uiTemplateCacheFile(uiLayout *layout, - const bContext *C, - PointerRNA *ptr, - const char *propname) +void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr) { - if (!ptr->data) { - return; + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE); + uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE); +} + +void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row, *sub; + + /* Only enable render procedural option if the active engine supports it. */ + const struct RenderEngineType *engine_type = CTX_data_engine_type(C); + + Scene *scene = CTX_data_scene(C); + const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, + scene); + + if (!engine_supports_procedural) { + row = uiLayoutRow(layout, false); + /* For Cycles, verify that experimental features are enabled. */ + if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { + uiItemL( + row, + TIP_( + "The Cycles Alembic Procedural is only available with the experimental feature set"), + ICON_INFO); + } + else { + uiItemL( + row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO); + } } + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, engine_supports_procedural); + uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE); + + const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural"); + const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch"); + + row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, use_render_procedural); + uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE); + + sub = uiLayoutRow(layout, false); + uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural); + uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE); +} + +void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row, *sub, *subsub; + + row = uiLayoutRow(layout, false); + uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); + sub = uiLayoutRow(row, true); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE); + subsub = uiLayoutRow(sub, true); + uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame")); + uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE); + uiItemDecoratorR(row, fileptr, "frame", 0); + + row = uiLayoutRow(layout, false); + uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE); + uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence")); +} + +bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr) +{ PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); - return; + return false; } if (RNA_property_type(prop) != PROP_POINTER) { @@ -6417,10 +6489,27 @@ void uiTemplateCacheFile(uiLayout *layout, __func__, RNA_struct_identifier(ptr->type), propname); + return false; + } + + *r_file_ptr = RNA_property_pointer_get(ptr, prop); + return true; +} + +void uiTemplateCacheFile(uiLayout *layout, + const bContext *C, + PointerRNA *ptr, + const char *propname) +{ + if (!ptr->data) { + return; + } + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { return; } - PointerRNA fileptr = RNA_property_pointer_get(ptr, prop); CacheFile *file = fileptr.data; uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); @@ -6442,7 +6531,7 @@ void uiTemplateCacheFile(uiLayout *layout, SpaceProperties *sbuts = CTX_wm_space_properties(C); - uiLayout *row, *sub, *subsub; + uiLayout *row, *sub; uiLayoutSetPropSep(layout, true); @@ -6451,68 +6540,11 @@ void uiTemplateCacheFile(uiLayout *layout, sub = uiLayoutRow(row, true); uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload"); - row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE); - - /* Only enable render procedural option if the active engine supports it. */ - const struct RenderEngineType *engine_type = CTX_data_engine_type(C); - - Scene *scene = CTX_data_scene(C); - const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, - scene); - - if (!engine_supports_procedural) { - row = uiLayoutRow(layout, false); - /* For Cycles, verify that experimental features are enabled. */ - if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { - uiItemL( - row, - TIP_( - "The Cycles Alembic Procedural is only available with the experimental feature set"), - ICON_INFO); - } - else { - uiItemL( - row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO); - } - } - - row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, engine_supports_procedural); - uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE); - - const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural"); - const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch"); - - row = uiLayoutRow(layout, false); - uiLayoutSetEnabled(row, use_render_procedural); - uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE); - - sub = uiLayoutRow(layout, false); - uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural); - uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE); - - row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); - sub = uiLayoutRow(row, true); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE); - subsub = uiLayoutRow(sub, true); - uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame")); - uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE); - uiItemDecoratorR(row, &fileptr, "frame", 0); - - row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE); - uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence")); - if (sbuts->mainb == BCONTEXT_CONSTRAINT) { row = uiLayoutRow(layout, false); uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE); } - uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE); - uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE); - /* TODO: unused for now, so no need to expose. */ #if 0 row = uiLayoutRow(layout, false); diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc index 500834f4434..81b24c75020 100644 --- a/source/blender/editors/interface/interface_view.cc +++ b/source/blender/editors/interface/interface_view.cc @@ -60,7 +60,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block, StringRef idname, std::unique_ptr<AbstractTreeView> tree_view) { - ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink); + ViewLink *view_link = MEM_new<ViewLink>(__func__); BLI_addtail(&block.views, view_link); view_link->view = std::move(tree_view); @@ -72,7 +72,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block, void ui_block_free_views(uiBlock *block) { LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) { - OBJECT_GUARDED_DELETE(link, ViewLink); + MEM_delete(link); } } diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index 44b5f85050f..f4da114159f 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -25,6 +25,20 @@ set(INC ../../io/alembic ../../io/collada ../../io/gpencil + ../../io/wavefront_obj + ../../io/usd + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc +) + +set(INC_SYS + +) + +set(SRC + io_alembic.c ../../io/usd ../../makesdna ../../makesrna @@ -43,6 +57,7 @@ set(SRC io_gpencil_export.c io_gpencil_import.c io_gpencil_utils.c + io_obj.c io_ops.c io_usd.c @@ -57,6 +72,7 @@ set(SRC set(LIB bf_blenkernel bf_blenlib + bf_wavefront_obj ) if(WITH_OPENCOLLADA) diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c new file mode 100644 index 00000000000..1e1e3c2ff42 --- /dev/null +++ b/source/blender/editors/io/io_obj.c @@ -0,0 +1,369 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup editor/io + */ + +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" + +#include "IO_wavefront_obj.h" +#include "io_obj.h" + +const EnumPropertyItem io_obj_transform_axis_forward[] = { + {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"}, + {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"}, + {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"}, + {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"}, + {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"}, + {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; + +const EnumPropertyItem io_obj_transform_axis_up[] = { + {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"}, + {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"}, + {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"}, + {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"}, + {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"}, + {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; + +const EnumPropertyItem io_obj_export_evaluation_mode[] = { + {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"}, + {DAG_EVAL_VIEWPORT, + "DAG_EVAL_VIEWPORT", + 0, + "Viewport (Default)", + "Export objects as they appear in the viewport"}, + {0, NULL, 0, NULL, NULL}}; + +static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + Main *bmain = CTX_data_main(C); + char filepath[FILE_MAX]; + + if (BKE_main_blendfile_path(bmain)[0] == '\0') { + BLI_strncpy(filepath, "untitled", sizeof(filepath)); + } + else { + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + } + + BLI_path_extension_replace(filepath, sizeof(filepath), ".obj"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + WM_event_add_fileselect(C, op); + return OPERATOR_RUNNING_MODAL; +} + +static int wm_obj_export_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + struct OBJExportParams export_params; + RNA_string_get(op->ptr, "filepath", export_params.filepath); + export_params.blen_filepath = CTX_data_main(C)->filepath; + export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation"); + export_params.start_frame = RNA_int_get(op->ptr, "start_frame"); + export_params.end_frame = RNA_int_get(op->ptr, "end_frame"); + + export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); + export_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor"); + export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode"); + + export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects"); + export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv"); + export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals"); + export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials"); + export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh"); + export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs"); + + export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups"); + export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups"); + export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups"); + export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups"); + export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags"); + + OBJ_export(C, &export_params); + + return OPERATOR_FINISHED; +} + +static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) +{ + + const bool export_animation = RNA_boolean_get(imfptr, "export_animation"); + const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups"); + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + /* Animation options. */ + uiLayout *box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Animation"), ICON_ANIM); + uiLayout *col = uiLayoutColumn(box, false); + uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(sub, true); + uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE); + uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE); + uiLayoutSetEnabled(sub, export_animation); + + /* Object Transform options. */ + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE); + uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE); + sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects")); + uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE); + uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE); + + /* Options for what to write. */ + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE); + uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE); + uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE); + uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE); + uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE); + + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Grouping"), ICON_GROUP); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE); + sub = uiLayoutColumn(sub, false); + uiLayoutSetEnabled(sub, export_smooth_groups); + uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE); +} + +static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + ui_obj_export_settings(op->layout, &ptr); +} + +/** + * Return true if any property in the UI is changed. + */ +static bool wm_obj_export_check(bContext *C, wmOperator *op) +{ + char filepath[FILE_MAX]; + Scene *scene = CTX_data_scene(C); + bool changed = false; + RNA_string_get(op->ptr, "filepath", filepath); + + if (!BLI_path_extension_check(filepath, ".obj")) { + BLI_path_extension_ensure(filepath, FILE_MAX, ".obj"); + RNA_string_set(op->ptr, "filepath", filepath); + changed = true; + } + + { + int start = RNA_int_get(op->ptr, "start_frame"); + int end = RNA_int_get(op->ptr, "end_frame"); + /* Set the defaults. */ + if (start == INT_MIN) { + start = SFRA; + changed = true; + } + if (end == INT_MAX) { + end = EFRA; + changed = true; + } + /* Fix user errors. */ + if (end < start) { + end = start; + changed = true; + } + RNA_int_set(op->ptr, "start_frame", start); + RNA_int_set(op->ptr, "end_frame", end); + } + + /* Both forward and up axes cannot be the same (or same except opposite sign). */ + if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES == + (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) { + /* TODO (ankitm) Show a warning here. */ + RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1); + changed = true; + } + return changed; +} + +void WM_OT_obj_export(struct wmOperatorType *ot) +{ + ot->name = "Export Wavefront OBJ"; + ot->description = "Save the scene to a Wavefront OBJ file"; + ot->idname = "WM_OT_obj_export"; + + ot->invoke = wm_obj_export_invoke; + ot->exec = wm_obj_export_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_obj_export_draw; + ot->check = wm_obj_export_check; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + /* Animation options. */ + RNA_def_boolean(ot->srna, + "export_animation", + false, + "Export Animation", + "Export multiple frames instead of the current frame only"); + RNA_def_int(ot->srna, + "start_frame", + INT_MIN, /* wm_obj_export_check uses this to set SFRA. */ + INT_MIN, + INT_MAX, + "Start Frame", + "The first frame to be exported", + INT_MIN, + INT_MAX); + RNA_def_int(ot->srna, + "end_frame", + INT_MAX, /* wm_obj_export_check uses this to set EFRA. */ + INT_MIN, + INT_MAX, + "End Frame", + "The last frame to be exported", + INT_MIN, + INT_MAX); + /* Object transform options. */ + RNA_def_enum(ot->srna, + "forward_axis", + io_obj_transform_axis_forward, + OBJ_AXIS_NEGATIVE_Z_FORWARD, + "Forward Axis", + ""); + RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_float(ot->srna, + "scaling_factor", + 1.0f, + 0.001f, + 10000.0f, + "Scale", + "Upscale the object by this factor", + 0.01, + 1000.0f); + /* File Writer options. */ + RNA_def_enum(ot->srna, + "export_eval_mode", + io_obj_export_evaluation_mode, + DAG_EVAL_VIEWPORT, + "Object Properties", + "Determines properties like object visibility, modifiers etc., where they differ " + "for Render and Viewport"); + RNA_def_boolean(ot->srna, + "export_selected_objects", + false, + "Export Selected Objects", + "Export only selected objects instead of all supported objects"); + RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", ""); + RNA_def_boolean(ot->srna, + "export_normals", + true, + "Export Normals", + "Export per-face normals if the face is flat-shaded, per-face-per-loop " + "normals if smooth-shaded"); + RNA_def_boolean(ot->srna, + "export_materials", + true, + "Export Materials", + "Export MTL library. There must be a Principled-BSDF node for image textures to " + "be exported to the MTL file"); + RNA_def_boolean(ot->srna, + "export_triangulated_mesh", + false, + "Export Triangulated Mesh", + "All ngons with four or more vertices will be triangulated. Meshes in " + "the scene will not be affected. Behaves like Triangulate Modifier with " + "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4"); + RNA_def_boolean(ot->srna, + "export_curves_as_nurbs", + false, + "Export Curves as NURBS", + "Export curves in parametric form instead of exporting as mesh"); + + RNA_def_boolean(ot->srna, + "export_object_groups", + false, + "Export Object Groups", + "Append mesh name to object name, separated by a '_'"); + RNA_def_boolean(ot->srna, + "export_material_groups", + false, + "Export Material Groups", + "Append mesh name and material name to object name, separated by a '_'"); + RNA_def_boolean( + ot->srna, + "export_vertex_groups", + false, + "Export Vertex Groups", + "Export the name of the vertex group of a face. It is approximated " + "by choosing the vertex group with the most members among the vertices of a face"); + RNA_def_boolean( + ot->srna, + "export_smooth_groups", + false, + "Export Smooth Groups", + "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\""); + RNA_def_boolean( + ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", ""); +} diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h new file mode 100644 index 00000000000..5a0e6971edd --- /dev/null +++ b/source/blender/editors/io/io_obj.h @@ -0,0 +1,25 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup editor/io + */ + +#pragma once + +struct wmOperatorType; + +void WM_OT_obj_export(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index b2788ee49a2..5dff0b69c2a 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -39,6 +39,7 @@ #include "io_cache.h" #include "io_gpencil.h" +#include "io_obj.h" void ED_operatortypes_io(void) { @@ -68,4 +69,5 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_open); WM_operatortype_append(CACHEFILE_OT_reload); + WM_operatortype_append(WM_OT_obj_export); } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 3772a37ac44..6b58e1a060d 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2605,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, /** * Calculate the center and maximum excursion of mesh. + * (Considers all meshes in multi-object edit mode) */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { @@ -2613,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) BMIter iter; BMVert *v; float min[3], max[3]; + float ws[3]; INIT_MINMAX(min, max); for (uint b = 0; b < kcd->objects_len; b++) { @@ -2620,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) em = BKE_editmesh_from_object(ob); if (kcd->cagecos[b]) { - minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert); + for (int i = 0; i < em->bm->totvert; i++) { + copy_v3_v3(ws, kcd->cagecos[b][i]); + mul_m4_v3(ob->obmat, ws); + minmax_v3v3_v3(min, max, ws); + } } else { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(min, max, v->co); + copy_v3_v3(ws, v->co); + mul_m4_v3(ob->obmat, ws); + minmax_v3v3_v3(min, max, ws); } } } diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 8cfcc96517c..a1a7dfac282 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -388,8 +388,7 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev * that the mouse clicked in a viewport region and its coordinates can be used to ray-cast * the PBVH and update the active Face Set ID. */ bScreen *screen = CTX_wm_screen(C); - ARegion *region = BKE_screen_find_main_region_at_xy( - screen, SPACE_VIEW3D, event->xy[0], event->xy[1]); + ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy); if (!region) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 5c3a8fc2277..91a512ae8e9 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -89,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob) if (ob->mode & OB_MODE_POSE) { bPoseChannel *pchan; - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan) { return &pchan->constraints; } @@ -2215,7 +2215,7 @@ static bool get_new_constraint_target( bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); - bPoseChannel *pchanact = BKE_pose_channel_active(obact); + bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact); bool only_curve = false, only_mesh = false, only_ob = false; bool found = false; @@ -2370,7 +2370,7 @@ static int constraint_add_exec( pchan = NULL; } else { - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); /* ensure not to confuse object/pose adding */ if (pchan == NULL) { @@ -2650,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); bConstraint *con = NULL; uiPopupMenu *pup; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index f06744068d5..38d0a044cb4 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1638,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) /** \name Object Mode Set Operator * \{ */ -static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, - PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), - bool *r_free) +static const EnumPropertyItem *object_mode_set_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { const EnumPropertyItem *input = rna_enum_object_mode_items; EnumPropertyItem *item = NULL; @@ -1790,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) ot->prop = RNA_def_enum( ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); - RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_enum_funcs(ot->prop, object_mode_set_itemf); RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index e3c2932e17a..f9ad35d261d 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type) { + if (ob == NULL) { + return NULL; + } + char modifier_name[MAX_NAME]; GpencilModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); @@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_FINISHED; + } const int new_active_index = dmd->segment_active_index + 1; DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN( dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__); @@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_FINISHED; + } + if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) { return OPERATOR_CANCELLED; } @@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_FINISHED; + } + if (dmd->segments_len < 2) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 5065a2c00f0..51967ff35c7 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C, BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget)); - pchan_act = BKE_pose_channel_active(ob); + pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (LIKELY(pchan_act)) { invert_m4_m4(pose_mat, pchan_act->pose_mat); mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 811f20e82be..a6eb35d49b9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports, } case PAR_BONE: case PAR_BONE_RELATIVE: - pchan = BKE_pose_channel_active(par); - pchan_eval = BKE_pose_channel_active(parent_eval); + pchan = BKE_pose_channel_active_if_layer_visible(par); + pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval); if (pchan == NULL) { BKE_report(reports, RPT_ERROR, "No active bone"); @@ -2355,7 +2355,8 @@ static bool make_override_library_poll(bContext *C) /* Object must be directly linked to be overridable. */ return (ED_operator_objectmode(C) && obact != NULL && (ID_IS_LINKED(obact) || (obact->instance_collection != NULL && - ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)))); + ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) && + !ID_IS_OVERRIDE_LIBRARY(obact)))); } static const EnumPropertyItem *make_override_collections_of_linked_object_itemf( diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index 719ffd36f03..4737de4d8fa 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -463,8 +463,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev Object *active_object = CTX_data_active_object(C); Mesh *mesh = (Mesh *)active_object->data; - VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN( - sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data"); + VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>( + "Voxel Size Edit OP Custom Data"); /* Initial operator Custom Data setup. */ cd->draw_handle = ED_region_draw_cb_activate( diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 4c4727f51ee..c320313643d 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) sub_v3_v3(mpt, offset_local); mul_v3_m4v3(&pt->x, diff_mat, mpt); } + + /* Apply transform to editcurve*/ + if (gps->editcurve != NULL) { + for (i = 0; i < gps->editcurve->tot_curve_points; i++) { + BezTriple *bezt = &gps->editcurve->curve_points[i].bezt; + for (int j = 0; j < 3; j++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(bezt->vec[j], diff_mat, mpt); + } + } + } } } } diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 5f85f6ea0eb..df44d840ad3 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -115,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob, const bool select_only, float r_center[3]) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { copy_v3_v3(r_center, pchan->pose_head); return true; diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 367d72b0ad7..4f571fa6353 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); - if (target_psmd->mesh_final->runtime.deformed_only) { - /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ + const bool use_dm_final_indices = (target_psys->part->use_modifier_stack && + !target_psmd->mesh_final->runtime.deformed_only); + + if (use_dm_final_indices) { mesh = target_psmd->mesh_final; } else { @@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, return false; } /* don't modify the original vertices */ + /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE); /* BMESH_ONLY, deform dm may not have tessface */ @@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, tpa->foffset = 0.0f; tpa->num = nearest.index; - tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL); + if (use_dm_final_indices) { + tpa->num_dmcache = DMCACHE_ISCHILD; + } + else { + tpa->num_dmcache = psys_particle_dm_face_lookup( + target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL); + } } else { me = &medge[nearest.index]; diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 46afa390997..31dca83a3ab 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -36,15 +36,15 @@ set(INC ) set(SRC - render_internal.c - render_opengl.c - render_ops.c - render_preview.c - render_shading.c - render_update.c - render_view.c + render_internal.cc + render_opengl.cc + render_ops.cc + render_preview.cc + render_shading.cc + render_update.cc + render_view.cc - render_intern.h + render_intern.hh ) set(LIB diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh index d374717664b..d374717664b 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.hh diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc index 29d829dc131..441be3a6ce3 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.cc @@ -21,9 +21,9 @@ * \ingroup edrend */ -#include <math.h> -#include <stddef.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstring> #include "MEM_guardedalloc.h" @@ -50,6 +50,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -77,12 +78,12 @@ #include "SEQ_relations.h" -#include "render_intern.h" +#include "render_intern.hh" /* Render Callbacks */ static int render_break(void *rjv); -typedef struct RenderJob { +struct RenderJob { Main *main; Scene *scene; ViewLayer *single_layer; @@ -109,7 +110,7 @@ typedef struct RenderJob { ColorManagedDisplaySettings display_settings; bool supports_glsl_draw; bool interface_locked; -} RenderJob; +}; /* called inside thread! */ static bool image_buffer_calc_tile_rect(const RenderResult *rr, @@ -121,11 +122,11 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr, { int tile_y, tile_height, tile_x, tile_width; - /* When `renrect` argument is not NULL, we only refresh scan-lines. */ + /* When `renrect` argument is not nullptr, we only refresh scan-lines. */ if (renrect) { /* if (tile_height == recty), rendering of layer is ready, * we should not draw, other things happen... */ - if (rr->renlay == NULL || renrect->ymax >= rr->recty) { + if (rr->renlay == nullptr || renrect->ymax >= rr->recty) { return false; } @@ -189,7 +190,7 @@ static void image_buffer_rect_update(RenderJob *rj, const char *viewname) { Scene *scene = rj->scene; - const float *rectf = NULL; + const float *rectf = nullptr; int linear_stride, linear_offset_x, linear_offset_y; ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; @@ -230,12 +231,12 @@ static void image_buffer_rect_update(RenderJob *rj, ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; return; } - if (rr->renlay == NULL) { + if (rr->renlay == nullptr) { return; } rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname); } - if (rectf == NULL) { + if (rectf == nullptr) { return; } @@ -256,7 +257,7 @@ static void image_buffer_rect_update(RenderJob *rj, IMB_partial_display_buffer_update(ibuf, rectf, - NULL, + nullptr, linear_stride, linear_offset_x, linear_offset_y, @@ -315,17 +316,17 @@ static int screen_render_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); RenderEngineType *re_type = RE_engines_find(scene->r.engine); ViewLayer *active_layer = CTX_data_view_layer(C); - ViewLayer *single_layer = NULL; + ViewLayer *single_layer = nullptr; Render *re; Image *ima; View3D *v3d = CTX_wm_view3d(C); Main *mainp = CTX_data_main(C); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); - struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr; /* Cannot do render if there is not this function. */ - if (re_type->render == NULL) { + if (re_type->render == nullptr) { return OPERATOR_CANCELLED; } @@ -342,11 +343,11 @@ static int screen_render_exec(bContext *C, wmOperator *op) G.is_break = false; - RE_draw_lock_cb(re, NULL, NULL); - RE_test_break_cb(re, NULL, render_break); + RE_draw_lock_cb(re, nullptr, nullptr); + RE_test_break_cb(re, nullptr, render_break); ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(scene, ima, true); /* cleanup sequencer caches before starting user triggered render. @@ -371,7 +372,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } - RE_SetReports(re, NULL); + RE_SetReports(re, nullptr); /* No redraw needed, we leave state as we entered it. */ ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C)); @@ -383,7 +384,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) static void render_freejob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); BKE_color_managed_view_settings_free(&rj->view_settings); MEM_freeN(rj); @@ -471,15 +472,15 @@ static void make_renderinfo_string(const RenderStats *rs, static void image_renderinfo_cb(void *rjv, RenderStats *rs) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); RenderResult *rr; rr = RE_AcquireResultRead(rj->re); if (rr) { /* malloc OK here, stats_draw is not in tile threads */ - if (rr->text == NULL) { - rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); + if (rr->text == nullptr) { + rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext")); } make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text); @@ -493,7 +494,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs) static void render_progress_update(void *rjv, float progress) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); if (rj->progress && *rj->progress != progress) { *rj->progress = progress; @@ -511,20 +512,22 @@ static void render_progress_update(void *rjv, float progress) static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser) { wmWindowManager *wm; - ScrArea *first_area = NULL, *matched_area = NULL; + ScrArea *first_area = nullptr, *matched_area = nullptr; /* image window, compo node users */ - for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */ + for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr; + wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */ wmWindow *win; - for (win = wm->windows.first; win && matched_area == NULL; win = win->next) { + for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr; + win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); /* area->spacedata might be empty when toggling full-screen mode. */ - if (sima != NULL && sima->image == rj->image) { - if (first_area == NULL) { + if (sima != nullptr && sima->image == rj->image) { + if (first_area == nullptr) { first_area = area; } if (area == rj->area) { @@ -537,12 +540,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, } } - if (matched_area == NULL) { + if (matched_area == nullptr) { matched_area = first_area; } if (matched_area) { - SpaceImage *sima = matched_area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first); RenderResult *main_rr = RE_AcquireResultRead(rj->re); /* TODO(sergey): is there faster way to get the layer index? */ @@ -562,7 +565,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); Image *ima = rj->image; ImBuf *ibuf; void *lock; @@ -584,7 +587,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec return; } - if (rr == NULL) { + if (rr == nullptr) { return; } @@ -622,14 +625,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec static void current_scene_update(void *rjv, Scene *scene) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); rj->current_scene = scene; rj->iuser.scene = scene; } static void render_startjob(void *rjv, short *stop, short *do_update, float *progress) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); rj->stop = stop; rj->do_update = do_update; @@ -657,7 +660,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro rj->write_still); } - RE_SetReports(rj->re, NULL); + RE_SetReports(rj->re, nullptr); } static void render_image_restore_layer(RenderJob *rj) @@ -665,15 +668,16 @@ static void render_image_restore_layer(RenderJob *rj) wmWindowManager *wm; /* image window, compo node users */ - for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */ + for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm; + wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */ wmWindow *win; - for (win = wm->windows.first; win; win = win->next) { + for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area == rj->area) { if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); if (RE_HasSingleLayer(rj->re)) { /* For single layer renders keep the active layer @@ -699,7 +703,7 @@ static void render_image_restore_layer(RenderJob *rj) static void render_endjob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); /* this render may be used again by the sequencer without the active * 'Render' where the callbacks would be re-assigned. assign dummy callbacks @@ -725,7 +729,8 @@ static void render_endjob(void *rjv) rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE; if (rj->single_layer) { - nodeUpdateID(rj->scene->nodetree, &rj->scene->id); + BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id); + BKE_ntree_update_main(rj->main, nullptr); WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene); } @@ -735,7 +740,7 @@ static void render_endjob(void *rjv) /* XXX render stability hack */ G.is_rendering = false; - WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL); + WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr); /* Partial render result will always update display buffer * for first render layer only. This is nice because you'll @@ -772,7 +777,7 @@ static void render_endjob(void *rjv) * and using one from Global will unlock exactly the same manager as * was locked before running the job. */ - WM_set_locked_interface(G_MAIN->wm.first, false); + WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false); DEG_tag_on_visible_update(G_MAIN, false); } } @@ -780,7 +785,7 @@ static void render_endjob(void *rjv) /* called by render, check job 'stop' value or the global */ static int render_breakjob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); if (G.is_break) { return 1; @@ -807,7 +812,7 @@ static int render_break(void *UNUSED(rjv)) /* maybe need a way to get job send notifier? */ static void render_drawlock(void *rjv, bool lock) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); /* If interface is locked, renderer callback shall do nothing. */ if (!rj->interface_locked) { @@ -869,11 +874,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene) BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true); /* Go over all the visible objects. */ - for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { + for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm; + wm = static_cast<wmWindowManager *>(wm->id.next)) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { ViewLayer *view_layer = WM_window_get_active_view_layer(win); - for (base = view_layer->object_bases.first; base; base = base->next) { + for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) { clean_viewport_memory_base(base); } } @@ -891,7 +897,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *active_layer = CTX_data_view_layer(C); - ViewLayer *single_layer = NULL; + ViewLayer *single_layer = nullptr; RenderEngineType *re_type = RE_engines_find(scene->r.engine); Render *re; wmJob *wm_job; @@ -900,13 +906,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); - View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL; - struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr; + struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr; const char *name; ScrArea *area; /* Cannot do render if there is not this function. */ - if (re_type->render == NULL) { + if (re_type->render == nullptr) { return OPERATOR_CANCELLED; } @@ -962,7 +968,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even area = render_view_open(C, event->xy[0], event->xy[1], op->reports); /* job custom data */ - rj = MEM_callocN(sizeof(RenderJob), "render job"); + rj = MEM_cnew<RenderJob>("render job"); rj->main = bmain; rj->scene = scene; rj->current_scene = rj->scene; @@ -986,7 +992,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings); if (area) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); rj->orig_layer = sima->iuser.layer; } @@ -1030,7 +1036,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); - WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); + WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob); if (RNA_struct_property_is_set(op->ptr, "layer")) { WM_jobs_delay_start(wm_job, 0.2); @@ -1038,7 +1044,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* get a render result image, and make sure it is empty */ ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima, true); rj->image = ima; @@ -1098,32 +1104,32 @@ void RENDER_OT_render(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "animation", - 0, + false, "Animation", "Render files from the animation range of this scene"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_boolean( ot->srna, "write_still", - 0, + false, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)"); prop = RNA_def_boolean(ot->srna, "use_viewport", - 0, + false, "Use 3D Viewport", "When inside a 3D viewport, use layers and camera of the viewport"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "layer", - NULL, + nullptr, RE_MAXNAME, "Render Layer", "Single render layer to re-render (used only when animation is disabled)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "scene", - NULL, + nullptr, MAX_ID_NAME - 2, "Scene", "Scene to render, current scene if not specified"); @@ -1139,7 +1145,7 @@ Scene *ED_render_job_get_scene(const bContext *C) return rj->scene; } - return NULL; + return nullptr; } Scene *ED_render_job_get_current_scene(const bContext *C) @@ -1149,7 +1155,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C) if (rj) { return rj->current_scene; } - return NULL; + return nullptr; } /* Motion blur curve preset */ @@ -1180,7 +1186,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot) {CURVE_PRESET_LINE, "LINE", 0, "Line", ""}, {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""}, {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; ot->name = "Shutter Curve Preset"; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc index 1e1a95f2965..8d2e7e9b453 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.cc @@ -21,9 +21,9 @@ * \ingroup render */ -#include <math.h> -#include <stddef.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstring> #include "MEM_guardedalloc.h" @@ -82,7 +82,7 @@ #include "GPU_framebuffer.h" #include "GPU_matrix.h" -#include "render_intern.h" +#include "render_intern.hh" /* Define this to get timing information. */ // #define DEBUG_TIME @@ -95,7 +95,7 @@ * For really highres renders it might fail still. */ #define MAX_SCHEDULED_FRAMES 8 -typedef struct OGLRender { +struct OGLRender { Main *bmain; Render *re; Scene *scene; @@ -159,7 +159,7 @@ typedef struct OGLRender { #ifdef DEBUG_TIME double time_start; #endif -} OGLRender; +}; static bool screen_opengl_is_multiview(OGLRender *oglrender) { @@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender) RegionView3D *rv3d = oglrender->rv3d; RenderData *rd = &oglrender->scene->r; - if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) { + if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) { return false; } return (rd->scemode & R_MULTIVIEW) && - ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera)); + ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera)); } static void screen_opengl_views_setup(OGLRender *oglrender) @@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender) if (!is_multiview) { /* we only have one view when multiview is off */ - rv = rr->views.first; + rv = static_cast<RenderView *>(rr->views.first); - if (rv == NULL) { - rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + if (rv == nullptr) { + rv = MEM_cnew<RenderView>("new opengl render view"); BLI_addtail(&rr->views, rv); } @@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } /* remove all the views that are not needed */ - rv = rr->views.last; + rv = static_cast<RenderView *>(rr->views.last); while (rv) { - srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)); + srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name))); if (BKE_scene_multiview_is_render_view_active(rd, srv)) { rv = rv->prev; } @@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } /* create all the views that are needed */ - for (srv = rd->views.first; srv; srv = srv->next) { + for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) { continue; } - rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)); + rv = static_cast<RenderView *>( + BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name))); - if (rv == NULL) { - rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + if (rv == nullptr) { + rv = MEM_cnew<RenderView>("new opengl render view"); BLI_strncpy(rv->name, srv->name, sizeof(rv->name)); BLI_addtail(&rr->views, rv); } @@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ARegion *region = oglrender->region; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; - Object *camera = NULL; + Object *camera = nullptr; int sizex = oglrender->sizex; int sizey = oglrender->sizey; - const short view_context = (v3d != NULL); + const short view_context = (v3d != nullptr); bool draw_sky = (scene->r.alphamode == R_ADDSKY); - float *rectf = NULL; - uchar *rect = NULL; + float *rectf = nullptr; + uchar *rect = nullptr; const char *viewname = RE_GetActiveRenderView(oglrender->re); - ImBuf *ibuf_result = NULL; + ImBuf *ibuf_result = nullptr; if (oglrender->is_sequencer) { SpaceSeq *sseq = oglrender->sseq; - struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL; + struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr; /* use pre-calculated ImBuf (avoids deadlock), see: */ ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id]; @@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R * TODO(sergey): In the case of output to float container (EXR) * it actually makes sense to keep float buffer instead. */ - if (out->rect_float != NULL) { + if (out->rect_float != nullptr) { IMB_rect_from_float(out); imb_freerectfloatImBuf(out); } @@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_FLAG_RENDER_VIEWPORT; - gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"); + gp_rect = static_cast<uchar *>( + MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect")); GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { @@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph, scene, - v3d->shading.type, + static_cast<eDrawType>(v3d->shading.type), v3d, region, sizex, @@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R else { ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, - NULL, + nullptr, OB_SOLID, scene->camera, oglrender->sizex, @@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R } } - if (ibuf_result != NULL) { + if (ibuf_result != nullptr) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { - BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4); + BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); @@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, - NULL); + nullptr); /* write images as individual images or stereo */ BKE_render_result_stamp_info(scene, scene->camera, rr, false); @@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) } rr = RE_AcquireResultRead(oglrender->re); - for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) { + for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; + rv = rv->next, view_id++) { BLI_assert(view_id < oglrender->views_len); RE_SetActiveRenderView(oglrender->re, rv->name); oglrender->view_id = view_id; @@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt) { - if (adt == NULL || adt->action == NULL) { + if (adt == nullptr || adt->action == nullptr) { return; } @@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An int frame_end = PEFRA; LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) { - if (fcu->driver != NULL || fcu->fpt != NULL) { + if (fcu->driver != nullptr || fcu->fpt != nullptr) { /* Drivers have values for any point in time, so to get "the keyed frames" they are * useless. Same for baked FCurves, they also have keys for every frame, which is not * useful for rendering the keyed subset of the frames. */ @@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender, const bGPdata *gp) { - if (gp == NULL) { + if (gp == nullptr) { return; } @@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) { ID **id_p = cb_data->id_pointer; - if (*id_p == NULL) { + if (*id_p == nullptr) { return IDWALK_RET_NOP; } ID *id = *id_p; @@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_STOP_RECURSION; } - OGLRender *oglrender = cb_data->user_data; + OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data); /* Whitelist of datablocks to follow pointers into. */ const ID_Type id_type = GS(id->name); @@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender) /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */ BKE_library_foreach_ID_link( - NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE); + nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE); } CTX_DATA_END; } @@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); - const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth : - R_IMF_CHAN_DEPTH_32; + const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>( + (is_animation) ? scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32); char err_out[256] = "unknown"; if (G.background) { @@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) is_view_context = false; } - if (!is_view_context && scene->camera == NULL) { + if (!is_view_context && scene->camera == nullptr) { BKE_report(op->reports, RPT_ERROR, "Scene has no camera"); return false; } @@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) } /* allocate opengl render */ - oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender"); + oglrender = MEM_cnew<OGLRender>("OGLRender"); op->customdata = oglrender; oglrender->ofs = ofs; @@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->is_sequencer = is_sequencer; if (is_sequencer) { oglrender->sseq = CTX_wm_space_seq(C); - ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__); + ImBuf **ibufs_arr = static_cast<ImBuf **>( + MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__)); oglrender->seq_data.ibufs_arr = ibufs_arr; } @@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* so quad view renders camera */ ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region); - oglrender->rv3d = oglrender->region->regiondata; + oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata); /* MUST be cleared on exit */ memset(&oglrender->scene->customdata_mask_modal, @@ -832,13 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* create image and image user */ oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(oglrender->scene, oglrender->ima, true); oglrender->iuser.scene = scene; /* create render result */ - RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL); + RE_InitState( + oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr); /* create render views */ screen_opengl_views_setup(oglrender); @@ -848,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->win = win; oglrender->totvideos = 0; - oglrender->mh = NULL; - oglrender->movie_ctx_arr = NULL; + oglrender->mh = nullptr; + oglrender->movie_ctx_arr = nullptr; if (is_animation) { if (is_render_keyed_only) { @@ -866,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) BLI_spin_init(&oglrender->reports_lock); } else { - oglrender->task_pool = NULL; + oglrender->task_pool = nullptr; } oglrender->num_scheduled_frames = 0; BLI_mutex_init(&oglrender->task_mutex); @@ -959,7 +965,7 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) static void screen_opengl_render_cancel(bContext *C, wmOperator *op) { - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); } /* share between invoke and exec */ @@ -969,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) OGLRender *oglrender; Scene *scene; - oglrender = op->customdata; + oglrender = static_cast<OGLRender *>(op->customdata); scene = oglrender->scene; oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r); @@ -983,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) &scene->r, oglrender->sizex, oglrender->sizey, &width, &height); oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); - if (oglrender->mh == NULL) { + if (oglrender->mh == nullptr) { BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported"); screen_opengl_render_end(C, oglrender); return false; } - oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); + oglrender->movie_ctx_arr = static_cast<void **>( + MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies")); for (i = 0; i < oglrender->totvideos; i++) { Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph); @@ -1017,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) return true; } -typedef struct WriteTaskData { +struct WriteTaskData { RenderResult *rr; Scene tmp_scene; -} WriteTaskData; +}; static void write_result_func(TaskPool *__restrict pool, void *task_data_v) { @@ -1073,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, - NULL); + nullptr); BKE_render_result_stamp_info(scene, scene->camera, rr, false); - ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name); + ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name); if (!ok) { BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name); } } - if (reports.list.first != NULL) { + if (reports.list.first != nullptr) { BLI_spin_lock(&oglrender->reports_lock); - for (Report *report = reports.list.first; report != NULL; report = report->next) { - BKE_report(oglrender->reports, report->type, report->message); + for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr; + report = report->next) { + BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message); } BLI_spin_unlock(&oglrender->reports_lock); } @@ -1105,7 +1113,7 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr) return false; } Scene *scene = oglrender->scene; - WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data"); + WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data"); task_data->rr = rr; task_data->tmp_scene = *scene; BLI_mutex_lock(&oglrender->task_mutex); @@ -1114,18 +1122,18 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr) BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex); } BLI_mutex_unlock(&oglrender->task_mutex); - BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL); + BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr); return true; } static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { - OGLRender *oglrender = op->customdata; + OGLRender *oglrender = static_cast<OGLRender *>(op->customdata); Scene *scene = oglrender->scene; Depsgraph *depsgraph = oglrender->depsgraph; char name[FILE_MAX]; bool ok = false; - const bool view_context = (oglrender->v3d != NULL); + const bool view_context = (oglrender->v3d != nullptr); bool is_movie; RenderResult *rr; @@ -1148,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, - NULL); + nullptr); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BLI_spin_lock(&oglrender->reports_lock); @@ -1177,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) BKE_scene_camera_switch_update(scene); } - if (oglrender->render_frames == NULL || + if (oglrender->render_frames == nullptr || BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) { /* render into offscreen buffer */ screen_opengl_render_apply(C, oglrender); @@ -1185,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) /* save to disk */ rr = RE_AcquireResultRead(oglrender->re); - RenderResult *new_rr = RE_DuplicateRenderResult(rr); - RE_ReleaseResult(oglrender->re); + { + RenderResult *new_rr = RE_DuplicateRenderResult(rr); + RE_ReleaseResult(oglrender->re); - ok = schedule_write_result(oglrender, new_rr); + ok = schedule_write_result(oglrender, new_rr); + } finally: /* Step the frame and bail early if needed */ @@ -1197,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */ /* stop at the end or on error */ if (CFRA >= PEFRA || !ok) { - screen_opengl_render_end(C, op->customdata); - return 0; + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); + return false; } - return 1; + return true; } static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event) { - OGLRender *oglrender = op->customdata; + OGLRender *oglrender = static_cast<OGLRender *>(op->customdata); const bool anim = RNA_boolean_get(op->ptr, "animation"); bool ret; @@ -1214,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent case EVT_ESCKEY: /* cancel */ oglrender->pool_ok = false; /* Flag pool for cancel. */ - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; case TIMER: /* render frame? */ @@ -1231,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene); if (anim == 0) { - screen_opengl_render_apply(C, op->customdata); - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata)); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; } @@ -1261,7 +1271,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven } } - oglrender = op->customdata; + oglrender = static_cast<OGLRender *>(op->customdata); render_view_open(C, event->xy[0], event->xy[1], op->reports); /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */ @@ -1284,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op) if (!is_animation) { /* same as invoke */ /* render image */ - screen_opengl_render_apply(C, op->customdata); - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata)); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; } @@ -1312,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C), struct PointerRNA *ptr) { if (!RNA_boolean_get(ptr, "animation")) { - return NULL; + return nullptr; } if (RNA_boolean_get(ptr, "render_keyed_only")) { @@ -1344,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "animation", - 0, + false, "Animation", "Render files from the animation range of this scene"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "render_keyed_only", - 0, + false, "Render Keyframes Only", "Render only those frames where selected objects have a key in their " "animation data. Only used when rendering animation"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( - ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display"); + ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( ot->srna, "write_still", - 0, + false, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "view_context", - 1, + true, "View Context", "Use the current 3D view for rendering, else use scene settings"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc index e0aa02b354d..0f10d186e6e 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.cc @@ -21,7 +21,7 @@ * \ingroup edrend */ -#include <stdlib.h> +#include <cstdlib> #include "BLI_utildefines.h" @@ -29,11 +29,11 @@ #include "WM_api.h" -#include "render_intern.h" /* own include */ +#include "render_intern.hh" /* own include */ /***************************** render ***********************************/ -void ED_operatortypes_render(void) +void ED_operatortypes_render() { WM_operatortype_append(OBJECT_OT_material_slot_add); WM_operatortype_append(OBJECT_OT_material_slot_remove); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc index 409430d28f1..55e37f85071 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.cc @@ -23,9 +23,9 @@ /* global includes */ -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstdlib> +#include <cstring> #ifndef WIN32 # include <unistd.h> @@ -116,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect); /** \name Local Structs * \{ */ -typedef struct ShaderPreview { +struct ShaderPreview { /* from wmJob */ void *owner; short *stop, *do_update; @@ -137,31 +137,32 @@ typedef struct ShaderPreview { int sizex, sizey; uint *pr_rect; - int pr_method; + ePreviewRenderMethod pr_method; bool own_id_copy; Main *bmain; Main *pr_main; -} ShaderPreview; +}; -typedef struct IconPreviewSize { +struct IconPreviewSize { struct IconPreviewSize *next, *prev; int sizex, sizey; uint *rect; -} IconPreviewSize; +}; -typedef struct IconPreview { +struct IconPreview { Main *bmain; - Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */ + Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */ Scene *scene; void *owner; - ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ + ID *id, + *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ ListBase sizes; - /* May be NULL, is used for rendering IDs that require some other object for it to be applied on - * before the ID can be represented as an image, for example when rendering an Action. */ + /* May be nullptr, is used for rendering IDs that require some other object for it to be applied + * on before the ID can be represented as an image, for example when rendering an Action. */ struct Object *active_object; -} IconPreview; +}; /** \} */ @@ -169,18 +170,18 @@ typedef struct IconPreview { /** \name Preview for Buttons * \{ */ -static Main *G_pr_main = NULL; -static Main *G_pr_main_grease_pencil = NULL; +static Main *G_pr_main = nullptr; +static Main *G_pr_main_grease_pencil = nullptr; #ifndef WITH_HEADLESS static Main *load_main_from_memory(const void *blend, int blend_size) { const int fileflags = G.fileflags; - Main *bmain = NULL; + Main *bmain = nullptr; BlendFileData *bfd; G.fileflags |= G_FILE_NO_UI; - bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL); + bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr); if (bfd) { bmain = bfd->main; @@ -192,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size) } #endif -void ED_preview_ensure_dbase(void) +void ED_preview_ensure_dbase() { #ifndef WITH_HEADLESS static bool base_initialized = false; @@ -212,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene) return (type->flag & RE_USE_PREVIEW) != 0; } -static bool preview_method_is_render(int pr_method) +static bool preview_method_is_render(const ePreviewRenderMethod pr_method) { return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER); } -void ED_preview_free_dbase(void) +void ED_preview_free_dbase() { if (G_pr_main) { BKE_main_free(G_pr_main); @@ -230,11 +231,11 @@ void ED_preview_free_dbase(void) static Scene *preview_get_scene(Main *pr_main) { - if (pr_main == NULL) { - return NULL; + if (pr_main == nullptr) { + return nullptr; } - return pr_main->scenes.first; + return static_cast<Scene *>(pr_main->scenes.first); } static const char *preview_collection_name(const ePreviewType pr_type) @@ -276,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce) static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type) { /* Set appropriate layer as visible. */ - LayerCollection *lc = view_layer->layer_collections.first; + LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first); const char *collection_name = preview_collection_name(pr_type); - for (lc = lc->layer_collections.first; lc; lc = lc->next) { + for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) { if (STREQ(lc->collection->id.name + 2, collection_name)) { lc->collection->flag &= ~COLLECTION_HIDE_RENDER; } @@ -308,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main, } const char *material_name = preview_floor_material_name(scene, pr_method); - Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2); + Material *mat = static_cast<Material *>( + BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2)); if (mat) { me->mat[0] = mat; } @@ -329,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main, } } if (base->object->type == OB_MESH) { - switch_preview_floor_material(pr_main, base->object->data, scene, pr_method); + switch_preview_floor_material( + pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method); } } } @@ -348,16 +351,16 @@ static void set_preview_visibility(Main *pr_main, static World *preview_get_localized_world(ShaderPreview *sp, World *world) { - if (world == NULL) { - return NULL; + if (world == nullptr) { + return nullptr; } - if (sp->worldcopy != NULL) { + if (sp->worldcopy != nullptr) { return sp->worldcopy; } - ID *id_copy = BKE_id_copy_ex(NULL, + ID *id_copy = BKE_id_copy_ex(nullptr, &world->id, - NULL, + nullptr, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); sp->worldcopy = (World *)id_copy; @@ -367,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) static ID *duplicate_ids(ID *id, const bool allow_failure) { - if (id == NULL) { + if (id == nullptr) { /* Non-ID preview render. */ - return NULL; + return nullptr; } switch (GS(id->name)) { @@ -379,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure) case ID_LA: case ID_WO: { BLI_assert(BKE_previewimg_id_supports_jobs(id)); - ID *id_copy = BKE_id_copy_ex( - NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); + ID *id_copy = BKE_id_copy_ex(nullptr, + id, + nullptr, + LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | + LIB_ID_COPY_NO_ANIMDATA); return id_copy; } /* These support threading, but don't need duplicating. */ case ID_IM: case ID_BR: BLI_assert(BKE_previewimg_id_supports_jobs(id)); - return NULL; + return nullptr; default: if (!allow_failure) { BLI_assert_msg(0, "ID type preview not supported."); } - return NULL; + return nullptr; } } @@ -419,13 +425,14 @@ static World *preview_get_world(Main *pr_main, const ID_Type id_type, const ePreviewRenderMethod pr_method) { - World *result = NULL; + World *result = nullptr; const char *world_name = preview_world_name(sce, id_type, pr_method); - result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2); + result = static_cast<World *>( + BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2)); /* No world found return first world. */ - if (result == NULL) { - result = pr_main->worlds.first; + if (result == nullptr) { + result = static_cast<World *>(pr_main->worlds.first); } BLI_assert_msg(result, "Preview file has no world."); @@ -454,7 +461,7 @@ static World *preview_prepare_world(Main *pr_main, } /* call this with a pointer to initialize preview scene */ -/* call this with NULL to restore assigned ID pointers in preview scene */ +/* call this with nullptr to restore assigned ID pointers in preview scene */ static Scene *preview_prepare_scene( Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp) { @@ -465,7 +472,7 @@ static Scene *preview_prepare_scene( sce = preview_get_scene(pr_main); if (sce) { - ViewLayer *view_layer = sce->view_layers.first; + ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first); /* Only enable the combined renderpass */ view_layer->passflag = SCE_PASS_COMBINED; @@ -491,7 +498,8 @@ static Scene *preview_prepare_scene( sce->r.cfra = scene->r.cfra; /* Setup the world. */ - sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method); + sce->world = preview_prepare_world( + pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method); if (id_type == ID_TE) { /* Texture is not actually rendered with engine, just set dummy value. */ @@ -499,13 +507,13 @@ static Scene *preview_prepare_scene( } if (id_type == ID_MA) { - Material *mat = NULL, *origmat = (Material *)id; + Material *mat = nullptr, *origmat = (Material *)id; if (origmat) { /* work on a copy */ - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); mat = sp->matcopy = (Material *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->materials, mat); /* Use current scene world for lighting. */ @@ -523,10 +531,10 @@ static Scene *preview_prepare_scene( } /* For grease pencil, always use sphere for icon renders. */ - const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER && - sp->pr_main == G_pr_main_grease_pencil) ? - MA_SPHERE_A : - mat->pr_type; + const ePreviewType preview_type = static_cast<ePreviewType>( + (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ? + MA_SPHERE_A : + mat->pr_type); set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method); } else { @@ -555,23 +563,23 @@ static Scene *preview_prepare_scene( } } else if (id_type == ID_TE) { - Tex *tex = NULL, *origtex = (Tex *)id; + Tex *tex = nullptr, *origtex = (Tex *)id; if (origtex) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); tex = sp->texcopy = (Tex *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->textures, tex); } } else if (id_type == ID_LA) { - Light *la = NULL, *origla = (Light *)id; + Light *la = nullptr, *origla = (Light *)id; /* work on a copy */ if (origla) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); la = sp->lampcopy = (Light *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->lights, la); } @@ -594,12 +602,12 @@ static Scene *preview_prepare_scene( } } else if (id_type == ID_WO) { - World *wrld = NULL, *origwrld = (World *)id; + World *wrld = nullptr, *origwrld = (World *)id; if (origwrld) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); wrld = sp->worldcopy = (World *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->worlds, wrld); } @@ -610,7 +618,7 @@ static Scene *preview_prepare_scene( return sce; } - return NULL; + return nullptr; } /* new UI convention: draw is in pixel space already. */ @@ -647,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect /* test if something rendered ok */ re = RE_GetRender(name); - if (re == NULL) { + if (re == nullptr) { return false; } @@ -659,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect } else { /* possible the job clears the views but we're still drawing T45496 */ - rv = NULL; + rv = nullptr; } if (rv && rv->rectf) { @@ -670,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); if (rres.rectx && rres.recty) { - uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), - "ed_preview_draw_rect"); + uchar *rect_byte = static_cast<uchar *>( + MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect")); float fx = rect->xmin + offx; float fy = rect->ymin; @@ -679,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex( - &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL); + immDrawPixelsTex(&state, + fx, + fy, + rres.rectx, + rres.recty, + GPU_RGBA8, + false, + rect_byte, + 1.0f, + 1.0f, + nullptr); MEM_freeN(rect_byte); - ok = 1; + ok = true; } } } @@ -703,7 +720,7 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceProperties *sbuts = CTX_wm_space_properties(C); - ShaderPreview *sp = WM_jobs_customdata(wm, area); + ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area)); rcti newrect; int ok; int newx = BLI_rcti_size_x(rect); @@ -729,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r /* start a new preview render job if signaled through sbuts->preview, * if no render result was found and no preview render job is running, * or if the job is running and the size of preview changed */ - if ((sbuts != NULL && sbuts->preview) || + if ((sbuts != nullptr && sbuts->preview) || (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) || (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) { - if (sbuts != NULL) { + if (sbuts != nullptr) { sbuts->preview = 0; } ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER); @@ -796,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe * viewport displays. */ CFRA = preview_data->cfra; - ViewLayer *view_layer = scene->view_layers.first; + ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first); Depsgraph *depsgraph = DEG_graph_new( preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT); - BLI_assert(preview_data->object != NULL); + BLI_assert(preview_data->object != nullptr); BLI_addtail(&preview_data->pr_main->objects, preview_data->object); BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object); @@ -831,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized) { Main *preview_main = BKE_main_new(); - const float pixelsize_old = U.pixelsize; char err_out[256] = "unknown"; BLI_assert(preview->id_copy && (preview->id_copy != preview->id)); - struct ObjectPreviewData preview_data = { - .pr_main = preview_main, - /* Act on a copy. */ - .object = (Object *)preview->id_copy, - .cfra = preview->scene->r.cfra, - .sizex = preview_sized->sizex, - .sizey = preview_sized->sizey, - }; + struct ObjectPreviewData preview_data = {}; + preview_data.pr_main = preview_main; + /* Act on a copy. */ + preview_data.object = (Object *)preview->id_copy; + preview_data.cfra = preview->scene->r.cfra; + preview_data.sizex = preview_sized->sizex; + preview_data.sizey = preview_sized->sizey; + Depsgraph *depsgraph; Scene *scene = object_preview_scene_create(&preview_data, &depsgraph); /* Ownership is now ours. */ - preview->id_copy = NULL; - - U.pixelsize = 2.0f; + preview->id_copy = nullptr; View3DShading shading; BKE_screen_view3d_shading_init(&shading); @@ -868,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview IB_rect, V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS, R_ALPHAPREMUL, - NULL, - NULL, + nullptr, + nullptr, err_out); /* TODO: color-management? */ - U.pixelsize = pixelsize_old; - if (ibuf) { icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect); IMB_freeImBuf(ibuf); @@ -893,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview static struct PoseBackup *action_preview_render_prepare(IconPreview *preview) { Object *object = preview->active_object; - if (object == NULL) { + if (object == nullptr) { WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering"); - return NULL; + return nullptr; } - if (object->pose == NULL) { + if (object->pose == nullptr) { WM_reportf(RPT_WARNING, "Object %s has no pose, unable to apply the Action before rendering", object->id.name + 2); - return NULL; + return nullptr; } /* Create a backup of the current pose. */ @@ -922,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview) static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup) { - if (pose_backup == NULL) { + if (pose_backup == nullptr) { return; } ED_pose_backup_restore(pose_backup); @@ -942,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview /* Not all code paths that lead to this function actually provide a depsgraph. * The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does, * but WM_OT_previews_ensure does not. */ - BLI_assert(depsgraph != NULL); + BLI_assert(depsgraph != nullptr); BLI_assert(preview->scene == DEG_get_input_scene(depsgraph)); /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */ @@ -950,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *camera_eval = scene_eval->camera; - if (camera_eval == NULL) { + if (camera_eval == nullptr) { printf("Scene has no camera, unable to render preview of %s without it.\n", preview->id->name + 2); return; @@ -959,7 +971,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview /* This renders with the Workbench engine settings stored on the Scene. */ ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene_eval, - NULL, + nullptr, OB_SOLID, camera_eval, preview_sized->sizex, @@ -967,8 +979,8 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview IB_rect, V3D_OFSDRAW_NONE, R_ADDSKY, - NULL, - NULL, + nullptr, + nullptr, err_out); action_preview_render_cleanup(preview, pose_backup); @@ -994,7 +1006,7 @@ static void shader_preview_update(void *spv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) { - ShaderPreview *sp = spv; + ShaderPreview *sp = static_cast<ShaderPreview *>(spv); *(sp->do_update) = true; } @@ -1002,7 +1014,7 @@ static void shader_preview_update(void *spv, /* called by renderer, checks job value */ static int shader_preview_break(void *spv) { - ShaderPreview *sp = spv; + ShaderPreview *sp = static_cast<ShaderPreview *>(spv); return *(sp->stop); } @@ -1020,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend /* This is needed otherwise no RenderResult is created. */ sce->r.scemode &= ~R_BUTS_PREVIEW; - RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL); + RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr); RE_SetScene(re, sce); /* Create buffer in empty RenderView created in the init step. */ RenderResult *rr = RE_AcquireResultWrite(re); RenderView *rv = (RenderView *)rr->views.first; - rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result"); + rv->rectf = static_cast<float *>( + MEM_callocN(sizeof(float[4]) * width * height, "texture render result")); RE_ReleaseResult(re); /* Get texture image pool (if any) */ @@ -1099,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs /* get the stuff from the builtin preview dbase */ sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp); - if (sce == NULL) { + if (sce == nullptr) { return; } @@ -1112,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs re = RE_GetRender(name); /* full refreshed render from first tile */ - if (re == NULL) { + if (re == nullptr) { re = RE_NewRender(name); } @@ -1162,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs } /* unassign the pointers, reset vars */ - preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp); + preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp); /* XXX bad exception, end-exec is not being called in render, because it uses local main. */ #if 0 @@ -1177,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs /* runs inside thread for material and icons */ static void shader_preview_startjob(void *customdata, short *stop, short *do_update) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); sp->stop = stop; sp->do_update = do_update; @@ -1208,17 +1221,17 @@ static void preview_id_copy_free(ID *id) static void shader_preview_free(void *customdata) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); Main *pr_main = sp->pr_main; - ID *main_id_copy = NULL; - ID *sub_id_copy = NULL; + ID *main_id_copy = nullptr; + ID *sub_id_copy = nullptr; if (sp->matcopy) { main_id_copy = (ID *)sp->matcopy; BLI_remlink(&pr_main->materials, sp->matcopy); } if (sp->texcopy) { - BLI_assert(main_id_copy == NULL); + BLI_assert(main_id_copy == nullptr); main_id_copy = (ID *)sp->texcopy; BLI_remlink(&pr_main->textures, sp->texcopy); } @@ -1233,7 +1246,7 @@ static void shader_preview_free(void *customdata) BLI_remlink(&pr_main->worlds, sp->worldcopy); } if (sp->lampcopy) { - BLI_assert(main_id_copy == NULL); + BLI_assert(main_id_copy == nullptr); main_id_copy = (ID *)sp->lampcopy; BLI_remlink(&pr_main->lights, sp->lampcopy); } @@ -1275,7 +1288,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush) BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id)); /* Use default color-spaces for brushes. */ - brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); + brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr); /* otherwise lets try to find it in other directories */ if (!(brush->icon_imbuf)) { @@ -1286,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush) if (path[0]) { /* Use default color spaces. */ - brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); + brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr); } } @@ -1312,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect) short ex, ey, dx, dy; /* paranoia test */ - if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { + if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { return; } @@ -1342,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect) IMB_scalefastImBuf(ima, ex, ey); /* if needed, convert to 32 bits */ - if (ima->rect == NULL) { + if (ima->rect == nullptr) { IMB_rect_from_float(ima); } @@ -1370,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha) static void icon_preview_startjob(void *customdata, short *stop, short *do_update) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); if (sp->pr_method == PR_ICON_DEFERRED) { - PreviewImage *prv = sp->owner; + PreviewImage *prv = static_cast<PreviewImage *>(sp->owner); ImBuf *thumb; - char *deferred_data = PRV_DEFERRED_DATA(prv); - int source = deferred_data[0]; + char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv)); + ThumbSource source = static_cast<ThumbSource>(deferred_data[0]); char *path = &deferred_data[1]; // printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path); @@ -1395,15 +1408,15 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat ID *id = sp->id; short idtype = GS(id->name); - BLI_assert(id != NULL); + BLI_assert(id != nullptr); if (idtype == ID_IM) { Image *ima = (Image *)id; - ImBuf *ibuf = NULL; + ImBuf *ibuf = nullptr; ImageUser iuser; BKE_imageuser_default(&iuser); - if (ima == NULL) { + if (ima == nullptr) { return; } @@ -1414,9 +1427,9 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat /* elubie: this needs to be changed: here image is always loaded if not * already there. Very expensive for large images. Need to find a way to * only get existing ibuf */ - ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { - BKE_image_release_ibuf(ima, ibuf, NULL); + ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr); + if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { + BKE_image_release_ibuf(ima, ibuf, nullptr); return; } @@ -1424,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat *do_update = true; - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_release_ibuf(ima, ibuf, nullptr); } else if (idtype == ID_BR) { Brush *br = (Brush *)id; @@ -1468,7 +1481,7 @@ static void common_preview_startjob(void *customdata, short *do_update, float *UNUSED(progress)) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) { icon_preview_startjob(customdata, stop, do_update); @@ -1484,12 +1497,12 @@ static void common_preview_startjob(void *customdata, */ static void other_id_types_preview_render(IconPreview *ip, IconPreviewSize *cur_size, - const int pr_method, + const ePreviewRenderMethod pr_method, short *stop, short *do_update, float *progress) { - ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); + ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview"); /* These types don't use the ShaderPreview mess, they have their own types and functions. */ BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB)); @@ -1505,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip, sp->id_copy = ip->id_copy; sp->bmain = ip->bmain; sp->own_id_copy = false; - Material *ma = NULL; + Material *ma = nullptr; if (sp->pr_method == PR_ICON_RENDER) { BLI_assert(ip->id); @@ -1515,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip, ma = (Material *)ip->id; } - if ((ma == NULL) || (ma->gp_style == NULL)) { + if ((ma == nullptr) || (ma->gp_style == nullptr)) { sp->pr_main = G_pr_main; } else { @@ -1553,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata, IconPreview *ip = (IconPreview *)customdata; IconPreviewSize *cur_size; - for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) { - PreviewImage *prv = ip->owner; + for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size; + cur_size = cur_size->next) { + PreviewImage *prv = static_cast<PreviewImage *>(ip->owner); /* Is this a render job or a deferred loading job? */ - const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER; + const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : + PR_ICON_RENDER; if (*stop) { break; @@ -1573,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, * they can skip this test. */ /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not * necessary to know here what happens inside lower-level functions. */ - const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC); + const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC); if (!use_solid_render_mode && preview_method_is_render(pr_method) && !check_engine_supports_preview(ip->scene)) { continue; @@ -1586,7 +1601,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, } #endif - if (ip->id != NULL) { + if (ip->id != nullptr) { switch (GS(ip->id->name)) { case ID_OB: if (object_preview_is_type_supported((Object *)ip->id)) { @@ -1599,7 +1614,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, action_preview_render(ip, cur_size); continue; default: - /* Fall through to the same code as the `ip->id == NULL` case. */ + /* Fall through to the same code as the `ip->id == nullptr` case. */ break; } } @@ -1609,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) { - IconPreviewSize *cur_size = ip->sizes.first, *new_size; + IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); while (cur_size) { if (cur_size->sizex == sizex && cur_size->sizey == sizey) { @@ -1620,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si cur_size = cur_size->next; } - new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); + IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize"); new_size->sizex = sizex; new_size->sizey = sizey; new_size->rect = rect; @@ -1630,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si static void icon_preview_endjob(void *customdata) { - IconPreview *ip = customdata; + IconPreview *ip = static_cast<IconPreview *>(customdata); if (ip->id) { @@ -1647,7 +1662,7 @@ static void icon_preview_endjob(void *customdata) for (i = 0; i < NUM_ICON_SIZES; i++) { if (prv_img->gputexture[i]) { GPU_texture_free(prv_img->gputexture[i]); - prv_img->gputexture[i] = NULL; + prv_img->gputexture[i] = nullptr; WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id); } } @@ -1656,7 +1671,7 @@ static void icon_preview_endjob(void *customdata) } if (ip->owner) { - PreviewImage *prv_img = ip->owner; + PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner); prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) { @@ -1685,20 +1700,20 @@ static void icon_preview_free(void *customdata) bool ED_preview_id_is_supported(const ID *id) { - if (id == NULL) { + if (id == nullptr) { return false; } if (GS(id->name) == ID_OB) { return object_preview_is_type_supported((const Object *)id); } - return BKE_previewimg_id_get_p(id) != NULL; + return BKE_previewimg_id_get_p(id) != nullptr; } void ED_preview_icon_render( const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey) { - IconPreview ip = {NULL}; + IconPreview ip = {nullptr}; short stop = false, update = false; float progress = 0.0f; @@ -1721,7 +1736,7 @@ void ED_preview_icon_render( icon_preview_endjob(&ip); BLI_freelistN(&ip.sizes); - if (ip.id_copy != NULL) { + if (ip.id_copy != nullptr) { preview_id_copy_free(ip.id_copy); } } @@ -1742,10 +1757,10 @@ void ED_preview_icon_job( WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); - ip = MEM_callocN(sizeof(IconPreview), "icon preview"); + ip = MEM_cnew<IconPreview>("icon preview"); /* render all resolutions from suspended job too */ - old_ip = WM_jobs_customdata_get(wm_job); + old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job)); if (old_ip) { BLI_movelisttolist(&ip->sizes, &old_ip->sizes); } @@ -1764,7 +1779,7 @@ void ED_preview_icon_job( /* Special threading hack: * warn main code that this preview is being rendered and cannot be freed... */ { - PreviewImage *prv_img = owner; + PreviewImage *prv_img = static_cast<PreviewImage *>(owner); if (prv_img->tag & PRV_TAG_DEFFERED) { prv_img->tag |= PRV_TAG_DEFFERED_RENDERING; } @@ -1777,7 +1792,8 @@ void ED_preview_icon_job( * Particularly important for heavy scenes and Eevee using OpenGL that blocks * the user interface drawing. */ WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0); - WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); + WM_jobs_callbacks( + wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -1789,7 +1805,7 @@ void ED_preview_shader_job(const bContext *C, MTex *slot, int sizex, int sizey, - int method) + ePreviewRenderMethod method) { Object *ob = CTX_data_active_object(C); wmJob *wm_job; @@ -1814,7 +1830,7 @@ void ED_preview_shader_job(const bContext *C, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); - sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); + sp = MEM_cnew<ShaderPreview>("shader preview"); /* customdata for preview thread */ sp->scene = scene; @@ -1828,7 +1844,7 @@ void ED_preview_shader_job(const bContext *C, sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); - Material *ma = NULL; + Material *ma = nullptr; /* hardcoded preview .blend for Eevee + Cycles, this should be solved * once with custom preview .blend path for external engines */ @@ -1838,7 +1854,7 @@ void ED_preview_shader_job(const bContext *C, ma = (Material *)id; } - if ((ma == NULL) || (ma->gp_style == NULL)) { + if ((ma == nullptr) || (ma->gp_style == nullptr)) { sp->pr_main = G_pr_main; } else { @@ -1855,7 +1871,7 @@ void ED_preview_shader_job(const bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, sp, shader_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); - WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL); + WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -1865,28 +1881,28 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain)) if (wm) { /* This is called to stop all preview jobs before scene data changes, to * avoid invalid memory access. */ - WM_jobs_kill(wm, NULL, common_preview_startjob); - WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes); + WM_jobs_kill(wm, nullptr, common_preview_startjob); + WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes); } } -typedef struct PreviewRestartQueueEntry { +struct PreviewRestartQueueEntry { struct PreviewRestartQueueEntry *next, *prev; enum eIconSizes size; ID *id; -} PreviewRestartQueueEntry; +}; static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue; -void ED_preview_restart_queue_free(void) +void ED_preview_restart_queue_free() { BLI_freelistN(&G_restart_previews_queue); } void ED_preview_restart_queue_add(ID *id, enum eIconSizes size) { - PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__); + PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__); queue_entry->size = size; queue_entry->id = id; BLI_addtail(&G_restart_previews_queue, queue_entry); @@ -1905,7 +1921,7 @@ void ED_preview_restart_queue_work(const bContext *C) } BKE_previewimg_clear_single(preview, queue_entry->size); - UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true); + UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true); BLI_freelinkN(&G_restart_previews_queue, queue_entry); } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc index 54ff25ede28..992bba420c1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.cc @@ -20,8 +20,8 @@ * \ingroup edrend */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -96,7 +96,7 @@ #include "engines/eevee/eevee_lightcache.h" -#include "render_intern.h" /* own include */ +#include "render_intern.hh" /* own include */ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob); @@ -106,7 +106,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob); static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); if (object_materials_supported_poll_ex(C, ob)) { if (BKE_object_is_in_editmode(ob) == true) { return true; @@ -123,7 +123,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_ static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); if (object_materials_supported_poll_ex(C, ob)) { if (BKE_object_is_in_editmode(ob) == false) { return true; @@ -159,7 +159,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob) } /* Material linked to obdata. */ - const ID *data = ob->data; + const ID *data = static_cast<ID *>(ob->data); return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data)); } @@ -188,8 +188,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -238,8 +238,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op) if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -277,7 +277,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) bool changed_multi = false; Object *obact = CTX_data_active_object(C); - const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; + const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr; uint objects_len = 0; Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); @@ -328,7 +328,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data); if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) { + for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) { if (ED_curve_nurb_select_check(v3d, nu)) { changed = true; nu->mat_nr = mat_nr_active; @@ -384,7 +384,7 @@ static int material_slot_de_select(bContext *C, bool select) { bool changed_multi = false; Object *obact = CTX_data_active_object(C); - const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; + const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr; uint objects_len = 0; Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); @@ -432,7 +432,7 @@ static int material_slot_de_select(bContext *C, bool select) int a; if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) { + for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) { if (nu->mat_nr == mat_nr_active) { if (nu->bezt) { a = nu->pntsu; @@ -477,7 +477,7 @@ static int material_slot_de_select(bContext *C, bool select) if (changed) { changed_multi = true; - DEG_id_tag_update(ob->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); } } @@ -545,7 +545,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op)) Material ***matar_object = &ob->mat; - Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__); + Material **matar = static_cast<Material **>( + MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__)); for (int i = ob->totcol; i--;) { matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i]; } @@ -620,7 +621,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__); + slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__)); range_vn_u(slot_remap, ob->totcol, 0); @@ -643,7 +644,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot) static const EnumPropertyItem material_slot_move[] = { {1, "UP", 0, "Up", ""}, {-1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -715,8 +716,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op) if (ob_active->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active); @@ -749,7 +750,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -757,17 +759,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : + nullptr); /* add or copy material */ if (ma) { Material *new_ma = (Material *)BKE_id_copy_ex( - bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); ma = new_ma; } else { const char *name = DATA_("Material"); - if (!(ob != NULL && ob->type == OB_GPENCIL)) { + if (!(ob != nullptr && ob->type == OB_GPENCIL)) { ma = BKE_material_add(bmain, name); } else { @@ -778,10 +781,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) } if (prop) { - if (ob != NULL) { + if (ob != nullptr) { /* Add slot follows user-preferences for creating new slots, * RNA pointer assignment doesn't, see: T60014. */ - if (BKE_object_material_get_p(ob, ob->actcol) == NULL) { + if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) { BKE_object_material_slot_add(bmain, ob); } } @@ -791,7 +794,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&ma->id); RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -823,7 +826,7 @@ void MATERIAL_OT_new(wmOperatorType *ot) static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) { - Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -845,7 +848,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&tex->id); RNA_id_pointer_create(&tex->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -876,7 +879,7 @@ void TEXTURE_OT_new(wmOperatorType *ot) static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) { - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; + World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -884,7 +887,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy world */ if (wo) { World *new_wo = (World *)BKE_id_copy_ex( - bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); wo = new_wo; } else { @@ -902,7 +905,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&wo->id); RNA_id_pointer_create(&wo->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -960,7 +963,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot) 0, "Blank", "Add a new view layer with all collections disabled"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -997,7 +1000,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) { + if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) { return OPERATOR_CANCELLED; } @@ -1041,7 +1044,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op)) BKE_view_layer_verify_aov(engine, scene, view_layer); } RE_engine_free(engine); - engine = NULL; + engine = nullptr; } if (scene->nodetree) { @@ -1080,7 +1083,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - if (view_layer->active_aov == NULL) { + if (view_layer->active_aov == nullptr) { return OPERATOR_FINISHED; } @@ -1093,7 +1096,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) BKE_view_layer_verify_aov(engine, scene, view_layer); } RE_engine_free(engine); - engine = NULL; + engine = nullptr; } if (scene->nodetree) { @@ -1135,7 +1138,7 @@ enum { static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) { - if (scene->eevee.light_cache_data != NULL) { + if (scene->eevee.light_cache_data != nullptr) { int subset = RNA_enum_get(op->ptr, "subset"); switch (subset) { case LIGHTCACHE_SUBSET_ALL: @@ -1261,7 +1264,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot) 0, "Cubemaps Only", "Try to only bake reflection cubemaps if irradiance grids are up to date"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1317,7 +1320,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) } EEVEE_lightcache_free(scene->eevee.light_cache_data); - scene->eevee.light_cache_data = NULL; + scene->eevee.light_cache_data = nullptr; EEVEE_lightcache_info_update(&scene->eevee); @@ -1358,7 +1361,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - BKE_scene_add_render_view(scene, NULL); + BKE_scene_add_render_view(scene, nullptr); scene->r.actview = BLI_listbase_count(&scene->r.views) - 1; WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -1389,7 +1392,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot) static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview); + SceneRenderView *rv = static_cast<SceneRenderView *>( + BLI_findlink(&scene->r.views, scene->r.actview)); if (!BKE_scene_remove_render_view(scene, rv)) { return OPERATOR_CANCELLED; @@ -1444,9 +1448,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi static bool freestyle_active_module_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); - return module != NULL; + return module != nullptr; } static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1486,7 +1490,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); BKE_freestyle_module_delete(&view_layer->freestyle_config, module); @@ -1516,7 +1520,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); int dir = RNA_enum_get(op->ptr, "direction"); if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) { @@ -1538,7 +1542,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1574,7 +1578,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL); + BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr); DEG_id_tag_update(&scene->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -1610,7 +1614,7 @@ static bool freestyle_active_lineset_poll(bContext *C) return false; } - return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL; + return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr; } static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1730,7 +1734,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1814,7 +1818,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type"); return OPERATOR_CANCELLED; } @@ -1861,7 +1865,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type"); return OPERATOR_CANCELLED; } @@ -1908,7 +1912,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type"); return OPERATOR_CANCELLED; } @@ -1955,7 +1959,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type"); return OPERATOR_CANCELLED; } @@ -2014,7 +2018,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; @@ -2070,7 +2074,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; @@ -2126,7 +2130,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); int dir = RNA_enum_get(op->ptr, "direction"); bool changed = false; @@ -2166,7 +2170,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -2252,9 +2256,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op) mtex_ar[act] = mtex_ar[act - 1]; mtex_ar[act - 1] = mtexswap; - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false); set_active_mtex(id, act - 1); } @@ -2265,9 +2272,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op) mtex_ar[act] = mtex_ar[act + 1]; mtex_ar[act + 1] = mtexswap; - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false); set_active_mtex(id, act + 1); } @@ -2285,7 +2295,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot) static const EnumPropertyItem slot_move[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -2311,9 +2321,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot) /* material copy/paste */ static int copy_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } @@ -2345,9 +2356,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot) static int paste_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } @@ -2382,14 +2394,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot) static short mtexcopied = 0; /* must be reset on file load */ static MTex mtexcopybuf; -void ED_render_clear_mtex_copybuf(void) +void ED_render_clear_mtex_copybuf() { /* use for file reload */ mtexcopied = 0; } static void copy_mtex_copybuf(ID *id) { - MTex **mtex = NULL; + MTex **mtex = nullptr; switch (GS(id->name)) { case ID_PA: @@ -2413,9 +2425,9 @@ static void copy_mtex_copybuf(ID *id) static void paste_mtex_copybuf(ID *id) { - MTex **mtex = NULL; + MTex **mtex = nullptr; - if (mtexcopied == 0 || mtexcopybuf.tex == NULL) { + if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) { return; } @@ -2432,8 +2444,8 @@ static void paste_mtex_copybuf(ID *id) } if (mtex) { - if (*mtex == NULL) { - *mtex = MEM_mallocN(sizeof(MTex), "mtex copy"); + if (*mtex == nullptr) { + *mtex = MEM_new<MTex>("mtex copy"); } else if ((*mtex)->tex) { id_us_min(&(*mtex)->tex->id); @@ -2455,7 +2467,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op)) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - if (id == NULL) { + if (id == nullptr) { /* copying empty slot */ ED_render_clear_mtex_copybuf(); return OPERATOR_CANCELLED; @@ -2470,7 +2482,7 @@ static bool copy_mtex_poll(bContext *C) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - return (id != NULL); + return (id != nullptr); } void TEXTURE_OT_slot_copy(wmOperatorType *ot) @@ -2499,14 +2511,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op)) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - if (id == NULL) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; - Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data; - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; - ParticleSystem *psys = - CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data; - FreestyleLineStyle *linestyle = - CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data; + if (id == nullptr) { + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); + Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data); + World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data); + ParticleSystem *psys = static_cast<ParticleSystem *>( + CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data); + FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>( + CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data); if (ma) { id = &ma->id; @@ -2524,14 +2537,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op)) id = &linestyle->id; } - if (id == NULL) { + if (id == nullptr) { return OPERATOR_CANCELLED; } } paste_mtex_copybuf(id); - WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL); + WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc index e975eab4736..b2958efde9b 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.cc @@ -20,8 +20,8 @@ * \ingroup edrend */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "DNA_cachefile_types.h" #include "DNA_light_types.h" @@ -62,7 +62,7 @@ #include "WM_api.h" -#include <stdio.h> +#include <cstdio> /* -------------------------------------------------------------------- */ /** \name Render Engines @@ -82,8 +82,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph, continue; } - View3D *v3d = area->spacedata.first; - RegionView3D *rv3d = region->regiondata; + View3D *v3d = static_cast<View3D *>(area->spacedata.first); + RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); RenderEngine *engine = rv3d->render_engine; /* call update if the scene changed, or if the render engine @@ -94,7 +94,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph, bContext *C = CTX_create(); CTX_data_main_set(C, bmain); CTX_data_scene_set(C, scene); - CTX_wm_manager_set(C, bmain->wm.first); + CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first)); CTX_wm_window_set(C, window); CTX_wm_screen_set(C, WM_window_get_active_screen(window)); CTX_wm_area_set(C, area); @@ -111,15 +111,15 @@ void ED_render_view3d_update(Depsgraph *depsgraph, else { RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); if (updated) { - DRW_notify_view_update((&(DRWUpdateContext){ - .bmain = bmain, - .depsgraph = depsgraph, - .scene = scene, - .view_layer = view_layer, - .region = region, - .v3d = v3d, - .engine_type = engine_type, - })); + DRWUpdateContext drw_context = {nullptr}; + drw_context.bmain = bmain; + drw_context.depsgraph = depsgraph; + drw_context.scene = scene; + drw_context.view_layer = view_layer; + drw_context.region = region; + drw_context.v3d = v3d; + drw_context.engine_type = engine_type; + DRW_notify_view_update(&drw_context); } } } @@ -148,7 +148,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool recursive_check = true; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { bScreen *screen = WM_window_get_active_screen(window); @@ -166,13 +166,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area) { /* clear all render engines in this area */ ARegion *region; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); if (area->spacetype != SPACE_VIEW3D) { return; } - for (region = area->regionbase.first; region; region = region->next) { + for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) { if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) { continue; } @@ -183,16 +183,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area) void ED_render_engine_changed(Main *bmain, const bool update_scene_data) { /* on changing the render engine type, clear all running render engines */ - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen; + screen = static_cast<bScreen *>(screen->id.next)) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ED_render_engine_area_exit(bmain, area); } } - RE_FreePersistentData(NULL); + RE_FreePersistentData(nullptr); /* Inform all render engines and draw managers. */ - DEGEditorUpdateContext update_ctx = {NULL}; + DEGEditorUpdateContext update_ctx = {nullptr}; update_ctx.bmain = bmain; - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene; + scene = static_cast<Scene *>(scene->id.next)) { update_ctx.scene = scene; LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { /* TDODO(sergey): Iterate over depsgraphs instead? */ @@ -258,14 +260,16 @@ static void texture_changed(Main *bmain, Tex *tex) /* icons */ BKE_icon_changed(BKE_icon_id_ensure(&tex->id)); - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (scene = static_cast<Scene *>(bmain->scenes.first); scene; + scene = static_cast<Scene *>(scene->id.next)) { /* paint overlays */ - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer; + view_layer = view_layer->next) { BKE_paint_invalidate_overlay_tex(scene, view_layer, tex); } /* find compositing nodes */ if (scene->use_nodes && scene->nodetree) { - for (node = scene->nodetree->nodes.first; node; node = node->next) { + for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) { if (node->id == &tex->id) { ED_node_tag_update_id(&scene->id); } @@ -288,7 +292,8 @@ static void image_changed(Main *bmain, Image *ima) BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); /* textures */ - for (tex = bmain->textures.first; tex; tex = tex->id.next) { + for (tex = static_cast<Tex *>(bmain->textures.first); tex; + tex = static_cast<Tex *>(tex->id.next)) { if (tex->type == TEX_IMAGE && tex->ima == ima) { texture_changed(bmain, tex); } @@ -300,10 +305,11 @@ static void scene_changed(Main *bmain, Scene *scene) Object *ob; /* glsl */ - for (ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ob = static_cast<Object *>(bmain->objects.first); ob; + ob = static_cast<Object *>(ob->id.next)) { if (ob->mode & OB_MODE_TEXTURE_PAINT) { BKE_texpaint_slots_refresh_object(scene, ob); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); } } } diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc index 9163718ffad..980cd899120 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.cc @@ -21,8 +21,8 @@ * \ingroup edrend */ -#include <stddef.h> -#include <string.h> +#include <cstddef> +#include <cstring> #include "BLI_listbase.h" #include "BLI_utildefines.h" @@ -47,7 +47,7 @@ #include "wm_window.h" -#include "render_intern.h" +#include "render_intern.hh" /*********************** utilities for finding areas *************************/ @@ -59,11 +59,11 @@ static ScrArea *biggest_non_image_area(bContext *C) { bScreen *screen = CTX_wm_screen(C); - ScrArea *area, *big = NULL; + ScrArea *area, *big = nullptr; int size, maxsize = 0, bwmaxsize = 0; short foundwin = 0; - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->winx > 30 && area->winy > 30) { size = area->winx * area->winy; if (!area->full && area->spacetype == SPACE_PROPERTIES) { @@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C) static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win) { wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *area = NULL; + ScrArea *area = nullptr; SpaceImage *sima; /* find an imagewindow showing render result */ - for (*win = wm->windows.first; *win; *win = (*win)->next) { + for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) { if (WM_window_get_active_scene(*win) == scene) { const bScreen *screen = WM_window_get_active_screen(*win); - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->spacetype == SPACE_IMAGE) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { break; } @@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C) SpaceImage *sima; /* find an imagewindow showing render result */ - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->spacetype == SPACE_IMAGE) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); if ((sima->mode == SI_MODE_VIEW) && !sima->image) { break; } @@ -136,13 +136,13 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - wmWindow *win = NULL; - ScrArea *area = NULL; + wmWindow *win = nullptr; + ScrArea *area = nullptr; SpaceImage *sima; bool area_was_image = false; if (U.render_display_type == USER_RENDER_DISPLAY_NONE) { - return NULL; + return nullptr; } if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) { @@ -168,14 +168,14 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) true, false, true, - WIN_ALIGN_LOCATION_CENTER) == NULL) { + WIN_ALIGN_LOCATION_CENTER) == nullptr) { BKE_report(reports, RPT_ERROR, "Failed to open window!"); - return NULL; + return nullptr; } area = CTX_wm_area(C); if (BLI_listbase_is_single(&area->spacedata) == false) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); sima->flag |= SI_PREVSPACE; } } @@ -185,7 +185,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) /* If the active screen is already in full-screen mode, skip this and * unset the area, so that the full-screen area is just changed later. */ if (area && area->full) { - area = NULL; + area = nullptr; } else { if (area && area->spacetype == SPACE_IMAGE) { @@ -199,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) if (!area) { area = find_area_showing_r_result(C, scene, &win); - if (area == NULL) { + if (area == nullptr) { area = find_area_image_empty(C); } @@ -208,12 +208,12 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) wm_window_raise(win); } - if (area == NULL) { + if (area == nullptr) { /* find largest open non-image area */ area = biggest_non_image_area(C); if (area) { ED_area_newspace(C, area, SPACE_IMAGE, true); - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); /* Makes "Escape" go back to previous space. */ sima->flag |= SI_PREVSPACE; @@ -228,7 +228,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0); if (area->spacetype != SPACE_IMAGE) { // XXX newspace(area, SPACE_IMAGE); - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); /* Makes "Escape" go back to previous space. */ sima->flag |= SI_PREVSPACE; @@ -236,7 +236,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } } } - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; /* get the correct image, and scale it */ @@ -272,7 +272,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op)) { wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); /* ensure image editor full-screen and area full-screen states are in sync */ if ((sima->flag & SI_FULLWINDOW) && !area->full) { @@ -333,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow); /* is there another window on current scene showing result? */ - for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) { + for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); if ((WM_window_is_temp_screen(win) && @@ -348,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e if (area) { /* but don't close it when rendering */ if (G.is_rendering == false) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); if (sima->flag & SI_PREVSPACE) { sima->flag &= ~SI_PREVSPACE; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 5dc6fe88663..95711fe20fa 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1667,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event) { rcti rect = region->winrct; rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y; - return BLI_rcti_isect_pt(&rect, event->xy[0], event->xy[1]); + return BLI_rcti_isect_pt_v(&rect, event->xy); } /** diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 304205d0cc4..04df90bf912 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -501,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat Object *obact = view_layer->basact ? view_layer->basact->object : NULL; Object *obpose = BKE_object_pose_armature_get(obact); - bPoseChannel *pchan = BKE_pose_channel_active(obpose); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose); if (pchan) { CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan); return CTX_RESULT_OK; diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index d017345b523..b9c92c1664d 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1128,8 +1128,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) { /* What area are we now in? */ - ScrArea *area = BKE_screen_find_area_xy( - screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); if (area == sad->sa1) { /* Same area, so possible split. */ @@ -1173,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* gesture is large enough? */ if (is_gesture) { /* second area, for join when (sa1 != sa2) */ - sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); /* apply sends event */ actionzone_apply(C, op, sad->az->type); actionzone_exit(op); @@ -1241,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C, int borderwidth = (4 * UI_DPI_FAC); ScrArea *sa1, *sa2; if (screen_geom_edge_is_horizontal(actedge)) { - sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth); - sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth); + sa1 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth}); + sa2 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth}); } else { - sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]); - sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]); + sa1 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]}); + sa2 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]}); } bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2))); if (!isGlobal) { @@ -1334,8 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: /* second area, for join */ - sad->sa2 = BKE_screen_find_area_xy( - CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy); break; case LEFTMOUSE: /* release LMB */ if (event->val == KM_RELEASE) { @@ -2508,8 +2510,7 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_area_tag_redraw(sd->sarea); } /* area context not set */ - sd->sarea = BKE_screen_find_area_xy( - CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy); if (sd->sarea) { ScrArea *area = sd->sarea; @@ -3517,7 +3518,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: { - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); jd->dir = area_getorientation(jd->sa1, jd->sa2); if (area == jd->sa1) { diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index b26291c4d1b..4bc9f1e2565 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -166,8 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (use_crop) { area = CTX_wm_area(C); bScreen *screen = CTX_wm_screen(C); - ScrArea *area_test = BKE_screen_find_area_xy( - screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); if (area_test != NULL) { area = area_test; } diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b826ff8701d..517125f016e 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -59,6 +59,7 @@ set(SRC sculpt.c sculpt_automasking.c sculpt_boundary.c + sculpt_brushes.c sculpt_cloth.c sculpt_detail.c sculpt_dyntopo.c @@ -71,6 +72,7 @@ set(SRC sculpt_mask_expand.c sculpt_mask_init.c sculpt_multiplane_scrape.c + sculpt_ops.c sculpt_paint_color.c sculpt_pose.c sculpt_smooth.c diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 7df5848e068..8a5d75d5f77 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -6623,7 +6623,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) } } - ntreeUpdateTree(CTX_data_main(C), ntree); + ED_node_tree_propagate_change(C, bmain, ntree); /* In case we added more than one node, position them too. */ nodePositionPropagate(out_node); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 90887b9fc39..09013ea00f4 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -25,6 +25,8 @@ #include "BKE_paint.h" +#include "BLI_compiler_compat.h" +#include "BLI_math.h" #include "BLI_rect.h" #include "DNA_scene_types.h" @@ -404,8 +406,61 @@ bool facemask_paint_poll(struct bContext *C); /** * Uses symm to selectively flip any axis of a coordinate. */ -void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm); -void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm); + +BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm) +{ + if (symm & PAINT_SYMM_X) { + out[0] = -in[0]; + } + else { + out[0] = in[0]; + } + if (symm & PAINT_SYMM_Y) { + out[1] = -in[1]; + } + else { + out[1] = in[1]; + } + if (symm & PAINT_SYMM_Z) { + out[2] = -in[2]; + } + else { + out[2] = in[2]; + } +} + +BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm) +{ + float axis[3], angle; + + quat_to_axis_angle(axis, &angle, in); + normalize_v3(axis); + + if (symm & PAINT_SYMM_X) { + axis[0] *= -1.0f; + angle *= -1.0f; + } + if (symm & PAINT_SYMM_Y) { + axis[1] *= -1.0f; + angle *= -1.0f; + } + if (symm & PAINT_SYMM_Z) { + axis[2] *= -1.0f; + angle *= -1.0f; + } + + axis_angle_normalized_to_quat(out, axis, angle); +} + +BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm) +{ + flip_v3_v3(v, v, symm); +} + +BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm) +{ + flip_qt_qt(quat, quat, symm); +} /* stroke operator */ typedef enum BrushStrokeMode { diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 541893f7957..95a0aba1ffb 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -397,51 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index) return ima; } -void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm) -{ - if (symm & PAINT_SYMM_X) { - out[0] = -in[0]; - } - else { - out[0] = in[0]; - } - if (symm & PAINT_SYMM_Y) { - out[1] = -in[1]; - } - else { - out[1] = in[1]; - } - if (symm & PAINT_SYMM_Z) { - out[2] = -in[2]; - } - else { - out[2] = in[2]; - } -} - -void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm) -{ - float axis[3], angle; - - quat_to_axis_angle(axis, &angle, in); - normalize_v3(axis); - - if (symm & PAINT_SYMM_X) { - axis[0] *= -1.0f; - angle *= -1.0f; - } - if (symm & PAINT_SYMM_Y) { - axis[1] *= -1.0f; - angle *= -1.0f; - } - if (symm & PAINT_SYMM_Z) { - axis[2] *= -1.0f; - angle *= -1.0f; - } - - axis_angle_normalized_to_quat(out, axis, angle); -} - void paint_sample_color( bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette) { diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b764d0e1b5b..fd550790f2e 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1329,103 +1329,6 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3 } } -static void sculpt_rake_rotate(const SculptSession *ss, - const float sculpt_co[3], - const float v_co[3], - float factor, - float r_delta[3]) -{ - float vec_rot[3]; - -#if 0 - /* lerp */ - sub_v3_v3v3(vec_rot, v_co, sculpt_co); - mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot); - add_v3_v3(vec_rot, sculpt_co); - sub_v3_v3v3(r_delta, vec_rot, v_co); - mul_v3_fl(r_delta, factor); -#else - /* slerp */ - float q_interp[4]; - sub_v3_v3v3(vec_rot, v_co, sculpt_co); - - copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry); - pow_qt_fl_normalized(q_interp, factor); - mul_qt_v3(q_interp, vec_rot); - - add_v3_v3(vec_rot, sculpt_co); - sub_v3_v3v3(r_delta, vec_rot, v_co); -#endif -} - -/** - * Align the grab delta to the brush normal. - * - * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`. - */ -static void sculpt_project_v3_normal_align(SculptSession *ss, - const float normal_weight, - float grab_delta[3]) -{ - /* Signed to support grabbing in (to make a hole) as well as out. */ - const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta); - - /* This scale effectively projects the offset so dragging follows the cursor, - * as the normal points towards the view, the scale increases. */ - float len_view_scale; - { - float view_aligned_normal[3]; - project_plane_v3_v3v3( - view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal); - len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm)); - len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f; - } - - mul_v3_fl(grab_delta, 1.0f - normal_weight); - madd_v3_v3fl( - grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name SculptProjectVector - * - * Fast-path for #project_plane_v3_v3v3 - * \{ */ - -typedef struct SculptProjectVector { - float plane[3]; - float len_sq; - float len_sq_inv_neg; - bool is_valid; - -} SculptProjectVector; - -/** - * \param plane: Direction, can be any length. - */ -static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3]) -{ - copy_v3_v3(spvc->plane, plane); - spvc->len_sq = len_squared_v3(spvc->plane); - spvc->is_valid = (spvc->len_sq > FLT_EPSILON); - spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f; -} - -/** - * Calculate the projection. - */ -static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3]) -{ -#if 0 - project_plane_v3_v3v3(r_vec, vec, spvc->plane); -#else - /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */ - madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg); -#endif -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1835,15 +1738,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, /* ===== Sculpting ===== */ -static void flip_v3(float v[3], const ePaintSymmetryFlags symm) -{ - flip_v3_v3(v, v, symm); -} - -static void flip_qt(float quat[4], const ePaintSymmetryFlags symm) -{ - flip_qt_qt(quat, quat, symm); -} static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle) { @@ -1913,9 +1807,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * (optionally using original coordinates). * * Functions are: - * - #calc_area_center - * - #calc_area_normal - * - #calc_area_normal_and_center + * - #SCULPT_calc_area_center + * - #SCULPT_calc_area_normal + * - #SCULPT_calc_area_normal_and_center * * \note These are all _very_ similar, when changing one, check others. * \{ */ @@ -2137,7 +2031,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use add_v2_v2_int(join->count_co, anctd->count_co); } -static void calc_area_center( +void SCULPT_calc_area_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); @@ -2238,7 +2132,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush, * This calculates flatten center and area normal together, * amortizing the memory bandwidth and loop overhead to calculate both at the same time. */ -static void calc_area_normal_and_center( +void SCULPT_calc_area_normal_and_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); @@ -2633,9 +2527,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]) continue; } - if (ss->cache && (ss->cache->flag & (CLIP_X << i)) && - (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) { - co[i] = 0.0f; + bool do_clip = false; + float co_clip[3]; + if (ss->cache && (ss->cache->flag & (CLIP_X << i))) { + /* Take possible mirror object into account. */ + mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co); + + if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) { + co_clip[i] = 0.0f; + float imtx[4][4]; + invert_m4_m4(imtx, ss->cache->clip_mirror_mtx); + mul_m4_v3(imtx, co_clip); + do_clip = true; + } + } + + if (do_clip) { + co[i] = co_clip[i]; } else { co[i] = val[i]; @@ -2856,10 +2764,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Sculpt Topology Rake (Shared Utility) - * \{ */ - typedef struct { SculptSession *ss; const float *ray_start; @@ -2885,1295 +2789,6 @@ typedef struct { bool original; } SculptFindNearestToRayData; -static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - Sculpt *sd = data->sd; - const Brush *brush = data->brush; - - float direction[3]; - copy_v3_v3(direction, ss->cache->grab_delta_symmetry); - - float tmp[3]; - mul_v3_v3fl( - tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction)); - sub_v3_v3(direction, tmp); - normalize_v3(direction); - - /* Cancel if there's no grab data. */ - if (is_zero_v3(direction)) { - return; - } - - const float bstrength = clamp_f(data->strength, 0.0f, 1.0f); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = - bstrength * - SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * - ss->cache->pressure; - - float avg[3], val[3]; - - SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert); - - sub_v3_v3v3(val, avg, vd.co); - - madd_v3_v3v3fl(val, vd.co, val, fade); - - SCULPT_clip(sd, ss, vd.co, val); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void bmesh_topology_rake( - Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - const float strength = clamp_f(bstrength, 0.0f, 1.0f); - - /* Interactions increase both strength and quality. */ - const int iterations = 3; - - int iteration; - const int count = iterations * strength + 1; - const float factor = iterations * strength / count; - - for (iteration = 0; iteration <= count; iteration++) { - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .strength = factor, - }; - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - - BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Mask Brush - * \{ */ - -static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); - - if (bstrength > 0.0f) { - (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); - } - else { - (*vd.mask) += fade * bstrength * (*vd.mask); - } - *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - BKE_pbvh_vertex_iter_end; - } -} - -static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); -} - -static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - switch ((BrushMaskTool)brush->mask_tool) { - case BRUSH_MASK_DRAW: - do_mask_brush_draw(sd, ob, nodes, totnode); - break; - case BRUSH_MASK_SMOOTH: - SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true); - break; - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Multires Displacement Eraser Brush - * \{ */ - -static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); - - float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - float limit_co[3]; - float disp[3]; - SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); - sub_v3_v3v3(disp, limit_co, vd.co); - mul_v3_v3fl(proxy[vd.i], disp, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Multires Displacement Smear Brush - * \{ */ - -static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - float current_disp[3]; - float current_disp_norm[3]; - float interp_limit_surface_disp[3]; - - copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); - - switch (brush->smear_deform_type) { - case BRUSH_SMEAR_DEFORM_DRAG: - sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); - break; - case BRUSH_SMEAR_DEFORM_PINCH: - sub_v3_v3v3(current_disp, ss->cache->location, vd.co); - break; - case BRUSH_SMEAR_DEFORM_EXPAND: - sub_v3_v3v3(current_disp, vd.co, ss->cache->location); - break; - } - - normalize_v3_v3(current_disp_norm, current_disp); - mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); - - float weights_accum = 1.0f; - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { - float vertex_disp[3]; - float vertex_disp_norm[3]; - float neighbor_limit_co[3]; - SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); - sub_v3_v3v3(vertex_disp, - ss->cache->limit_surface_co[ni.index], - ss->cache->limit_surface_co[vd.index]); - const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; - normalize_v3_v3(vertex_disp_norm, vertex_disp); - - if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) { - continue; - } - - const float disp_interp = clamp_f( - -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); - madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); - weights_accum += disp_interp; - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); - - float new_co[3]; - add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); - interp_v3_v3v3(vd.co, vd.co, new_co, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_smear_store_prev_disp_task_cb_ex( - void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - sub_v3_v3v3(ss->cache->prev_displacement[vd.index], - SCULPT_vertex_co_get(ss, vd.index), - ss->cache->limit_surface_co[vd.index]); - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - SculptSession *ss = ob->sculpt; - - BKE_curvemapping_init(brush->curve); - - const int totvert = SCULPT_vertex_count_get(ss); - if (!ss->cache->prev_displacement) { - ss->cache->prev_displacement = MEM_malloc_arrayN( - totvert, sizeof(float[3]), "prev displacement"); - ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); - for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); - sub_v3_v3v3(ss->cache->prev_displacement[i], - SCULPT_vertex_co_get(ss, i), - ss->cache->limit_surface_co[i]); - } - } - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range( - 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); - BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Draw Brush - * \{ */ - -static void do_draw_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *offset = data->offset; - - PBVHVertexIter vd; - float(*proxy)[3]; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], offset, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - const float bstrength = ss->cache->bstrength; - - /* Offset with as much as possible factored in already. */ - float effective_normal[3]; - SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); - mul_v3_v3fl(offset, effective_normal, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise - * initialize before threads so they can do curve mapping. */ - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .offset = offset, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); -} - -static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *offset = data->offset; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], offset, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - const float bstrength = ss->cache->bstrength; - - /* Offset with as much as possible factored in already. */ - float effective_normal[3]; - SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); - mul_v3_v3fl(offset, effective_normal, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise - * initialize before threads so they can do curve mapping. */ - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .offset = offset, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Topology Brush - * \{ */ - -static void do_topology_slide_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float current_disp[3]; - float current_disp_norm[3]; - float final_disp[3] = {0.0f, 0.0f, 0.0f}; - - switch (brush->slide_deform_type) { - case BRUSH_SLIDE_DEFORM_DRAG: - sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); - break; - case BRUSH_SLIDE_DEFORM_PINCH: - sub_v3_v3v3(current_disp, ss->cache->location, vd.co); - break; - case BRUSH_SLIDE_DEFORM_EXPAND: - sub_v3_v3v3(current_disp, vd.co, ss->cache->location); - break; - } - - normalize_v3_v3(current_disp_norm, current_disp); - mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { - float vertex_disp[3]; - float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); - normalize_v3_v3(vertex_disp_norm, vertex_disp); - if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { - madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - mul_v3_v3fl(proxy[vd.i], final_disp, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -void SCULPT_relax_vertex(SculptSession *ss, - PBVHVertexIter *vd, - float factor, - bool filter_boundary_face_sets, - float *r_final_pos) -{ - float smooth_pos[3]; - float final_disp[3]; - float boundary_normal[3]; - int avg_count = 0; - int neighbor_count = 0; - zero_v3(smooth_pos); - zero_v3(boundary_normal); - const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { - neighbor_count++; - if (!filter_boundary_face_sets || - (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { - - /* When the vertex to relax is boundary, use only connected boundary vertices for the average - * position. */ - if (is_boundary) { - if (!SCULPT_vertex_is_boundary(ss, ni.index)) { - continue; - } - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); - avg_count++; - - /* Calculate a normal for the constraint plane using the edges of the boundary. */ - float to_neighbor[3]; - sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); - normalize_v3(to_neighbor); - add_v3_v3(boundary_normal, to_neighbor); - } - else { - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); - avg_count++; - } - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - /* Don't modify corner vertices. */ - if (neighbor_count <= 2) { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - if (avg_count > 0) { - mul_v3_fl(smooth_pos, 1.0f / avg_count); - } - else { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - float plane[4]; - float smooth_closest_plane[3]; - float vno[3]; - - if (is_boundary && avg_count == 2) { - normalize_v3_v3(vno, boundary_normal); - } - else { - SCULPT_vertex_normal_get(ss, vd->index, vno); - } - - if (is_zero_v3(vno)) { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - plane_from_point_normal_v3(plane, vd->co, vno); - closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos); - sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co); - - mul_v3_fl(final_disp, factor); - add_v3_v3v3(r_final_pos, vd->co, final_disp); -} - -static void do_topology_relax_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - BKE_curvemapping_init(brush->curve); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - if (ss->cache->alt_smooth) { - SCULPT_boundary_info_ensure(ob); - for (int i = 0; i < 4; i++) { - BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); - } - } - else { - BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); - } -} - -static void calc_sculpt_plane( - Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) && - (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) || - !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { - switch (brush->sculpt_plane) { - case SCULPT_DISP_DIR_VIEW: - copy_v3_v3(r_area_no, ss->cache->true_view_normal); - break; - - case SCULPT_DISP_DIR_X: - ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f); - break; - - case SCULPT_DISP_DIR_Y: - ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f); - break; - - case SCULPT_DISP_DIR_Z: - ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f); - break; - - case SCULPT_DISP_DIR_AREA: - calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); - normalize_v3(r_area_no); - } - break; - - default: - break; - } - - /* For flatten center. */ - /* Flatten center has not been calculated yet if we are not using the area normal. */ - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { - calc_area_center(sd, ob, nodes, totnode, r_area_co); - } - - /* For area normal. */ - if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && - (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - copy_v3_v3(r_area_no, ss->cache->sculpt_normal); - } - else { - copy_v3_v3(ss->cache->sculpt_normal, r_area_no); - } - - /* For flatten center. */ - if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && - (brush->flag & BRUSH_ORIGINAL_PLANE)) { - copy_v3_v3(r_area_co, ss->cache->last_center); - } - else { - copy_v3_v3(ss->cache->last_center, r_area_co); - } - } - else { - /* For area normal. */ - copy_v3_v3(r_area_no, ss->cache->sculpt_normal); - - /* For flatten center. */ - copy_v3_v3(r_area_co, ss->cache->last_center); - - /* For area normal. */ - flip_v3(r_area_no, ss->cache->mirror_symmetry_pass); - - /* For flatten center. */ - flip_v3(r_area_co, ss->cache->mirror_symmetry_pass); - - /* For area normal. */ - mul_m4_v3(ss->cache->symm_rot_mat, r_area_no); - - /* For flatten center. */ - mul_m4_v3(ss->cache->symm_rot_mat, r_area_co); - - /* Shift the plane for the current tile. */ - add_v3_v3(r_area_co, ss->cache->plane_offset); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Crease & Blob Brush - * \{ */ - -/** - * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' - */ -static void do_crease_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - SculptProjectVector *spvc = data->spvc; - const float flippedbstrength = data->flippedbstrength; - const float *offset = data->offset; - - PBVHVertexIter vd; - float(*proxy)[3]; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float val1[3]; - float val2[3]; - - /* First we pinch. */ - sub_v3_v3v3(val1, test.location, vd.co); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(val1, val1, ss->cache->view_normal); - } - - mul_v3_fl(val1, fade * flippedbstrength); - - sculpt_project_v3(spvc, val1, val1); - - /* Then we draw. */ - mul_v3_v3fl(val2, offset, fade); - - add_v3_v3v3(proxy[vd.i], val1, val2); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - const Scene *scene = ss->cache->vc->scene; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - float bstrength = ss->cache->bstrength; - float flippedbstrength, crease_correction; - float brush_alpha; - - SculptProjectVector spvc; - - /* Offset with as much as possible factored in already. */ - mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* We divide out the squared alpha and multiply by the squared crease - * to give us the pinch strength. */ - crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor; - brush_alpha = BKE_brush_alpha_get(scene, brush); - if (brush_alpha > 0.0f) { - crease_correction /= brush_alpha * brush_alpha; - } - - /* We always want crease to pinch or blob to relax even when draw is negative. */ - flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength : - crease_correction * bstrength; - - if (brush->sculpt_tool == SCULPT_TOOL_BLOB) { - flippedbstrength *= -1.0f; - } - - /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single - * point. Without this we get a 'flat' surface surrounding the pinch. */ - sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .spvc = &spvc, - .offset = offset, - .flippedbstrength = flippedbstrength, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); -} - -static void do_pinch_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*stroke_xz)[3] = data->stroke_xz; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - float x_object_space[3]; - float z_object_space[3]; - copy_v3_v3(x_object_space, stroke_xz[0]); - copy_v3_v3(z_object_space, stroke_xz[1]); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float disp_center[3]; - float x_disp[3]; - float z_disp[3]; - /* Calculate displacement from the vertex to the brush center. */ - sub_v3_v3v3(disp_center, test.location, vd.co); - - /* Project the displacement into the X vector (aligned to the stroke). */ - mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space)); - - /* Project the displacement into the Z vector (aligned to the surface normal). */ - mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space)); - - /* Add the two projected vectors to calculate the final displacement. - * The Y component is removed. */ - add_v3_v3v3(disp_center, x_disp, z_disp); - - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal); - } - mul_v3_v3fl(proxy[vd.i], disp_center, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - float area_no[3]; - float area_co[3]; - - float mat[4][4]; - calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); - - /* delay the first daub because grab delta is not setup */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - /* Initialize `mat`. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], ss->cache->location); - mat[3][3] = 1.0f; - normalize_m4(mat); - - float stroke_xz[2][3]; - normalize_v3_v3(stroke_xz[0], mat[0]); - normalize_v3_v3(stroke_xz[1], mat[2]); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .stroke_xz = stroke_xz, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); -} - -static void do_grab_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *grab_delta = data->grab_delta; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - if (grab_silhouette) { - float silhouette_test_dir[3]; - normalize_v3_v3(silhouette_test_dir, grab_delta); - if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) { - mul_v3_fl(silhouette_test_dir, -1.0f); - } - float vno[3]; - normal_short_to_float_v3(vno, orig_data.no); - fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f); - } - - mul_v3_v3fl(proxy[vd.i], grab_delta, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); -} - -static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *grab_delta = data->grab_delta; - const float *location = ss->cache->location; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - float dir; - if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) { - dir = 1.0f; - } - else { - dir = -1.0f; - } - - if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) { - int symm = ss->cache->mirror_symmetry_pass; - if (ELEM(symm, 1, 2, 4, 7)) { - dir = -dir; - } - } - - KelvinletParams params; - float force = len_v3(grab_delta) * dir * bstrength; - BKE_kelvinlet_init_params( - ¶ms, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - float final_disp[3]; - switch (brush->elastic_deform_type) { - case BRUSH_ELASTIC_DEFORM_GRAB: - BKE_kelvinlet_grab(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { - BKE_kelvinlet_grab_biscale(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - } - case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { - BKE_kelvinlet_grab_triscale(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - } - case BRUSH_ELASTIC_DEFORM_SCALE: - BKE_kelvinlet_scale( - final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); - break; - case BRUSH_ELASTIC_DEFORM_TWIST: - BKE_kelvinlet_twist( - final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); - break; - } - - if (vd.mask) { - mul_v3_fl(final_disp, 1.0f - *vd.mask); - } - - mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); - - copy_v3_v3(proxy[vd.i], final_disp); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); -} - ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]) { ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT; @@ -4257,7 +2872,7 @@ void SCULPT_calc_brush_plane( break; case SCULPT_DISP_DIR_AREA: - calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); + SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); normalize_v3(r_area_no); @@ -4271,7 +2886,7 @@ void SCULPT_calc_brush_plane( /* For flatten center. */ /* Flatten center has not been calculated yet if we are not using the area normal. */ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { - calc_area_center(sd, ob, nodes, totnode, r_area_co); + SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co); } /* For area normal. */ @@ -4316,564 +2931,12 @@ void SCULPT_calc_brush_plane( } } -static void do_nudge_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *cono = data->cono; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], cono, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - float tmp[3], cono[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); - cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .cono = cono, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); -} - -static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - SculptProjectVector *spvc = data->spvc; - const float *grab_delta = data->grab_delta; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - const bool do_rake_rotation = ss->cache->is_rake_rotation_valid; - const bool do_pinch = (brush->crease_pinch_factor != 0.5f); - const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) * - (len_v3(grab_delta) / ss->cache->radius)) : - 0.0f; - - const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - KelvinletParams params; - BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float fade; - if (do_elastic) { - fade = 1.0f; - } - else { - fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - } - - mul_v3_v3fl(proxy[vd.i], grab_delta, fade); - - /* Negative pinch will inflate, helps maintain volume. */ - if (do_pinch) { - float delta_pinch_init[3], delta_pinch[3]; - - sub_v3_v3v3(delta_pinch, vd.co, test.location); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal); - } - - /* Important to calculate based on the grabbed location - * (intentionally ignore fade here). */ - add_v3_v3(delta_pinch, grab_delta); - - sculpt_project_v3(spvc, delta_pinch, delta_pinch); - - copy_v3_v3(delta_pinch_init, delta_pinch); - - float pinch_fade = pinch * fade; - /* When reducing, scale reduction back by how close to the center we are, - * so we don't pinch into nothingness. */ - if (pinch > 0.0f) { - /* Square to have even less impact for close vertices. */ - pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius)); - } - mul_v3_fl(delta_pinch, 1.0f + pinch_fade); - sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch); - add_v3_v3(proxy[vd.i], delta_pinch); - } - - if (do_rake_rotation) { - float delta_rotate[3]; - sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate); - add_v3_v3(proxy[vd.i], delta_rotate); - } - - if (do_elastic) { - float disp[3]; - BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); - mul_v3_fl(disp, bstrength * 20.0f); - if (vd.mask) { - mul_v3_fl(disp, 1.0f - *vd.mask); - } - mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); - copy_v3_v3(proxy[vd.i], disp); - } - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - const float bstrength = ss->cache->bstrength; - float grab_delta[3]; - - SculptProjectVector spvc; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (bstrength < 0.0f) { - negate_v3(grab_delta); - } - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - /* Optionally pinch while painting. */ - if (brush->crease_pinch_factor != 0.5f) { - sculpt_project_v3_cache_init(&spvc, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .spvc = &spvc, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); -} - -static void do_thumb_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *cono = data->cono; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], cono, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - float tmp[3], cono[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); - cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .cono = cono, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); -} - -static void do_rotate_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float angle = data->angle; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - float vec[3], rot[3][3]; - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - sub_v3_v3v3(vec, orig_data.co, ss->cache->location); - axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); - mul_v3_m3v3(proxy[vd.i], rot, vec); - add_v3_v3(proxy[vd.i], ss->cache->location); - sub_v3_v3(proxy[vd.i], orig_data.co); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1}; - const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .angle = angle, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); -} - -static void do_layer_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - Sculpt *sd = data->sd; - const Brush *brush = data->brush; - - const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - const float bstrength = ss->cache->bstrength; - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - const int vi = vd.index; - float *disp_factor; - if (use_persistent_base) { - disp_factor = &ss->persistent_base[vi].disp; - } - else { - disp_factor = &ss->cache->layer_displacement_factor[vi]; - } - - /* When using persistent base, the layer brush (holding Control) invert mode resets the - * height of the layer to 0. This makes possible to clean edges of previously added layers - * on top of the base. */ - /* The main direction of the layers is inverted using the regular brush strength with the - * brush direction property. */ - if (use_persistent_base && ss->cache->invert) { - (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) * - ((*disp_factor) > 0.0f ? -1.0f : 1.0f); - } - else { - (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor)); - } - if (vd.mask) { - const float clamp_mask = 1.0f - *vd.mask; - *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask); - } - else { - *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f); - } - - float final_co[3]; - float normal[3]; - - if (use_persistent_base) { - SCULPT_vertex_persistent_normal_get(ss, vi, normal); - mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); - } - else { - normal_short_to_float_v3(normal, orig_data.no); - mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor); - } - - float vdisp[3]; - sub_v3_v3v3(vdisp, final_co, vd.co); - mul_v3_fl(vdisp, fabsf(fade)); - add_v3_v3v3(final_co, vd.co, vdisp); - - SCULPT_clip(sd, ss, vd.co, final_co); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (ss->cache->layer_displacement_factor == NULL) { - ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss), - "layer displacement factor"); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); -} - -static void do_inflate_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float val[3]; - - if (vd.fno) { - copy_v3_v3(val, vd.fno); - } - else { - normal_short_to_float_v3(val, vd.no); - } - - mul_v3_fl(val, fade * ss->cache->radius); - mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); -} - int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3]) { return (!(brush->flag & BRUSH_PLANE_TRIM) || ((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared))); } -static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip) -{ - float d = plane_point_side_v3(plane, co); - if (flip) { - d = -d; - } - return d <= 0.0f; -} - int SCULPT_plane_point_side(const float co[3], const float plane[4]) { float d = plane_point_side_v3(plane, co); @@ -4893,807 +2956,6 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss) return rv; } -static void do_flatten_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - float intr[3]; - float val[3]; - - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - - sub_v3_v3v3(val, intr, vd.co); - - if (SCULPT_plane_trim(ss->cache, brush, val)) { - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - - float offset = SCULPT_brush_plane_offset_get(sd, ss); - float displace; - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Clay Brush - * \{ */ - -typedef struct ClaySampleData { - float plane_dist[2]; -} ClaySampleData; - -static void calc_clay_surface_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - ClaySampleData *csd = tls->userdata_chunk; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - float plane[4]; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - - /* Apply the brush normal radius to the test before sampling. */ - float test_radius = sqrtf(test.radius_squared); - test_radius *= brush->normal_radius_factor; - test.radius_squared = test_radius * test_radius; - plane_from_point_normal_v3(plane, area_co, area_no); - - if (is_zero_v4(plane)) { - return; - } - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float plane_dist = dist_signed_to_plane_v3(vd.co, plane); - float plane_dist_abs = fabsf(plane_dist); - if (plane_dist > 0.0f) { - csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs); - } - else { - csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs); - } - BKE_pbvh_vertex_iter_end; - } -} - -static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata), - void *__restrict chunk_join, - void *__restrict chunk) -{ - ClaySampleData *join = chunk_join; - ClaySampleData *csd = chunk; - join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]); - join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]); -} - -static void do_clay_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = fabsf(ss->cache->bstrength); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - - sub_v3_v3v3(val, intr, vd.co); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = fabsf(ss->cache->radius); - const float initial_radius = fabsf(ss->cache->initial_radius); - bool flip = ss->cache->bstrength < 0.0f; - - float offset = SCULPT_brush_plane_offset_get(sd, ss); - float displace; - - float area_no[3]; - float area_co[3]; - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SculptThreadedTaskData sample_data = { - .sd = NULL, - .ob = ob, - .brush = brush, - .nodes = nodes, - .totnode = totnode, - .area_no = area_no, - .area_co = ss->cache->location, - }; - - ClaySampleData csd = {{0}}; - - TaskParallelSettings sample_settings; - BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); - sample_settings.func_reduce = calc_clay_surface_reduce; - sample_settings.userdata_chunk = &csd; - sample_settings.userdata_chunk_size = sizeof(ClaySampleData); - - BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); - - float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); - d_offset = min_ff(radius, d_offset); - d_offset = d_offset / radius; - d_offset = 1.0f - d_offset; - displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f))); - if (flip) { - displace = -displace; - } - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - copy_v3_v3(area_co, ss->cache->location); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); -} - -static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*mat)[4] = data->mat; - const float *area_no_sp = data->area_no_sp; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - SculptBrushTest test; - float(*proxy)[3]; - const bool flip = (ss->cache->bstrength < 0.0f); - const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SCULPT_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { - continue; - } - - if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */ - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - ss->cache->radius * test.dist, - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const bool flip = (ss->cache->bstrength < 0.0f); - const float radius = flip ? -ss->cache->radius : ss->cache->radius; - const float offset = SCULPT_brush_plane_offset_get(sd, ss); - const float displace = radius * (0.18f + offset); - - /* The sculpt-plane normal (whatever its set to). */ - float area_no_sp[3]; - - /* Geometry normal */ - float area_no[3]; - float area_co[3]; - - float temp[3]; - float mat[4][4]; - float scale[4][4]; - float tmat[4][4]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); - SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor); - - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); - } - else { - copy_v3_v3(area_no, area_no_sp); - } - - /* Delay the first daub because grab delta is not setup. */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the - * vertices. When in Add mode, vertices that are below the plane and inside the cube are move - * towards the plane. In this situation, there may be cases where a vertex is outside the cube - * but below the plane, so won't be deformed, causing artifacts. In order to prevent these - * artifacts, this displaces the test cube space in relation to the plane in order to - * deform more vertices that may be below it. */ - /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set - * by doing multiple tests using the default "Clay Strips" brush preset. */ - float area_co_displaced[3]; - madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f); - - /* Initialize brush local-space matrix. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], area_co_displaced); - mat[3][3] = 1.0f; - normalize_m4(mat); - - /* Scale brush local space matrix. */ - scale_m4_fl(scale, ss->cache->radius); - mul_m4_m4m4(tmat, mat, scale); - - /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in - * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices - * during big deformation while keeping the surface as uniform as possible. */ - mul_v3_fl(tmat[2], 1.25f); - - invert_m4_m4(mat, tmat); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no_sp = area_no_sp, - .area_co = area_co, - .mat = mat, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); -} - -static void do_fill_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - float offset = SCULPT_brush_plane_offset_get(sd, ss); - - float displace; - - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); -} - -static void do_scrape_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - if (SCULPT_plane_point_side(vd.co, test.plane_tool)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - float offset = SCULPT_brush_plane_offset_get(sd, ss); - - float displace; - - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = -radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Clay Thumb Brush - * \{ */ - -static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*mat)[4] = data->mat; - const float *area_no_sp = data->area_no_sp; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = data->clay_strength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - float plane_tilt[4]; - float normal_tilt[3]; - float imat[4][4]; - - invert_m4_m4(imat, mat); - rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle)); - - /* Plane aligned to the geometry normal (back part of the brush). */ - plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); - /* Tilted plane (front part of the brush). */ - plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - float local_co[3]; - mul_v3_m4v3(local_co, mat, vd.co); - float intr[3], intr_tilt[3]; - float val[3]; - - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co); - - /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex - * coordinates. */ - /* We can also control the mix with a curve if it produces noticeable artifacts in the center - * of the brush. */ - const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f; - interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix); - sub_v3_v3v3(val, intr_tilt, vd.co); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache) -{ - float final_pressure = 0.0f; - for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) { - final_pressure += cache->clay_pressure_stabilizer[i]; - } - return final_pressure / SCULPT_CLAY_STABILIZER_LEN; -} - -static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - const float offset = SCULPT_brush_plane_offset_get(sd, ss); - const float displace = radius * (0.25f + offset); - - /* Sampled geometry normal and area center. */ - float area_no_sp[3]; - float area_no[3]; - float area_co[3]; - - float temp[3]; - float mat[4][4]; - float scale[4][4]; - float tmat[4][4]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); - - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); - } - else { - copy_v3_v3(area_no, area_no_sp); - } - - /* Delay the first daub because grab delta is not setup. */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - ss->cache->clay_thumb_front_angle = 0.0f; - return; - } - - /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the - * stroke. */ - if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { - ss->cache->clay_thumb_front_angle += 0.8f; - ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - /* Displace the brush planes. */ - copy_v3_v3(area_co, ss->cache->location); - mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - /* Initialize brush local-space matrix. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], ss->cache->location); - mat[3][3] = 1.0f; - normalize_m4(mat); - - /* Scale brush local space matrix. */ - scale_m4_fl(scale, ss->cache->radius); - mul_m4_m4m4(tmat, mat, scale); - invert_m4_m4(mat, tmat); - - float clay_strength = ss->cache->bstrength * - sculpt_clay_thumb_get_stabilized_pressure(ss->cache); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no_sp = area_no_sp, - .area_co = ss->cache->location, - .mat = mat, - .clay_strength = clay_strength, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -6036,7 +3298,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Apply one type of brush action. */ switch (brush->sculpt_tool) { case SCULPT_TOOL_DRAW: - do_draw_brush(sd, ob, nodes, totnode); + SCULPT_do_draw_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SMOOTH: if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) { @@ -6047,80 +3309,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } break; case SCULPT_TOOL_CREASE: - do_crease_brush(sd, ob, nodes, totnode); + SCULPT_do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_BLOB: - do_crease_brush(sd, ob, nodes, totnode); + SCULPT_do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, ob, nodes, totnode); + SCULPT_do_pinch_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, ob, nodes, totnode); + SCULPT_do_inflate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_GRAB: - do_grab_brush(sd, ob, nodes, totnode); + SCULPT_do_grab_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_ROTATE: - do_rotate_brush(sd, ob, nodes, totnode); + SCULPT_do_rotate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SNAKE_HOOK: - do_snake_hook_brush(sd, ob, nodes, totnode); + SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_NUDGE: - do_nudge_brush(sd, ob, nodes, totnode); + SCULPT_do_nudge_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_THUMB: - do_thumb_brush(sd, ob, nodes, totnode); + SCULPT_do_thumb_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_LAYER: - do_layer_brush(sd, ob, nodes, totnode); + SCULPT_do_layer_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FLATTEN: - do_flatten_brush(sd, ob, nodes, totnode); + SCULPT_do_flatten_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY: - do_clay_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY_STRIPS: - do_clay_strips_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_MULTIPLANE_SCRAPE: SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY_THUMB: - do_clay_thumb_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FILL: if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) { - do_scrape_brush(sd, ob, nodes, totnode); + SCULPT_do_scrape_brush(sd, ob, nodes, totnode); } else { - do_fill_brush(sd, ob, nodes, totnode); + SCULPT_do_fill_brush(sd, ob, nodes, totnode); } break; case SCULPT_TOOL_SCRAPE: if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) { - do_fill_brush(sd, ob, nodes, totnode); + SCULPT_do_fill_brush(sd, ob, nodes, totnode); } else { - do_scrape_brush(sd, ob, nodes, totnode); + SCULPT_do_scrape_brush(sd, ob, nodes, totnode); } break; case SCULPT_TOOL_MASK: - do_mask_brush(sd, ob, nodes, totnode); + SCULPT_do_mask_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_POSE: SCULPT_do_pose_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DRAW_SHARP: - do_draw_sharp_brush(sd, ob, nodes, totnode); + SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_ELASTIC_DEFORM: - do_elastic_deform_brush(sd, ob, nodes, totnode); + SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SLIDE_RELAX: - do_slide_relax_brush(sd, ob, nodes, totnode); + SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_BOUNDARY: SCULPT_do_boundary_brush(sd, ob, nodes, totnode); @@ -6132,10 +3394,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DISPLACEMENT_ERASER: - do_displacement_eraser_brush(sd, ob, nodes, totnode); + SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DISPLACEMENT_SMEAR: - do_displacement_smear_brush(sd, ob, nodes, totnode); + SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); @@ -6157,7 +3419,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } if (sculpt_brush_use_topology_rake(ss, brush)) { - bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); + SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); } /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ @@ -6737,6 +3999,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) { ModifierData *md; + unit_m4(ss->cache->clip_mirror_mtx); + for (md = ob->modifiers.first; md; md = md->next) { if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) { continue; @@ -6758,6 +4022,13 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) if (mmd->tolerance > ss->cache->clip_tolerance[i]) { ss->cache->clip_tolerance[i] = mmd->tolerance; } + + /* Store matrix for mirror object clipping. */ + if (mmd->mirror_ob) { + float imtx_mirror_ob[4][4]; + invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat); + mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat); + } } } } @@ -6946,7 +4217,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo case SCULPT_TOOL_CLAY_STRIPS: return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f)); case SCULPT_TOOL_CLAY_THUMB: { - float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache); + float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache); return initial_size * clay_stabilized_pressure; } default: @@ -8131,7 +5402,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) sculpt_brush_exit_tex(sd); } -static void SCULPT_OT_brush_stroke(wmOperatorType *ot) +void SCULPT_OT_brush_stroke(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Sculpt"; @@ -8159,677 +5430,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) "Clicks on the background do not start the stroke"); } -/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */ - -static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - if (!ss) { - return OPERATOR_FINISHED; - } - SCULPT_vertex_random_access_ensure(ss); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - - MEM_SAFE_FREE(ss->persistent_base); - - const int totvert = SCULPT_vertex_count_get(ss); - ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, - "layer persistent base"); - - for (int i = 0; i < totvert; i++) { - copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); - SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); - ss->persistent_base[i].disp = 0.0f; - } - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Set Persistent Base"; - ot->idname = "SCULPT_OT_set_persistent_base"; - ot->description = "Reset the copy of the mesh that is being sculpted on"; - - /* API callbacks. */ - ot->exec = sculpt_set_persistent_base_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/************************* SCULPT_OT_optimize *************************/ - -static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - SCULPT_pbvh_clear(ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -/* The BVH gets less optimal more quickly with dynamic topology than - * regular sculpting. There is no doubt more clever stuff we can do to - * optimize it on the fly, but for now this gives the user a nicer way - * to recalculate it than toggling modes. */ -static void SCULPT_OT_optimize(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Rebuild BVH"; - ot->idname = "SCULPT_OT_optimize"; - ot->description = "Recalculate the sculpt BVH to improve performance"; - - /* API callbacks. */ - ot->exec = sculpt_optimize_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/********************* Dynamic topology symmetrize ********************/ - -static bool sculpt_no_multires_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) { - return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS; - } - return false; -} - -static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Object *ob = CTX_data_active_object(C); - const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - SculptSession *ss = ob->sculpt; - PBVH *pbvh = ss->pbvh; - const float dist = RNA_float_get(op->ptr, "merge_tolerance"); - - if (!pbvh) { - return OPERATOR_CANCELLED; - } - - switch (BKE_pbvh_type(pbvh)) { - case PBVH_BMESH: - /* Dyntopo Symmetrize. */ - - /* To simplify undo for symmetrize, all BMesh elements are logged - * as deleted, then after symmetrize operation all BMesh elements - * are logged as added (as opposed to attempting to store just the - * parts that symmetrize modifies). */ - SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize"); - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); - BM_log_before_all_removed(ss->bm, ss->bm_log); - - BM_mesh_toolflags_set(ss->bm, true); - - /* Symmetrize and re-triangulate. */ - BMO_op_callf(ss->bm, - (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", - sd->symmetrize_direction, - dist, - true); - SCULPT_dynamic_topology_triangulate(ss->bm); - - /* Bisect operator flags edges (keep tags clean for edge queue). */ - BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); - - BM_mesh_toolflags_set(ss->bm, false); - - /* Finish undo. */ - BM_log_all_added(ss->bm, ss->bm_log); - SCULPT_undo_push_end(); - - break; - case PBVH_FACES: - /* Mesh Symmetrize. */ - ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); - Mesh *mesh = ob->data; - - BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist); - - ED_sculpt_undo_geometry_end(ob); - BKE_mesh_calc_normals(ob->data); - BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - - break; - case PBVH_GRIDS: - return OPERATOR_CANCELLED; - } - - /* Redraw. */ - SCULPT_pbvh_clear(ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_symmetrize(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Symmetrize"; - ot->idname = "SCULPT_OT_symmetrize"; - ot->description = "Symmetrize the topology modifications"; - - /* API callbacks. */ - ot->exec = sculpt_symmetrize_exec; - ot->poll = sculpt_no_multires_poll; - - RNA_def_float(ot->srna, - "merge_tolerance", - 0.001f, - 0.0f, - FLT_MAX, - "Merge Distance", - "Distance within which symmetrical vertices are merged", - 0.0f, - 1.0f); -} - -/**** Toggle operator for turning sculpt mode on or off ****/ - -static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - /* Create persistent sculpt mode data. */ - BKE_sculpt_toolsettings_data_ensure(scene); - - /* Create sculpt mode session data. */ - if (ob->sculpt != NULL) { - BKE_sculptsession_free(ob); - } - ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - ob->sculpt->mode_type = OB_MODE_SCULPT; - - BKE_sculpt_ensure_orig_mesh_data(scene, ob); - - BKE_scene_graph_evaluated_ensure(depsgraph, bmain); - - /* This function expects a fully evaluated depsgraph. */ - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - - /* Here we can detect geometry that was just added to Sculpt Mode as it has the - * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ - /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not - * initialized, which is used is some operators that modify the mesh topology to perform certain - * actions in the new polys. After these operations are finished, all polys should have a valid - * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility - * correctly. */ - /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new - * objects, like moving the transform pivot position to the new area or masking existing - * geometry. */ - SculptSession *ss = ob->sculpt; - const int new_face_set = SCULPT_face_set_next_available_get(ss); - for (int i = 0; i < ss->totfaces; i++) { - if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { - ss->face_sets[i] = new_face_set; - } - } -} - -void ED_object_sculptmode_enter_ex(Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - Object *ob, - const bool force_dyntopo, - ReportList *reports) -{ - const int mode_flag = OB_MODE_SCULPT; - Mesh *me = BKE_mesh_from_object(ob); - - /* Enter sculpt mode. */ - ob->mode |= mode_flag; - - sculpt_init_session(bmain, depsgraph, scene, ob); - - if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && - fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) { - BKE_report( - reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); - } - else if (is_negative_m4(ob->obmat)) { - BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); - } - - Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); - BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); - - paint_cursor_start(paint, SCULPT_mode_poll_view3d); - - /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, - * As long as no data was added that is not supported. */ - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - - const char *message_unsupported = NULL; - if (me->totloop != me->totpoly * 3) { - message_unsupported = TIP_("non-triangle face"); - } - else if (mmd != NULL) { - message_unsupported = TIP_("multi-res modifier"); - } - else { - enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob); - if (flag == 0) { - /* pass */ - } - else if (flag & DYNTOPO_WARN_VDATA) { - message_unsupported = TIP_("vertex data"); - } - else if (flag & DYNTOPO_WARN_EDATA) { - message_unsupported = TIP_("edge data"); - } - else if (flag & DYNTOPO_WARN_LDATA) { - message_unsupported = TIP_("face data"); - } - else if (flag & DYNTOPO_WARN_MODIFIER) { - message_unsupported = TIP_("constructive modifier"); - } - else { - BLI_assert(0); - } - } - - if ((message_unsupported == NULL) || force_dyntopo) { - /* Needed because we may be entering this mode before the undo system loads. */ - wmWindowManager *wm = bmain->wm.first; - bool has_undo = wm->undo_stack != NULL; - /* Undo push is needed to prevent memory leak. */ - if (has_undo) { - SCULPT_undo_push_begin(ob, "Dynamic topology enable"); - } - SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); - if (has_undo) { - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); - SCULPT_undo_push_end(); - } - } - else { - BKE_reportf( - reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); - me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; - } - } - - /* Flush object mode. */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); -} - -void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports); -} - -void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - const int mode_flag = OB_MODE_SCULPT; - Mesh *me = BKE_mesh_from_object(ob); - - multires_flush_sculpt_updates(ob); - - /* Not needed for now. */ -#if 0 - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); -#endif - - /* Always for now, so leaving sculpt mode always ensures scene is in - * a consistent state. */ - if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - /* Dynamic topology must be disabled before exiting sculpt - * mode to ensure the undo stack stays in a consistent - * state. */ - sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob); - - /* Store so we know to re-enable when entering sculpt mode. */ - me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; - } - - /* Leave sculpt mode. */ - ob->mode &= ~mode_flag; - - BKE_sculptsession_free(ob); - - paint_cursor_delete_textures(); - - /* Never leave derived meshes behind. */ - BKE_object_free_derived_caches(ob); - - /* Flush object mode. */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); -} - -void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); -} - -static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) -{ - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - const int mode_flag = OB_MODE_SCULPT; - const bool is_mode_set = (ob->mode & mode_flag) != 0; - - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } - - if (is_mode_set) { - ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); - } - else { - if (depsgraph) { - depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - } - ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports); - BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); - - if (ob->mode & mode_flag) { - Mesh *me = ob->data; - /* Dyntopo adds its own undo step. */ - if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { - /* Without this the memfile undo step is used, - * while it works it causes lag when undoing the first undo step, see T71564. */ - wmWindowManager *wm = CTX_wm_manager(C); - if (wm->op_undo_depth <= 1) { - SCULPT_undo_push_begin(ob, op->type->name); - } - } - } - } - - WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - - WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); - - WM_toolsystem_update_from_context_view3d(C); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Sculpt Mode"; - ot->idname = "SCULPT_OT_sculptmode_toggle"; - ot->description = "Toggle sculpt mode in 3D view"; - - /* API callbacks. */ - ot->exec = sculpt_mode_toggle_exec; - ot->poll = ED_operator_object_active_editable_mesh; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - - ss->preview_vert_index_count = 0; - int totpoints = 0; - - /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ - if (!ss->pbvh) { - return; - } - - if (!ss->deform_modifiers_active) { - return; - } - - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return; - } - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - if (!ss->pmap) { - return; - } - - float brush_co[3]; - copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); - - BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); - - /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ - const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; - - if (ss->preview_vert_index_list == NULL) { - ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); - } - - GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); - int active_v = SCULPT_active_vertex_get(ss); - BLI_gsqueue_push(not_visited_vertices, &active_v); - - while (!BLI_gsqueue_is_empty(not_visited_vertices)) { - int from_v; - BLI_gsqueue_pop(not_visited_vertices, &from_v); - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - if (totpoints + (ni.size * 2) < max_preview_vertices) { - int to_v = ni.index; - ss->preview_vert_index_list[totpoints] = from_v; - totpoints++; - ss->preview_vert_index_list[totpoints] = to_v; - totpoints++; - if (BLI_BITMAP_TEST(visited_vertices, to_v)) { - continue; - } - BLI_BITMAP_ENABLE(visited_vertices, to_v); - const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); - if (len_squared_v3v3(brush_co, co) < radius * radius) { - BLI_gsqueue_push(not_visited_vertices, &to_v); - } - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - } - - BLI_gsqueue_free(not_visited_vertices); - - MEM_freeN(visited_vertices); - - ss->preview_vert_index_count = totpoints; -} - -static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data && ID_IS_LINKED(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - MLoop *c_loop = &loops[c_poly->loopstart + j]; - float srgb_color[4]; - linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color); - loopcols[loop_index].r = (char)(srgb_color[0] * 255); - loopcols[loop_index].g = (char)(srgb_color[1] * 255); - loopcols[loop_index].b = (char)(srgb_color[2] * 255); - loopcols[loop_index].a = (char)(srgb_color[3] * 255); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sculpt Vertex Color to Vertex Color"; - ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; - ot->idname = "SCULPT_OT_vertex_to_loop_colors"; - - /* api callbacks */ - ot->poll = SCULPT_vertex_colors_poll; - ot->exec = vertex_to_loop_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data && ID_IS_LINKED(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - MLoop *c_loop = &loops[c_poly->loopstart + j]; - vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); - vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); - vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); - vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); - srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Color to Sculpt Vertex Color"; - ot->description = "Copy the active loop color layer to the vertex color"; - ot->idname = "SCULPT_OT_loop_to_vertex_colors"; - - /* api callbacks */ - ot->poll = SCULPT_vertex_colors_poll; - ot->exec = loop_to_vertex_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int sculpt_sample_color_invoke(bContext *C, - wmOperator *UNUSED(op), - const wmEvent *UNUSED(e)) -{ - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Brush *brush = BKE_paint_brush(&sd->paint); - SculptSession *ss = ob->sculpt; - int active_vertex = SCULPT_active_vertex_get(ss); - const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex); - if (!active_vertex_color) { - return OPERATOR_CANCELLED; - } - - float color_srgb[3]; - copy_v3_v3(color_srgb, active_vertex_color); - IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb); - BKE_brush_color_set(scene, brush, color_srgb); - - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_sample_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sample Color"; - ot->idname = "SCULPT_OT_sample_color"; - ot->description = "Sample the vertex color of the active vertex"; - - /* api callbacks */ - ot->invoke = sculpt_sample_color_invoke; - ot->poll = SCULPT_vertex_colors_poll; - - ot->flag = OPTYPE_REGISTER; -} - /* Fake Neighbors. */ /* This allows the sculpt tools to work on meshes with multiple connected components as they had * only one connected component. When initialized and enabled, the sculpt API will return extra @@ -9105,356 +5705,10 @@ void SCULPT_fake_neighbors_free(Object *ob) sculpt_pose_fake_neighbors_free(ss); } -/** - * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the - * mask based on the difference between two colors (the active color and the color of any other - * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active - * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer - * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between - * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going - * to be. - */ -#define MASK_BY_COLOR_SLOPE 0.25f - -static float sculpt_mask_by_color_delta_get(const float *color_a, - const float *color_b, - const float threshold, - const bool invert) -{ - float len = len_v3v3(color_a, color_b); - /* Normalize len to the (0, 1) range. */ - len = len / M_SQRT3; - - if (len < threshold - MASK_BY_COLOR_SLOPE) { - len = 1.0f; - } - else if (len >= threshold) { - len = 0.0f; - } - else { - len = (-len + threshold) / MASK_BY_COLOR_SLOPE; - } - - if (invert) { - return 1.0f - len; - } - return len; -} - -static float sculpt_mask_by_color_final_mask_get(const float current_mask, - const float new_mask, - const bool invert, - const bool preserve_mask) -{ - if (preserve_mask) { - if (invert) { - return min_ff(current_mask, new_mask); - } - return max_ff(current_mask, new_mask); - } - return new_mask; -} - -typedef struct MaskByColorContiguousFloodFillData { - float threshold; - bool invert; - float *new_mask; - float initial_color[3]; -} MaskByColorContiguousFloodFillData; - -static void do_mask_by_color_contiguous_update_nodes_cb( - void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); - bool update_node = false; - - const bool invert = data->mask_by_color_invert; - const bool preserve_mask = data->mask_by_color_preserve_mask; - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float current_mask = *vd.mask; - const float new_mask = data->mask_by_color_floodfill[vd.index]; - *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); - if (current_mask == *vd.mask) { - continue; - } - update_node = true; - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; - if (update_node) { - BKE_pbvh_node_mark_redraw(data->nodes[n]); - } -} - -static bool sculpt_mask_by_color_contiguous_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) -{ - MaskByColorContiguousFloodFillData *data = userdata; - const float *current_color = SCULPT_vertex_color_get(ss, to_v); - float new_vertex_mask = sculpt_mask_by_color_delta_get( - current_color, data->initial_color, data->threshold, data->invert); - data->new_mask[to_v] = new_vertex_mask; - - if (is_duplicate) { - data->new_mask[to_v] = data->new_mask[from_v]; - } - - float len = len_v3v3(current_color, data->initial_color); - len = len / M_SQRT3; - return len <= data->threshold; -} - -static void sculpt_mask_by_color_contiguous(Object *object, - const int vertex, - const float threshold, - const bool invert, - const bool preserve_mask) -{ - SculptSession *ss = object->sculpt; - const int totvert = SCULPT_vertex_count_get(ss); - - float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask"); - - if (invert) { - for (int i = 0; i < totvert; i++) { - new_mask[i] = 1.0f; - } - } - - SculptFloodFill flood; - SCULPT_floodfill_init(ss, &flood); - SCULPT_floodfill_add_initial(&flood, vertex); - - MaskByColorContiguousFloodFillData ffd; - ffd.threshold = threshold; - ffd.invert = invert; - ffd.new_mask = new_mask; - copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex)); - - SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd); - SCULPT_floodfill_free(&flood); - - int totnode; - PBVHNode **nodes; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - - SculptThreadedTaskData data = { - .ob = object, - .nodes = nodes, - .mask_by_color_floodfill = new_mask, - .mask_by_color_vertex = vertex, - .mask_by_color_threshold = threshold, - .mask_by_color_invert = invert, - .mask_by_color_preserve_mask = preserve_mask, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range( - 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings); - - MEM_SAFE_FREE(nodes); - - MEM_freeN(new_mask); -} - -static void do_mask_by_color_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); - bool update_node = false; - - const float threshold = data->mask_by_color_threshold; - const bool invert = data->mask_by_color_invert; - const bool preserve_mask = data->mask_by_color_preserve_mask; - const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float current_mask = *vd.mask; - const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert); - *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); - - if (current_mask == *vd.mask) { - continue; - } - update_node = true; - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; - if (update_node) { - BKE_pbvh_node_mark_redraw(data->nodes[n]); - } -} - -static void sculpt_mask_by_color_full_mesh(Object *object, - const int vertex, - const float threshold, - const bool invert, - const bool preserve_mask) -{ - SculptSession *ss = object->sculpt; - - int totnode; - PBVHNode **nodes; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - - SculptThreadedTaskData data = { - .ob = object, - .nodes = nodes, - .mask_by_color_vertex = vertex, - .mask_by_color_threshold = threshold, - .mask_by_color_invert = invert, - .mask_by_color_preserve_mask = preserve_mask, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings); - - MEM_SAFE_FREE(nodes); -} - -static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - /* Color data is not available in Multires. */ - if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { - return OPERATOR_CANCELLED; - } - - if (!ss->vcol) { - return OPERATOR_CANCELLED; - } - - SCULPT_vertex_random_access_ensure(ss); - - /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, - * so it needs to be updated here. */ - SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); - - SCULPT_undo_push_begin(ob, "Mask by color"); - - const int active_vertex = SCULPT_active_vertex_get(ss); - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool invert = RNA_boolean_get(op->ptr, "invert"); - const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); - - if (RNA_boolean_get(op->ptr, "contiguous")) { - sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); - } - else { - sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); - } - - BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); - SCULPT_undo_push_end(); - - SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_mask_by_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Mask by Color"; - ot->idname = "SCULPT_OT_mask_by_color"; - ot->description = "Creates a mask based on the sculpt vertex colors"; - - /* api callbacks */ - ot->invoke = sculpt_mask_by_color_invoke; - ot->poll = SCULPT_vertex_colors_poll; - - ot->flag = OPTYPE_REGISTER; - - ot->prop = RNA_def_boolean( - ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas"); - - ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask"); - ot->prop = RNA_def_boolean( - ot->srna, - "preserve_previous_mask", - false, - "Preserve Previous Mask", - "Preserve the previous mask and add or subtract the new one generated by the colors"); - - RNA_def_float(ot->srna, - "threshold", - 0.35f, - 0.0f, - 1.0f, - "Threshold", - "How much changes in color affect the mask generation", - 0.0f, - 1.0f); -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Operator Registration * \{ */ -void ED_operatortypes_sculpt(void) -{ - WM_operatortype_append(SCULPT_OT_brush_stroke); - WM_operatortype_append(SCULPT_OT_sculptmode_toggle); - WM_operatortype_append(SCULPT_OT_set_persistent_base); - WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); - WM_operatortype_append(SCULPT_OT_optimize); - WM_operatortype_append(SCULPT_OT_symmetrize); - WM_operatortype_append(SCULPT_OT_detail_flood_fill); - WM_operatortype_append(SCULPT_OT_sample_detail_size); - WM_operatortype_append(SCULPT_OT_set_detail_size); - WM_operatortype_append(SCULPT_OT_mesh_filter); - WM_operatortype_append(SCULPT_OT_mask_filter); - WM_operatortype_append(SCULPT_OT_dirty_mask); - WM_operatortype_append(SCULPT_OT_mask_expand); - WM_operatortype_append(SCULPT_OT_set_pivot_position); - WM_operatortype_append(SCULPT_OT_face_sets_create); - WM_operatortype_append(SCULPT_OT_face_sets_change_visibility); - WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors); - WM_operatortype_append(SCULPT_OT_face_sets_init); - WM_operatortype_append(SCULPT_OT_cloth_filter); - WM_operatortype_append(SCULPT_OT_face_sets_edit); - WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture); - WM_operatortype_append(SCULPT_OT_face_set_box_gesture); - WM_operatortype_append(SCULPT_OT_trim_box_gesture); - WM_operatortype_append(SCULPT_OT_trim_lasso_gesture); - WM_operatortype_append(SCULPT_OT_project_line_gesture); - - WM_operatortype_append(SCULPT_OT_sample_color); - WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); - WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); - WM_operatortype_append(SCULPT_OT_color_filter); - WM_operatortype_append(SCULPT_OT_mask_by_color); - WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); - WM_operatortype_append(SCULPT_OT_mask_init); - - WM_operatortype_append(SCULPT_OT_expand); -} - /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_brushes.c b/source/blender/editors/sculpt_paint/sculpt_brushes.c new file mode 100644 index 00000000000..8842d93410c --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_brushes.c @@ -0,0 +1,2847 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * Implements the Sculpt Mode tools + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_dial_2d.h" +#include "BLI_ghash.h" +#include "BLI_gsqueue.h" +#include "BLI_hash.h" +#include "BLI_math.h" +#include "BLI_math_color.h" +#include "BLI_math_color_blend.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_kelvinlet.h" +#include "BKE_key.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_mirror.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_pbvh.h" +#include "BKE_pointcache.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subsurf.h" + +#include "DEG_depsgraph.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_view3d.h" + +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +/* -------------------------------------------------------------------- */ +/** \name SculptProjectVector + * + * Fast-path for #project_plane_v3_v3v3 + * \{ */ + +typedef struct SculptProjectVector { + float plane[3]; + float len_sq; + float len_sq_inv_neg; + bool is_valid; + +} SculptProjectVector; + +static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip) +{ + float d = plane_point_side_v3(plane, co); + if (flip) { + d = -d; + } + return d <= 0.0f; +} + +/** + * \param plane: Direction, can be any length. + */ +static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3]) +{ + copy_v3_v3(spvc->plane, plane); + spvc->len_sq = len_squared_v3(spvc->plane); + spvc->is_valid = (spvc->len_sq > FLT_EPSILON); + spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f; +} + +/** + * Calculate the projection. + */ +static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3]) +{ +#if 0 + project_plane_v3_v3v3(r_vec, vec, spvc->plane); +#else + /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */ + madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg); +#endif +} + +static void calc_sculpt_plane( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) && + (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) || + !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { + switch (brush->sculpt_plane) { + case SCULPT_DISP_DIR_VIEW: + copy_v3_v3(r_area_no, ss->cache->true_view_normal); + break; + + case SCULPT_DISP_DIR_X: + ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f); + break; + + case SCULPT_DISP_DIR_Y: + ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f); + break; + + case SCULPT_DISP_DIR_Z: + ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f); + break; + + case SCULPT_DISP_DIR_AREA: + SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); + normalize_v3(r_area_no); + } + break; + + default: + break; + } + + /* For flatten center. */ + /* Flatten center has not been calculated yet if we are not using the area normal. */ + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { + SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co); + } + + /* For area normal. */ + if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && + (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + copy_v3_v3(r_area_no, ss->cache->sculpt_normal); + } + else { + copy_v3_v3(ss->cache->sculpt_normal, r_area_no); + } + + /* For flatten center. */ + if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && + (brush->flag & BRUSH_ORIGINAL_PLANE)) { + copy_v3_v3(r_area_co, ss->cache->last_center); + } + else { + copy_v3_v3(ss->cache->last_center, r_area_co); + } + } + else { + /* For area normal. */ + copy_v3_v3(r_area_no, ss->cache->sculpt_normal); + + /* For flatten center. */ + copy_v3_v3(r_area_co, ss->cache->last_center); + + /* For area normal. */ + flip_v3(r_area_no, ss->cache->mirror_symmetry_pass); + + /* For flatten center. */ + flip_v3(r_area_co, ss->cache->mirror_symmetry_pass); + + /* For area normal. */ + mul_m4_v3(ss->cache->symm_rot_mat, r_area_no); + + /* For flatten center. */ + mul_m4_v3(ss->cache->symm_rot_mat, r_area_co); + + /* Shift the plane for the current tile. */ + add_v3_v3(r_area_co, ss->cache->plane_offset); + } +} + +static void sculpt_rake_rotate(const SculptSession *ss, + const float sculpt_co[3], + const float v_co[3], + float factor, + float r_delta[3]) +{ + float vec_rot[3]; + +#if 0 + /* lerp */ + sub_v3_v3v3(vec_rot, v_co, sculpt_co); + mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot); + add_v3_v3(vec_rot, sculpt_co); + sub_v3_v3v3(r_delta, vec_rot, v_co); + mul_v3_fl(r_delta, factor); +#else + /* slerp */ + float q_interp[4]; + sub_v3_v3v3(vec_rot, v_co, sculpt_co); + + copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry); + pow_qt_fl_normalized(q_interp, factor); + mul_qt_v3(q_interp, vec_rot); + + add_v3_v3(vec_rot, sculpt_co); + sub_v3_v3v3(r_delta, vec_rot, v_co); +#endif +} + +/** + * Align the grab delta to the brush normal. + * + * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`. + */ +static void sculpt_project_v3_normal_align(SculptSession *ss, + const float normal_weight, + float grab_delta[3]) +{ + /* Signed to support grabbing in (to make a hole) as well as out. */ + const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta); + + /* This scale effectively projects the offset so dragging follows the cursor, + * as the normal points towards the view, the scale increases. */ + float len_view_scale; + { + float view_aligned_normal[3]; + project_plane_v3_v3v3( + view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal); + len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm)); + len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f; + } + + mul_v3_fl(grab_delta, 1.0f - normal_weight); + madd_v3_v3fl( + grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Draw Brush + * \{ */ + +static void do_draw_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *offset = data->offset; + + PBVHVertexIter vd; + float(*proxy)[3]; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], offset, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + const float bstrength = ss->cache->bstrength; + + /* Offset with as much as possible factored in already. */ + float effective_normal[3]; + SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); + mul_v3_v3fl(offset, effective_normal, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise + * initialize before threads so they can do curve mapping. */ + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .offset = offset, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); +} + +/** \} */ + +static void do_fill_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + float offset = SCULPT_brush_plane_offset_get(sd, ss); + + float displace; + + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); +} + +static void do_scrape_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + if (SCULPT_plane_point_side(vd.co, test.plane_tool)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + float offset = SCULPT_brush_plane_offset_get(sd, ss); + + float displace; + + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = -radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Clay Thumb Brush + * \{ */ + +static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*mat)[4] = data->mat; + const float *area_no_sp = data->area_no_sp; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = data->clay_strength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + float plane_tilt[4]; + float normal_tilt[3]; + float imat[4][4]; + + invert_m4_m4(imat, mat); + rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle)); + + /* Plane aligned to the geometry normal (back part of the brush). */ + plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + /* Tilted plane (front part of the brush). */ + plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + float local_co[3]; + mul_v3_m4v3(local_co, mat, vd.co); + float intr[3], intr_tilt[3]; + float val[3]; + + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co); + + /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex + * coordinates. */ + /* We can also control the mix with a curve if it produces noticeable artifacts in the center + * of the brush. */ + const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f; + interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix); + sub_v3_v3v3(val, intr_tilt, vd.co); + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache) +{ + float final_pressure = 0.0f; + for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) { + final_pressure += cache->clay_pressure_stabilizer[i]; + } + return final_pressure / SCULPT_CLAY_STABILIZER_LEN; +} + +void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + const float offset = SCULPT_brush_plane_offset_get(sd, ss); + const float displace = radius * (0.25f + offset); + + /* Sampled geometry normal and area center. */ + float area_no_sp[3]; + float area_no[3]; + float area_co[3]; + + float temp[3]; + float mat[4][4]; + float scale[4][4]; + float tmat[4][4]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); + + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); + } + else { + copy_v3_v3(area_no, area_no_sp); + } + + /* Delay the first daub because grab delta is not setup. */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + ss->cache->clay_thumb_front_angle = 0.0f; + return; + } + + /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the + * stroke. */ + if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { + ss->cache->clay_thumb_front_angle += 0.8f; + ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + /* Displace the brush planes. */ + copy_v3_v3(area_co, ss->cache->location); + mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + /* Initialize brush local-space matrix. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1.0f; + normalize_m4(mat); + + /* Scale brush local space matrix. */ + scale_m4_fl(scale, ss->cache->radius); + mul_m4_m4m4(tmat, mat, scale); + invert_m4_m4(mat, tmat); + + float clay_strength = ss->cache->bstrength * + SCULPT_clay_thumb_get_stabilized_pressure(ss->cache); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no_sp = area_no_sp, + .area_co = ss->cache->location, + .mat = mat, + .clay_strength = clay_strength, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); +} + +/** \} */ + +static void do_flatten_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + float intr[3]; + float val[3]; + + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + + sub_v3_v3v3(val, intr, vd.co); + + if (SCULPT_plane_trim(ss->cache, brush, val)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + + float offset = SCULPT_brush_plane_offset_get(sd, ss); + float displace; + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Clay Brush + * \{ */ + +typedef struct ClaySampleData { + float plane_dist[2]; +} ClaySampleData; + +static void calc_clay_surface_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + ClaySampleData *csd = tls->userdata_chunk; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + float plane[4]; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, brush->falloff_shape); + + /* Apply the brush normal radius to the test before sampling. */ + float test_radius = sqrtf(test.radius_squared); + test_radius *= brush->normal_radius_factor; + test.radius_squared = test_radius * test_radius; + plane_from_point_normal_v3(plane, area_co, area_no); + + if (is_zero_v4(plane)) { + return; + } + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float plane_dist = dist_signed_to_plane_v3(vd.co, plane); + float plane_dist_abs = fabsf(plane_dist); + if (plane_dist > 0.0f) { + csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs); + } + else { + csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs); + } + BKE_pbvh_vertex_iter_end; + } +} + +static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + ClaySampleData *join = chunk_join; + ClaySampleData *csd = chunk; + join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]); + join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]); +} + +static void do_clay_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = fabsf(ss->cache->bstrength); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + + sub_v3_v3v3(val, intr, vd.co); + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = fabsf(ss->cache->radius); + const float initial_radius = fabsf(ss->cache->initial_radius); + bool flip = ss->cache->bstrength < 0.0f; + + float offset = SCULPT_brush_plane_offset_get(sd, ss); + float displace; + + float area_no[3]; + float area_co[3]; + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SculptThreadedTaskData sample_data = { + .sd = NULL, + .ob = ob, + .brush = brush, + .nodes = nodes, + .totnode = totnode, + .area_no = area_no, + .area_co = ss->cache->location, + }; + + ClaySampleData csd = {{0}}; + + TaskParallelSettings sample_settings; + BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); + sample_settings.func_reduce = calc_clay_surface_reduce; + sample_settings.userdata_chunk = &csd; + sample_settings.userdata_chunk_size = sizeof(ClaySampleData); + + BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); + + float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); + d_offset = min_ff(radius, d_offset); + d_offset = d_offset / radius; + d_offset = 1.0f - d_offset; + displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f))); + if (flip) { + displace = -displace; + } + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + copy_v3_v3(area_co, ss->cache->location); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); +} + +static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*mat)[4] = data->mat; + const float *area_no_sp = data->area_no_sp; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + SculptBrushTest test; + float(*proxy)[3]; + const bool flip = (ss->cache->bstrength < 0.0f); + const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SCULPT_brush_test_init(ss, &test); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { + continue; + } + + if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */ + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + ss->cache->radius * test.dist, + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const bool flip = (ss->cache->bstrength < 0.0f); + const float radius = flip ? -ss->cache->radius : ss->cache->radius; + const float offset = SCULPT_brush_plane_offset_get(sd, ss); + const float displace = radius * (0.18f + offset); + + /* The sculpt-plane normal (whatever its set to). */ + float area_no_sp[3]; + + /* Geometry normal */ + float area_no[3]; + float area_co[3]; + + float temp[3]; + float mat[4][4]; + float scale[4][4]; + float tmat[4][4]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); + SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor); + + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); + } + else { + copy_v3_v3(area_no, area_no_sp); + } + + /* Delay the first daub because grab delta is not setup. */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the + * vertices. When in Add mode, vertices that are below the plane and inside the cube are move + * towards the plane. In this situation, there may be cases where a vertex is outside the cube + * but below the plane, so won't be deformed, causing artifacts. In order to prevent these + * artifacts, this displaces the test cube space in relation to the plane in order to + * deform more vertices that may be below it. */ + /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set + * by doing multiple tests using the default "Clay Strips" brush preset. */ + float area_co_displaced[3]; + madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f); + + /* Initialize brush local-space matrix. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], area_co_displaced); + mat[3][3] = 1.0f; + normalize_m4(mat); + + /* Scale brush local space matrix. */ + scale_m4_fl(scale, ss->cache->radius); + mul_m4_m4m4(tmat, mat, scale); + + /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in + * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices + * during big deformation while keeping the surface as uniform as possible. */ + mul_v3_fl(tmat[2], 1.25f); + + invert_m4_m4(mat, tmat); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no_sp = area_no_sp, + .area_co = area_co, + .mat = mat, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); +} + +static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + SculptProjectVector *spvc = data->spvc; + const float *grab_delta = data->grab_delta; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + const bool do_rake_rotation = ss->cache->is_rake_rotation_valid; + const bool do_pinch = (brush->crease_pinch_factor != 0.5f); + const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) * + (len_v3(grab_delta) / ss->cache->radius)) : + 0.0f; + + const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + KelvinletParams params; + BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float fade; + if (do_elastic) { + fade = 1.0f; + } + else { + fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + } + + mul_v3_v3fl(proxy[vd.i], grab_delta, fade); + + /* Negative pinch will inflate, helps maintain volume. */ + if (do_pinch) { + float delta_pinch_init[3], delta_pinch[3]; + + sub_v3_v3v3(delta_pinch, vd.co, test.location); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal); + } + + /* Important to calculate based on the grabbed location + * (intentionally ignore fade here). */ + add_v3_v3(delta_pinch, grab_delta); + + sculpt_project_v3(spvc, delta_pinch, delta_pinch); + + copy_v3_v3(delta_pinch_init, delta_pinch); + + float pinch_fade = pinch * fade; + /* When reducing, scale reduction back by how close to the center we are, + * so we don't pinch into nothingness. */ + if (pinch > 0.0f) { + /* Square to have even less impact for close vertices. */ + pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius)); + } + mul_v3_fl(delta_pinch, 1.0f + pinch_fade); + sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch); + add_v3_v3(proxy[vd.i], delta_pinch); + } + + if (do_rake_rotation) { + float delta_rotate[3]; + sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate); + add_v3_v3(proxy[vd.i], delta_rotate); + } + + if (do_elastic) { + float disp[3]; + BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); + mul_v3_fl(disp, bstrength * 20.0f); + if (vd.mask) { + mul_v3_fl(disp, 1.0f - *vd.mask); + } + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + copy_v3_v3(proxy[vd.i], disp); + } + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + const float bstrength = ss->cache->bstrength; + float grab_delta[3]; + + SculptProjectVector spvc; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (bstrength < 0.0f) { + negate_v3(grab_delta); + } + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + /* Optionally pinch while painting. */ + if (brush->crease_pinch_factor != 0.5f) { + sculpt_project_v3_cache_init(&spvc, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .spvc = &spvc, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); +} + +static void do_thumb_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *cono = data->cono; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], cono, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + float tmp[3], cono[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); + cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .cono = cono, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); +} + +static void do_rotate_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float angle = data->angle; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + float vec[3], rot[3][3]; + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + sub_v3_v3v3(vec, orig_data.co, ss->cache->location); + axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); + mul_v3_m3v3(proxy[vd.i], rot, vec); + add_v3_v3(proxy[vd.i], ss->cache->location); + sub_v3_v3(proxy[vd.i], orig_data.co); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1}; + const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .angle = angle, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); +} + +static void do_layer_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + Sculpt *sd = data->sd; + const Brush *brush = data->brush; + + const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + const float bstrength = ss->cache->bstrength; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + const int vi = vd.index; + float *disp_factor; + if (use_persistent_base) { + disp_factor = &ss->persistent_base[vi].disp; + } + else { + disp_factor = &ss->cache->layer_displacement_factor[vi]; + } + + /* When using persistent base, the layer brush (holding Control) invert mode resets the + * height of the layer to 0. This makes possible to clean edges of previously added layers + * on top of the base. */ + /* The main direction of the layers is inverted using the regular brush strength with the + * brush direction property. */ + if (use_persistent_base && ss->cache->invert) { + (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) * + ((*disp_factor) > 0.0f ? -1.0f : 1.0f); + } + else { + (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor)); + } + if (vd.mask) { + const float clamp_mask = 1.0f - *vd.mask; + *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask); + } + else { + *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f); + } + + float final_co[3]; + float normal[3]; + + if (use_persistent_base) { + SCULPT_vertex_persistent_normal_get(ss, vi, normal); + mul_v3_fl(normal, brush->height); + madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); + } + else { + normal_short_to_float_v3(normal, orig_data.no); + mul_v3_fl(normal, brush->height); + madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor); + } + + float vdisp[3]; + sub_v3_v3v3(vdisp, final_co, vd.co); + mul_v3_fl(vdisp, fabsf(fade)); + add_v3_v3v3(final_co, vd.co, vdisp); + + SCULPT_clip(sd, ss, vd.co, final_co); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (ss->cache->layer_displacement_factor == NULL) { + ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss), + "layer displacement factor"); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); +} + +static void do_inflate_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float val[3]; + + if (vd.fno) { + copy_v3_v3(val, vd.fno); + } + else { + normal_short_to_float_v3(val, vd.no); + } + + mul_v3_fl(val, fade * ss->cache->radius); + mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); +} + +static void do_nudge_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *cono = data->cono; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], cono, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + float tmp[3], cono[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); + cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .cono = cono, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Crease & Blob Brush + * \{ */ + +/** + * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' + */ +static void do_crease_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + SculptProjectVector *spvc = data->spvc; + const float flippedbstrength = data->flippedbstrength; + const float *offset = data->offset; + + PBVHVertexIter vd; + float(*proxy)[3]; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float val1[3]; + float val2[3]; + + /* First we pinch. */ + sub_v3_v3v3(val1, test.location, vd.co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(val1, val1, ss->cache->view_normal); + } + + mul_v3_fl(val1, fade * flippedbstrength); + + sculpt_project_v3(spvc, val1, val1); + + /* Then we draw. */ + mul_v3_v3fl(val2, offset, fade); + + add_v3_v3v3(proxy[vd.i], val1, val2); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + const Scene *scene = ss->cache->vc->scene; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + float bstrength = ss->cache->bstrength; + float flippedbstrength, crease_correction; + float brush_alpha; + + SculptProjectVector spvc; + + /* Offset with as much as possible factored in already. */ + mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* We divide out the squared alpha and multiply by the squared crease + * to give us the pinch strength. */ + crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor; + brush_alpha = BKE_brush_alpha_get(scene, brush); + if (brush_alpha > 0.0f) { + crease_correction /= brush_alpha * brush_alpha; + } + + /* We always want crease to pinch or blob to relax even when draw is negative. */ + flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength : + crease_correction * bstrength; + + if (brush->sculpt_tool == SCULPT_TOOL_BLOB) { + flippedbstrength *= -1.0f; + } + + /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single + * point. Without this we get a 'flat' surface surrounding the pinch. */ + sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .spvc = &spvc, + .offset = offset, + .flippedbstrength = flippedbstrength, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); +} + +static void do_pinch_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*stroke_xz)[3] = data->stroke_xz; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + float x_object_space[3]; + float z_object_space[3]; + copy_v3_v3(x_object_space, stroke_xz[0]); + copy_v3_v3(z_object_space, stroke_xz[1]); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float disp_center[3]; + float x_disp[3]; + float z_disp[3]; + /* Calculate displacement from the vertex to the brush center. */ + sub_v3_v3v3(disp_center, test.location, vd.co); + + /* Project the displacement into the X vector (aligned to the stroke). */ + mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space)); + + /* Project the displacement into the Z vector (aligned to the surface normal). */ + mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space)); + + /* Add the two projected vectors to calculate the final displacement. + * The Y component is removed. */ + add_v3_v3v3(disp_center, x_disp, z_disp); + + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal); + } + mul_v3_v3fl(proxy[vd.i], disp_center, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + float area_no[3]; + float area_co[3]; + + float mat[4][4]; + calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); + + /* delay the first daub because grab delta is not setup */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + /* Initialize `mat`. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1.0f; + normalize_m4(mat); + + float stroke_xz[2][3]; + normalize_v3_v3(stroke_xz[0], mat[0]); + normalize_v3_v3(stroke_xz[1], mat[2]); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .stroke_xz = stroke_xz, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); +} + +static void do_grab_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *grab_delta = data->grab_delta; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + if (grab_silhouette) { + float silhouette_test_dir[3]; + normalize_v3_v3(silhouette_test_dir, grab_delta); + if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) { + mul_v3_fl(silhouette_test_dir, -1.0f); + } + float vno[3]; + normal_short_to_float_v3(vno, orig_data.no); + fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f); + } + + mul_v3_v3fl(proxy[vd.i], grab_delta, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); +} + +static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *grab_delta = data->grab_delta; + const float *location = ss->cache->location; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + float dir; + if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) { + dir = 1.0f; + } + else { + dir = -1.0f; + } + + if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) { + int symm = ss->cache->mirror_symmetry_pass; + if (ELEM(symm, 1, 2, 4, 7)) { + dir = -dir; + } + } + + KelvinletParams params; + float force = len_v3(grab_delta) * dir * bstrength; + BKE_kelvinlet_init_params( + ¶ms, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + float final_disp[3]; + switch (brush->elastic_deform_type) { + case BRUSH_ELASTIC_DEFORM_GRAB: + BKE_kelvinlet_grab(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { + BKE_kelvinlet_grab_biscale(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + } + case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { + BKE_kelvinlet_grab_triscale(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + } + case BRUSH_ELASTIC_DEFORM_SCALE: + BKE_kelvinlet_scale( + final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); + break; + case BRUSH_ELASTIC_DEFORM_TWIST: + BKE_kelvinlet_twist( + final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); + break; + } + + if (vd.mask) { + mul_v3_fl(final_disp, 1.0f - *vd.mask); + } + + mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + + copy_v3_v3(proxy[vd.i], final_disp); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); +} +/** \} */ + +static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *offset = data->offset; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], offset, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + const float bstrength = ss->cache->bstrength; + + /* Offset with as much as possible factored in already. */ + float effective_normal[3]; + SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); + mul_v3_v3fl(offset, effective_normal, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise + * initialize before threads so they can do curve mapping. */ + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .offset = offset, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Topology Brush + * \{ */ + +static void do_topology_slide_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float current_disp[3]; + float current_disp_norm[3]; + float final_disp[3] = {0.0f, 0.0f, 0.0f}; + + switch (brush->slide_deform_type) { + case BRUSH_SLIDE_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SLIDE_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SLIDE_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { + madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_v3fl(proxy[vd.i], final_disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_relax_vertex(SculptSession *ss, + PBVHVertexIter *vd, + float factor, + bool filter_boundary_face_sets, + float *r_final_pos) +{ + float smooth_pos[3]; + float final_disp[3]; + float boundary_normal[3]; + int avg_count = 0; + int neighbor_count = 0; + zero_v3(smooth_pos); + zero_v3(boundary_normal); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + neighbor_count++; + if (!filter_boundary_face_sets || + (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { + + /* When the vertex to relax is boundary, use only connected boundary vertices for the average + * position. */ + if (is_boundary) { + if (!SCULPT_vertex_is_boundary(ss, ni.index)) { + continue; + } + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + avg_count++; + + /* Calculate a normal for the constraint plane using the edges of the boundary. */ + float to_neighbor[3]; + sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); + normalize_v3(to_neighbor); + add_v3_v3(boundary_normal, to_neighbor); + } + else { + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + avg_count++; + } + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + /* Don't modify corner vertices. */ + if (neighbor_count <= 2) { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + if (avg_count > 0) { + mul_v3_fl(smooth_pos, 1.0f / avg_count); + } + else { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + float plane[4]; + float smooth_closest_plane[3]; + float vno[3]; + + if (is_boundary && avg_count == 2) { + normalize_v3_v3(vno, boundary_normal); + } + else { + SCULPT_vertex_normal_get(ss, vd->index, vno); + } + + if (is_zero_v3(vno)) { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + plane_from_point_normal_v3(plane, vd->co, vno); + closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos); + sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co); + + mul_v3_fl(final_disp, factor); + add_v3_v3v3(r_final_pos, vd->co, final_disp); +} + +static void do_topology_relax_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + BKE_curvemapping_init(brush->curve); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + if (ss->cache->alt_smooth) { + SCULPT_boundary_info_ensure(ob); + for (int i = 0; i < 4; i++) { + BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); + } + } + else { + BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Multires Displacement Eraser Brush + * \{ */ + +static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float limit_co[3]; + float disp[3]; + SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + sub_v3_v3v3(disp, limit_co, vd.co); + mul_v3_v3fl(proxy[vd.i], disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Multires Displacement Smear Brush + * \{ */ + +static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_limit_surface_disp[3]; + + copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); + + switch (brush->smear_deform_type) { + case BRUSH_SMEAR_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SMEAR_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SMEAR_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + float weights_accum = 1.0f; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + float neighbor_limit_co[3]; + SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); + sub_v3_v3v3(vertex_disp, + ss->cache->limit_surface_co[ni.index], + ss->cache->limit_surface_co[vd.index]); + const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + + if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) { + continue; + } + + const float disp_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); + weights_accum += disp_interp; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); + + float new_co[3]; + add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); + interp_v3_v3v3(vd.co, vd.co, new_co, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_store_prev_disp_task_cb_ex( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + sub_v3_v3v3(ss->cache->prev_displacement[vd.index], + SCULPT_vertex_co_get(ss, vd.index), + ss->cache->limit_surface_co[vd.index]); + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + BKE_curvemapping_init(brush->curve); + + const int totvert = SCULPT_vertex_count_get(ss); + if (!ss->cache->prev_displacement) { + ss->cache->prev_displacement = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "prev displacement"); + ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); + for (int i = 0; i < totvert; i++) { + SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); + sub_v3_v3v3(ss->cache->prev_displacement[i], + SCULPT_vertex_co_get(ss, i), + ss->cache->limit_surface_co[i]); + } + } + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Topology Rake (Shared Utility) + * \{ */ + +static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + Sculpt *sd = data->sd; + const Brush *brush = data->brush; + + float direction[3]; + copy_v3_v3(direction, ss->cache->grab_delta_symmetry); + + float tmp[3]; + mul_v3_v3fl( + tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction)); + sub_v3_v3(direction, tmp); + normalize_v3(direction); + + /* Cancel if there's no grab data. */ + if (is_zero_v3(direction)) { + return; + } + + const float bstrength = clamp_f(data->strength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = + bstrength * + SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss->cache->pressure; + + float avg[3], val[3]; + + SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert); + + sub_v3_v3v3(val, avg, vd.co); + + madd_v3_v3v3fl(val, vd.co, val, fade); + + SCULPT_clip(sd, ss, vd.co, val); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_bmesh_topology_rake( + Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + const float strength = clamp_f(bstrength, 0.0f, 1.0f); + + /* Interactions increase both strength and quality. */ + const int iterations = 3; + + int iteration; + const int count = iterations * strength + 1; + const float factor = iterations * strength / count; + + for (iteration = 0; iteration <= count; iteration++) { + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .strength = factor, + }; + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + + BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Mask Brush + * \{ */ + +static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + const float fade = SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + + if (bstrength > 0.0f) { + (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); + } + else { + (*vd.mask) += fade * bstrength * (*vd.mask); + } + *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + BKE_pbvh_vertex_iter_end; + } +} + +void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); +} + +void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + switch ((BrushMaskTool)brush->mask_tool) { + case BRUSH_MASK_DRAW: + SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode); + break; + case BRUSH_MASK_SMOOTH: + SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true); + break; + } +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 9082408b8dd..f00b24d690a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -248,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode) { /* Find 3D view to pick from. */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my); - ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL; + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my}); + ARegion *region = (area) ? + BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) : + NULL; if (region == NULL) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 4dd2a786922..35ffb214185 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -29,13 +29,13 @@ #include "DNA_meshdata_types.h" #include "DNA_vec_types.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_gsqueue.h" #include "BLI_threads.h" -#include "BKE_paint.h" -#include "BKE_pbvh.h" - struct AutomaskingCache; struct KeyBlock; struct Object; @@ -300,6 +300,10 @@ void SCULPT_calc_brush_plane(struct Sculpt *sd, void SCULPT_calc_area_normal( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]); +void SCULPT_calc_area_normal_and_center( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]); +void SCULPT_calc_area_center( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]); int SCULPT_nearest_vertex_get(struct Sculpt *sd, struct Object *ob, @@ -1025,6 +1029,7 @@ typedef struct StrokeCache { float scale[3]; int flag; float clip_tolerance[3]; + float clip_mirror_mtx[4][4]; float initial_mouse[2]; /* Variants */ @@ -1506,3 +1511,115 @@ void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot); /* Dyntopo. */ void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot); + +/* sculpt_brushes.c */ + +float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache); + +void SCULPT_do_draw_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_do_fill_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_scrape_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_thumb_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_flatten_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_strips_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_snake_hook_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_thumb_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_rotate_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_layer_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_inflate_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_nudge_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_crease_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_pinch_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_grab_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_elastic_deform_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_draw_sharp_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_slide_relax_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_do_displacement_smear_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_mask_brush_draw(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_mask_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_bmesh_topology_rake(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + const int totnode, + float bstrength); + +/* end sculpt_brushes.c */ + +/* sculpt_ops.c */ +void SCULPT_OT_brush_stroke(struct wmOperatorType *ot); + +/* end sculpt_ops.c */ diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c new file mode 100644 index 00000000000..119d246a770 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -0,0 +1,1141 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2006 by Nicholas Bishop + * All rights reserved. + * Implements the Sculpt Mode tools + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_array.h" +#include "BLI_blenlib.h" +#include "BLI_dial_2d.h" +#include "BLI_ghash.h" +#include "BLI_gsqueue.h" +#include "BLI_hash.h" +#include "BLI_link_utils.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color_blend.h" +#include "BLI_memarena.h" +#include "BLI_rand.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" +#include "atomic_ops.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_attribute.h" +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_kelvinlet.h" +#include "BKE_key.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_mesh_fair.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_mirror.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_pbvh.h" +#include "BKE_pointcache.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subsurf.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "IMB_colormanagement.h" + +#include "GPU_batch.h" +#include "GPU_batch_presets.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_space_api.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */ + +static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (!ss) { + return OPERATOR_FINISHED; + } + SCULPT_vertex_random_access_ensure(ss); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); + + MEM_SAFE_FREE(ss->persistent_base); + + const int totvert = SCULPT_vertex_count_get(ss); + ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, + "layer persistent base"); + + for (int i = 0; i < totvert; i++) { + copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); + ss->persistent_base[i].disp = 0.0f; + } + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Set Persistent Base"; + ot->idname = "SCULPT_OT_set_persistent_base"; + ot->description = "Reset the copy of the mesh that is being sculpted on"; + + /* API callbacks. */ + ot->exec = sculpt_set_persistent_base_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/************************* SCULPT_OT_optimize *************************/ + +static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + SCULPT_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +/* The BVH gets less optimal more quickly with dynamic topology than + * regular sculpting. There is no doubt more clever stuff we can do to + * optimize it on the fly, but for now this gives the user a nicer way + * to recalculate it than toggling modes. */ +static void SCULPT_OT_optimize(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Rebuild BVH"; + ot->idname = "SCULPT_OT_optimize"; + ot->description = "Recalculate the sculpt BVH to improve performance"; + + /* API callbacks. */ + ot->exec = sculpt_optimize_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************* Dynamic topology symmetrize ********************/ + +static bool sculpt_no_multires_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) { + return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS; + } + return false; +} + +static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + PBVH *pbvh = ss->pbvh; + const float dist = RNA_float_get(op->ptr, "merge_tolerance"); + + if (!pbvh) { + return OPERATOR_CANCELLED; + } + + switch (BKE_pbvh_type(pbvh)) { + case PBVH_BMESH: + /* Dyntopo Symmetrize. */ + + /* To simplify undo for symmetrize, all BMesh elements are logged + * as deleted, then after symmetrize operation all BMesh elements + * are logged as added (as opposed to attempting to store just the + * parts that symmetrize modifies). */ + SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize"); + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); + BM_log_before_all_removed(ss->bm, ss->bm_log); + + BM_mesh_toolflags_set(ss->bm, true); + + /* Symmetrize and re-triangulate. */ + BMO_op_callf(ss->bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", + sd->symmetrize_direction, + dist, + true); + SCULPT_dynamic_topology_triangulate(ss->bm); + + /* Bisect operator flags edges (keep tags clean for edge queue). */ + BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); + + BM_mesh_toolflags_set(ss->bm, false); + + /* Finish undo. */ + BM_log_all_added(ss->bm, ss->bm_log); + SCULPT_undo_push_end(); + + break; + case PBVH_FACES: + /* Mesh Symmetrize. */ + ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); + Mesh *mesh = ob->data; + + BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist); + + ED_sculpt_undo_geometry_end(ob); + BKE_mesh_calc_normals(ob->data); + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + + break; + case PBVH_GRIDS: + return OPERATOR_CANCELLED; + } + + /* Redraw. */ + SCULPT_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_symmetrize(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Symmetrize"; + ot->idname = "SCULPT_OT_symmetrize"; + ot->description = "Symmetrize the topology modifications"; + + /* API callbacks. */ + ot->exec = sculpt_symmetrize_exec; + ot->poll = sculpt_no_multires_poll; + + RNA_def_float(ot->srna, + "merge_tolerance", + 0.001f, + 0.0f, + FLT_MAX, + "Merge Distance", + "Distance within which symmetrical vertices are merged", + 0.0f, + 1.0f); +} + +/**** Toggle operator for turning sculpt mode on or off ****/ + +static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + /* Create persistent sculpt mode data. */ + BKE_sculpt_toolsettings_data_ensure(scene); + + /* Create sculpt mode session data. */ + if (ob->sculpt != NULL) { + BKE_sculptsession_free(ob); + } + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + ob->sculpt->mode_type = OB_MODE_SCULPT; + + BKE_sculpt_ensure_orig_mesh_data(scene, ob); + + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + + /* This function expects a fully evaluated depsgraph. */ + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); + + /* Here we can detect geometry that was just added to Sculpt Mode as it has the + * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ + /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not + * initialized, which is used is some operators that modify the mesh topology to perform certain + * actions in the new polys. After these operations are finished, all polys should have a valid + * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility + * correctly. */ + /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new + * objects, like moving the transform pivot position to the new area or masking existing + * geometry. */ + SculptSession *ss = ob->sculpt; + const int new_face_set = SCULPT_face_set_next_available_get(ss); + for (int i = 0; i < ss->totfaces; i++) { + if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { + ss->face_sets[i] = new_face_set; + } + } +} + +void ED_object_sculptmode_enter_ex(Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + const bool force_dyntopo, + ReportList *reports) +{ + const int mode_flag = OB_MODE_SCULPT; + Mesh *me = BKE_mesh_from_object(ob); + + /* Enter sculpt mode. */ + ob->mode |= mode_flag; + + sculpt_init_session(bmain, depsgraph, scene, ob); + + if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && + fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) { + BKE_report( + reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); + } + else if (is_negative_m4(ob->obmat)) { + BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); + } + + Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); + BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); + + paint_cursor_start(paint, SCULPT_mode_poll_view3d); + + /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, + * As long as no data was added that is not supported. */ + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + + const char *message_unsupported = NULL; + if (me->totloop != me->totpoly * 3) { + message_unsupported = TIP_("non-triangle face"); + } + else if (mmd != NULL) { + message_unsupported = TIP_("multi-res modifier"); + } + else { + enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob); + if (flag == 0) { + /* pass */ + } + else if (flag & DYNTOPO_WARN_VDATA) { + message_unsupported = TIP_("vertex data"); + } + else if (flag & DYNTOPO_WARN_EDATA) { + message_unsupported = TIP_("edge data"); + } + else if (flag & DYNTOPO_WARN_LDATA) { + message_unsupported = TIP_("face data"); + } + else if (flag & DYNTOPO_WARN_MODIFIER) { + message_unsupported = TIP_("constructive modifier"); + } + else { + BLI_assert(0); + } + } + + if ((message_unsupported == NULL) || force_dyntopo) { + /* Needed because we may be entering this mode before the undo system loads. */ + wmWindowManager *wm = bmain->wm.first; + bool has_undo = wm->undo_stack != NULL; + /* Undo push is needed to prevent memory leak. */ + if (has_undo) { + SCULPT_undo_push_begin(ob, "Dynamic topology enable"); + } + SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); + if (has_undo) { + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + SCULPT_undo_push_end(); + } + } + else { + BKE_reportf( + reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + } + } + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); +} + +void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports); +} + +void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + const int mode_flag = OB_MODE_SCULPT; + Mesh *me = BKE_mesh_from_object(ob); + + multires_flush_sculpt_updates(ob); + + /* Not needed for now. */ +#if 0 + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); +#endif + + /* Always for now, so leaving sculpt mode always ensures scene is in + * a consistent state. */ + if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + /* Dynamic topology must be disabled before exiting sculpt + * mode to ensure the undo stack stays in a consistent + * state. */ + sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob); + + /* Store so we know to re-enable when entering sculpt mode. */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + } + + /* Leave sculpt mode. */ + ob->mode &= ~mode_flag; + + BKE_sculptsession_free(ob); + + paint_cursor_delete_textures(); + + /* Never leave derived meshes behind. */ + BKE_object_free_derived_caches(ob); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); +} + +void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); +} + +static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) +{ + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + const int mode_flag = OB_MODE_SCULPT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (is_mode_set) { + ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); + } + else { + if (depsgraph) { + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + } + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports); + BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); + + if (ob->mode & mode_flag) { + Mesh *me = ob->data; + /* Dyntopo adds its own undo step. */ + if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { + /* Without this the memfile undo step is used, + * while it works it causes lag when undoing the first undo step, see T71564. */ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->op_undo_depth <= 1) { + SCULPT_undo_push_begin(ob, op->type->name); + } + } + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); + + WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + + WM_toolsystem_update_from_context_view3d(C); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Sculpt Mode"; + ot->idname = "SCULPT_OT_sculptmode_toggle"; + ot->description = "Toggle sculpt mode in 3D view"; + + /* API callbacks. */ + ot->exec = sculpt_mode_toggle_exec; + ot->poll = ED_operator_object_active_editable_mesh; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + + ss->preview_vert_index_count = 0; + int totpoints = 0; + + /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ + if (!ss->pbvh) { + return; + } + + if (!ss->deform_modifiers_active) { + return; + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + return; + } + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + if (!ss->pmap) { + return; + } + + float brush_co[3]; + copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); + + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); + + /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ + const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; + + if (ss->preview_vert_index_list == NULL) { + ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); + } + + GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); + int active_v = SCULPT_active_vertex_get(ss); + BLI_gsqueue_push(not_visited_vertices, &active_v); + + while (!BLI_gsqueue_is_empty(not_visited_vertices)) { + int from_v; + BLI_gsqueue_pop(not_visited_vertices, &from_v); + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { + if (totpoints + (ni.size * 2) < max_preview_vertices) { + int to_v = ni.index; + ss->preview_vert_index_list[totpoints] = from_v; + totpoints++; + ss->preview_vert_index_list[totpoints] = to_v; + totpoints++; + if (BLI_BITMAP_TEST(visited_vertices, to_v)) { + continue; + } + BLI_BITMAP_ENABLE(visited_vertices, to_v); + const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); + if (len_squared_v3v3(brush_co, co) < radius * radius) { + BLI_gsqueue_push(not_visited_vertices, &to_v); + } + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } + + BLI_gsqueue_free(not_visited_vertices); + + MEM_freeN(visited_vertices); + + ss->preview_vert_index_count = totpoints; +} + +static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + float srgb_color[4]; + linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color); + loopcols[loop_index].r = (char)(srgb_color[0] * 255); + loopcols[loop_index].g = (char)(srgb_color[1] * 255); + loopcols[loop_index].b = (char)(srgb_color[2] * 255); + loopcols[loop_index].a = (char)(srgb_color[3] * 255); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sculpt Vertex Color to Vertex Color"; + ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; + ot->idname = "SCULPT_OT_vertex_to_loop_colors"; + + /* api callbacks */ + ot->poll = SCULPT_vertex_colors_poll; + ot->exec = vertex_to_loop_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); + vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); + vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); + vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); + srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color to Sculpt Vertex Color"; + ot->description = "Copy the active loop color layer to the vertex color"; + ot->idname = "SCULPT_OT_loop_to_vertex_colors"; + + /* api callbacks */ + ot->poll = SCULPT_vertex_colors_poll; + ot->exec = loop_to_vertex_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int sculpt_sample_color_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(e)) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + int active_vertex = SCULPT_active_vertex_get(ss); + const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex); + if (!active_vertex_color) { + return OPERATOR_CANCELLED; + } + + float color_srgb[3]; + copy_v3_v3(color_srgb, active_vertex_color); + IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb); + BKE_brush_color_set(scene, brush, color_srgb); + + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_sample_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sample Color"; + ot->idname = "SCULPT_OT_sample_color"; + ot->description = "Sample the vertex color of the active vertex"; + + /* api callbacks */ + ot->invoke = sculpt_sample_color_invoke; + ot->poll = SCULPT_vertex_colors_poll; + + ot->flag = OPTYPE_REGISTER; +} + +/** + * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the + * mask based on the difference between two colors (the active color and the color of any other + * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active + * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer + * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between + * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going + * to be. + */ +#define MASK_BY_COLOR_SLOPE 0.25f + +static float sculpt_mask_by_color_delta_get(const float *color_a, + const float *color_b, + const float threshold, + const bool invert) +{ + float len = len_v3v3(color_a, color_b); + /* Normalize len to the (0, 1) range. */ + len = len / M_SQRT3; + + if (len < threshold - MASK_BY_COLOR_SLOPE) { + len = 1.0f; + } + else if (len >= threshold) { + len = 0.0f; + } + else { + len = (-len + threshold) / MASK_BY_COLOR_SLOPE; + } + + if (invert) { + return 1.0f - len; + } + return len; +} + +static float sculpt_mask_by_color_final_mask_get(const float current_mask, + const float new_mask, + const bool invert, + const bool preserve_mask) +{ + if (preserve_mask) { + if (invert) { + return min_ff(current_mask, new_mask); + } + return max_ff(current_mask, new_mask); + } + return new_mask; +} + +typedef struct MaskByColorContiguousFloodFillData { + float threshold; + bool invert; + float *new_mask; + float initial_color[3]; +} MaskByColorContiguousFloodFillData; + +static void do_mask_by_color_contiguous_update_nodes_cb( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); + bool update_node = false; + + const bool invert = data->mask_by_color_invert; + const bool preserve_mask = data->mask_by_color_preserve_mask; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + const float current_mask = *vd.mask; + const float new_mask = data->mask_by_color_floodfill[vd.index]; + *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); + if (current_mask == *vd.mask) { + continue; + } + update_node = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (update_node) { + BKE_pbvh_node_mark_redraw(data->nodes[n]); + } +} + +static bool sculpt_mask_by_color_contiguous_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) +{ + MaskByColorContiguousFloodFillData *data = userdata; + const float *current_color = SCULPT_vertex_color_get(ss, to_v); + float new_vertex_mask = sculpt_mask_by_color_delta_get( + current_color, data->initial_color, data->threshold, data->invert); + data->new_mask[to_v] = new_vertex_mask; + + if (is_duplicate) { + data->new_mask[to_v] = data->new_mask[from_v]; + } + + float len = len_v3v3(current_color, data->initial_color); + len = len / M_SQRT3; + return len <= data->threshold; +} + +static void sculpt_mask_by_color_contiguous(Object *object, + const int vertex, + const float threshold, + const bool invert, + const bool preserve_mask) +{ + SculptSession *ss = object->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask"); + + if (invert) { + for (int i = 0; i < totvert; i++) { + new_mask[i] = 1.0f; + } + } + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial(&flood, vertex); + + MaskByColorContiguousFloodFillData ffd; + ffd.threshold = threshold; + ffd.invert = invert; + ffd.new_mask = new_mask; + copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex)); + + SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd); + SCULPT_floodfill_free(&flood); + + int totnode; + PBVHNode **nodes; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + SculptThreadedTaskData data = { + .ob = object, + .nodes = nodes, + .mask_by_color_floodfill = new_mask, + .mask_by_color_vertex = vertex, + .mask_by_color_threshold = threshold, + .mask_by_color_invert = invert, + .mask_by_color_preserve_mask = preserve_mask, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings); + + MEM_SAFE_FREE(nodes); + + MEM_freeN(new_mask); +} + +static void do_mask_by_color_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); + bool update_node = false; + + const float threshold = data->mask_by_color_threshold; + const bool invert = data->mask_by_color_invert; + const bool preserve_mask = data->mask_by_color_preserve_mask; + const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + const float current_mask = *vd.mask; + const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert); + *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); + + if (current_mask == *vd.mask) { + continue; + } + update_node = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (update_node) { + BKE_pbvh_node_mark_redraw(data->nodes[n]); + } +} + +static void sculpt_mask_by_color_full_mesh(Object *object, + const int vertex, + const float threshold, + const bool invert, + const bool preserve_mask) +{ + SculptSession *ss = object->sculpt; + + int totnode; + PBVHNode **nodes; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + SculptThreadedTaskData data = { + .ob = object, + .nodes = nodes, + .mask_by_color_vertex = vertex, + .mask_by_color_threshold = threshold, + .mask_by_color_invert = invert, + .mask_by_color_preserve_mask = preserve_mask, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings); + + MEM_SAFE_FREE(nodes); +} + +static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + /* Color data is not available in Multires. */ + if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { + return OPERATOR_CANCELLED; + } + + if (!ss->vcol) { + return OPERATOR_CANCELLED; + } + + SCULPT_vertex_random_access_ensure(ss); + + /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, + * so it needs to be updated here. */ + SculptCursorGeometryInfo sgi; + float mouse[2]; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + + SCULPT_undo_push_begin(ob, "Mask by color"); + + const int active_vertex = SCULPT_active_vertex_get(ss); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool invert = RNA_boolean_get(op->ptr, "invert"); + const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); + + if (RNA_boolean_get(op->ptr, "contiguous")) { + sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); + } + else { + sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); + } + + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + SCULPT_undo_push_end(); + + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_mask_by_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Mask by Color"; + ot->idname = "SCULPT_OT_mask_by_color"; + ot->description = "Creates a mask based on the sculpt vertex colors"; + + /* api callbacks */ + ot->invoke = sculpt_mask_by_color_invoke; + ot->poll = SCULPT_vertex_colors_poll; + + ot->flag = OPTYPE_REGISTER; + + ot->prop = RNA_def_boolean( + ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas"); + + ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask"); + ot->prop = RNA_def_boolean( + ot->srna, + "preserve_previous_mask", + false, + "Preserve Previous Mask", + "Preserve the previous mask and add or subtract the new one generated by the colors"); + + RNA_def_float(ot->srna, + "threshold", + 0.35f, + 0.0f, + 1.0f, + "Threshold", + "How much changes in color affect the mask generation", + 0.0f, + 1.0f); +} + +void ED_operatortypes_sculpt(void) +{ + WM_operatortype_append(SCULPT_OT_brush_stroke); + WM_operatortype_append(SCULPT_OT_sculptmode_toggle); + WM_operatortype_append(SCULPT_OT_set_persistent_base); + WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); + WM_operatortype_append(SCULPT_OT_optimize); + WM_operatortype_append(SCULPT_OT_symmetrize); + WM_operatortype_append(SCULPT_OT_detail_flood_fill); + WM_operatortype_append(SCULPT_OT_sample_detail_size); + WM_operatortype_append(SCULPT_OT_set_detail_size); + WM_operatortype_append(SCULPT_OT_mesh_filter); + WM_operatortype_append(SCULPT_OT_mask_filter); + WM_operatortype_append(SCULPT_OT_dirty_mask); + WM_operatortype_append(SCULPT_OT_mask_expand); + WM_operatortype_append(SCULPT_OT_set_pivot_position); + WM_operatortype_append(SCULPT_OT_face_sets_create); + WM_operatortype_append(SCULPT_OT_face_sets_change_visibility); + WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors); + WM_operatortype_append(SCULPT_OT_face_sets_init); + WM_operatortype_append(SCULPT_OT_cloth_filter); + WM_operatortype_append(SCULPT_OT_face_sets_edit); + WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture); + WM_operatortype_append(SCULPT_OT_face_set_box_gesture); + WM_operatortype_append(SCULPT_OT_trim_box_gesture); + WM_operatortype_append(SCULPT_OT_trim_lasso_gesture); + WM_operatortype_append(SCULPT_OT_project_line_gesture); + + WM_operatortype_append(SCULPT_OT_sample_color); + WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); + WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); + WM_operatortype_append(SCULPT_OT_color_filter); + WM_operatortype_append(SCULPT_OT_mask_by_color); + WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); + WM_operatortype_append(SCULPT_OT_mask_init); + + WM_operatortype_append(SCULPT_OT_expand); +} diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 91083fa9682..847cba32c69 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -1079,6 +1079,9 @@ static void graph_region_draw(const bContext *C, ARegion *region) /* time-scrubbing */ ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); + /* current frame indicator */ + ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS); + /* scrollers */ UI_view2d_scrollers_draw(v2d, NULL); @@ -1126,6 +1129,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region) /* time-scrubbing */ ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); + /* current frame indicator */ + ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS); + /* scrollers */ UI_view2d_scrollers_draw(v2d, NULL); } diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 86c4b78dea4..f6c449a0584 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -679,7 +679,7 @@ using namespace blender::ed::asset_browser; FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings() { - AssetCatalogFilterSettings *filter_settings = OBJECT_GUARDED_NEW(AssetCatalogFilterSettings); + AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__); return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings); } @@ -688,7 +688,8 @@ void file_delete_asset_catalog_filter_settings( { AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>( filter_settings_handle); - OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings); + MEM_delete(*filter_settings); + *filter_settings = nullptr; } bool file_set_asset_catalog_filter_settings( diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 8178e54e023..a1472a2c1b3 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2624,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg matches = file_select_match(sfile, params->file, matched_file); /* *After* file_select_match! */ - BLI_filename_make_safe(params->file); + const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0; + BLI_filename_make_safe_ex(params->file, allow_tokens); if (matches) { /* replace the pattern (or filename that the user typed in, diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e3ac5840da3..f9783d1b19f 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -275,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) { params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0; } + if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) { + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0; + } if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) { params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0; } @@ -318,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0; } + if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) { + params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0; + } + if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) { params->display = RNA_property_enum_get(op->ptr, prop); } diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 4db1eb5214e..286580b5629 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -126,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot); void GRAPH_OT_duplicate(struct wmOperatorType *ot); void GRAPH_OT_delete(struct wmOperatorType *ot); void GRAPH_OT_clean(struct wmOperatorType *ot); +void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot); +void GRAPH_OT_breakdown(struct wmOperatorType *ot); void GRAPH_OT_decimate(struct wmOperatorType *ot); void GRAPH_OT_sample(struct wmOperatorType *ot); void GRAPH_OT_bake(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index ecafc75fc06..fe4cffcb3b8 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -470,6 +470,8 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_smooth); WM_operatortype_append(GRAPH_OT_clean); WM_operatortype_append(GRAPH_OT_decimate); + WM_operatortype_append(GRAPH_OT_blend_to_neighbor); + WM_operatortype_append(GRAPH_OT_breakdown); WM_operatortype_append(GRAPH_OT_euler_filter); WM_operatortype_append(GRAPH_OT_delete); WM_operatortype_append(GRAPH_OT_duplicate); diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index 0bb5e8b8d9c..733313dd06b 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -313,8 +313,7 @@ static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event ED_slider_init(gso->slider, event); if (gso->bezt_arr_list.first == NULL) { - WM_report(RPT_WARNING, - "Fcurve Slider: Can't work on baked channels. Unbake them and try again."); + WM_report(RPT_ERROR, "Cannot find keys to operate on."); graph_slider_exit(C, op); return OPERATOR_CANCELLED; } @@ -552,3 +551,256 @@ void GRAPH_OT_decimate(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend To Neighbor Operator + * \{ */ + +static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor) +{ + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + bAnimListElem *ale; + + /* Loop through filtered data and blend keys. */ + + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + blend_to_neighbor_fcurve_segment(fcu, segment, factor); + } + BLI_freelistN(&segments); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso) +{ + char status_str[UI_MAX_DRAW_STR]; + char mode_str[32]; + char slider_string[UI_MAX_DRAW_STR]; + + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); + + strcpy(mode_str, TIP_("Blend To Neighbor")); + + if (hasNumInput(&gso->num)) { + char str_ofs[NUM_STR_REP_LEN]; + + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string); + } + + ED_workspace_status_text(C, status_str); +} + +static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op) +{ + tGraphSliderOp *gso = op->customdata; + + blend_to_neighbor_draw_status_header(C, gso); + + /* Reset keyframe data to the state at invoke. */ + reset_bezts(gso); + + const float factor = ED_slider_factor_get(gso->slider); + RNA_property_float_set(op->ptr, gso->factor_prop, factor); + blend_to_neighbor_graph_keys(&gso->ac, factor); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + +static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const int invoke_result = graph_slider_invoke(C, op, event); + + if (invoke_result == OPERATOR_CANCELLED) { + return invoke_result; + } + + tGraphSliderOp *gso = op->customdata; + gso->modal_update = blend_to_neighbor_modal_update; + gso->factor_prop = RNA_struct_find_property(op->ptr, "factor"); + blend_to_neighbor_draw_status_header(C, gso); + + return invoke_result; +} + +static int blend_to_neighbor_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + blend_to_neighbor_graph_keys(&ac, factor); + + /* Set notifier that keyframes have changed. */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Blend To Neighbor"; + ot->idname = "GRAPH_OT_blend_to_neighbor"; + ot->description = "Blend selected keyframes to their left or right neighbor"; + + /* API callbacks. */ + ot->invoke = blend_to_neighbor_invoke; + ot->modal = graph_slider_modal; + ot->exec = blend_to_neighbor_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_factor(ot->srna, + "factor", + 1.0f / 3.0f, + -FLT_MAX, + FLT_MAX, + "Blend", + "The blend factor with 0.5 being the current frame", + 0.0f, + 1.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Breakdown Operator + * \{ */ + +static void breakdown_graph_keys(bAnimContext *ac, float factor) +{ + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + bAnimListElem *ale; + + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + breakdown_fcurve_segment(fcu, segment, factor); + } + BLI_freelistN(&segments); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso) +{ + char status_str[UI_MAX_DRAW_STR]; + char mode_str[32]; + char slider_string[UI_MAX_DRAW_STR]; + + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); + + strcpy(mode_str, TIP_("Breakdown")); + + if (hasNumInput(&gso->num)) { + char str_ofs[NUM_STR_REP_LEN]; + + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string); + } + + ED_workspace_status_text(C, status_str); +} + +static void breakdown_modal_update(bContext *C, wmOperator *op) +{ + tGraphSliderOp *gso = op->customdata; + + breakdown_draw_status_header(C, gso); + + /* Reset keyframe data to the state at invoke. */ + reset_bezts(gso); + breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider)); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + +static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const int invoke_result = graph_slider_invoke(C, op, event); + + if (invoke_result == OPERATOR_CANCELLED) { + return invoke_result; + } + + tGraphSliderOp *gso = op->customdata; + gso->modal_update = breakdown_modal_update; + breakdown_draw_status_header(C, gso); + + return invoke_result; +} + +static int breakdown_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + breakdown_graph_keys(&ac, factor); + + /* Set notifier that keyframes have changed. */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_breakdown(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Breakdown"; + ot->idname = "GRAPH_OT_breakdown"; + ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys"; + + /* API callbacks. */ + ot->invoke = breakdown_invoke; + ot->modal = graph_slider_modal; + ot->exec = breakdown_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_factor(ot->srna, + "factor", + 1.0f / 3.0f, + -FLT_MAX, + FLT_MAX, + "Factor", + "Favor either the left or the right key", + 0.0f, + 1.0f); +} + +/** \} */ diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index f9160774c41..23d07c9b45b 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1499,6 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op) } } +static void image_operator_prop_allow_tokens(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens"); + RNA_def_property_flag(prop, PROP_HIDDEN); +} + void IMAGE_OT_open(wmOperatorType *ot) { /* identifiers */ @@ -1516,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ + image_operator_prop_allow_tokens(ot); WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, @@ -1767,7 +1775,13 @@ static int image_save_options_init(Main *bmain, opts->im_format.views_format = ima->views_format; } - BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath)); + if (ima->source == IMA_SRC_TILED) { + BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath)); + BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); + } + else { + BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath)); + } /* sanitize all settings */ @@ -1804,14 +1818,10 @@ static int image_save_options_init(Main *bmain, BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain)); } - /* append UDIM numbering if not present */ - if (ima->source == IMA_SRC_TILED) { - char udim[6]; - ImageTile *tile = ima->tiles.first; - BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number); - + /* append UDIM marker if not present */ + if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) { int len = strlen(opts->filepath); - STR_CONCAT(opts->filepath, len, udim); + STR_CONCAT(opts->filepath, len, ".<UDIM>"); } } @@ -2070,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot) "Copy", "Create a new image file without modifying the current image in blender"); + image_operator_prop_allow_tokens(ot); WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, @@ -2584,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op) else if (sima) { ED_space_image_set(bmain, sima, ima, false); } + else { + /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to + * anything. ref. T94599. */ + id_us_min(&ima->id); + } BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE); diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 87bff913ff2..84b85b396fe 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b) return 0; } -/* - * Checks whether the given filepath refers to a UDIM texture. - * If yes, the range from 1001 to the highest tile is returned, otherwise 0. - * - * If the result is positive, the filepath will be overwritten with that of - * the 1001 tile. - * - * udim_tiles may get filled even if the result ultimately is false! - */ -static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range) -{ - char filename[FILE_MAX], dirname[FILE_MAXDIR]; - BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); - - ushort digits; - char base_head[FILE_MAX], base_tail[FILE_MAX]; - int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits); - - if (id < 1001 || id > IMA_UDIM_MAX) { - return false; - } - - bool is_udim = true; - int min_udim = IMA_UDIM_MAX + 1; - int max_udim = 0; - - struct direntry *dir; - uint totfile = BLI_filelist_dir_contents(dirname, &dir); - for (int i = 0; i < totfile; i++) { - if (!(dir[i].type & S_IFREG)) { - continue; - } - char head[FILE_MAX], tail[FILE_MAX]; - id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits); - - if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) || - !(STREQLEN(base_tail, tail, FILE_MAX))) { - continue; - } - - if (id < 1001 || id > IMA_UDIM_MAX) { - is_udim = false; - break; - } - - BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id))); - min_udim = min_ii(min_udim, id); - max_udim = max_ii(max_udim, id); - } - BLI_filelist_free(dir, totfile); - - if (is_udim && min_udim <= IMA_UDIM_MAX) { - char primary_filename[FILE_MAX]; - BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim); - BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename); - - *udim_start = min_udim; - *udim_range = max_udim - min_udim + 1; - return true; - } - return false; -} - /** * From a list of frames, compute the start (offset) and length of the sequence - * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well. + * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well. */ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim) { /* UDIM */ if (detect_udim) { int udim_start, udim_range; - bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range); + bool result = BKE_image_get_tile_info( + range->filepath, &range->udim_tiles, &udim_start, &udim_range); if (result) { range->offset = udim_start; diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index bcf26743030..005ae0214cd 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -43,6 +43,7 @@ #include "BLT_translation.h" +#include "BKE_action.h" #include "BKE_armature.h" #include "BKE_blender_version.h" #include "BKE_context.h" @@ -351,7 +352,7 @@ static void stats_object_pose(const Object *ob, SceneStats *stats) LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { stats->totbone++; if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { - if (pchan->bone->layer & arm->layer) { + if (BKE_pose_is_layer_visible(arm, pchan)) { stats->totbonesel++; } } diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index bbfd886ce56..5bb5320655b 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -36,6 +36,7 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_scene.h" #include "BKE_tracking.h" @@ -135,24 +136,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { -#if 0 - /* XXX no context access here. */ - bNode *node = (bNode*)ptr->data; - CurveMapping *cumap = node->storage; - - if (cumap) { - cumap->flag |= CUMA_DRAW_CFRA; - if (node->custom1 < node->custom2) { - cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1); - } - } -#endif - uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); - uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); - uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); + uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -1558,7 +1546,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp) @@ -1652,12 +1641,6 @@ void ED_node_init_butfuncs() node_template_properties_update(ntype); } NODE_TYPES_END; - - /* tree type icons */ - ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING; - ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL; - ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE; - ntreeType_Geometry->ui_icon = ICON_NODETREE; } void ED_init_custom_node_type(bNodeType *UNUSED(ntype)) diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc index e1ba36e81c0..45126e9cee0 100644 --- a/source/blender/editors/space_node/link_drag_search.cc +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -29,6 +29,8 @@ #include "WM_api.h" +#include "ED_node.h" + #include "node_intern.hh" using blender::nodes::SocketLinkOperation; @@ -77,7 +79,7 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams ¶ms) bNode &group_input = params.add_node("NodeGroupInput"); /* This is necessary to create the new sockets in the other input nodes. */ - ntreeUpdateTree(CTX_data_main(¶ms.C), ¶ms.node_tree); + ED_node_tree_propagate_change(¶ms.C, CTX_data_main(¶ms.C), ¶ms.node_tree); /* Hide the new input in all other group input nodes, to avoid making them taller. */ LISTBASE_FOREACH (bNode *, node, ¶ms.node_tree.nodes) { @@ -103,6 +105,26 @@ static void add_group_input_node_fn(nodes::LinkSearchOpParams ¶ms) nodeAddLink(¶ms.node_tree, &group_input, socket, ¶ms.node, ¶ms.socket); } +static void add_existing_group_input_fn(nodes::LinkSearchOpParams ¶ms, + const bNodeSocket &interface_socket) +{ + const int group_input_index = BLI_findindex(¶ms.node_tree.inputs, &interface_socket); + bNode &group_input = params.add_node("NodeGroupInput"); + + LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) { + socket->flag |= SOCK_HIDDEN; + } + + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index); + if (socket == nullptr) { + /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */ + return; + } + + socket->flag &= ~SOCK_HIDDEN; + nodeAddLink(¶ms.node_tree, &group_input, socket, ¶ms.node, ¶ms.socket); +} + /** * Call the callback to gather compatible socket connections for all node types, and the operations * that will actually make the connections. Also add some custom operations like connecting a group @@ -134,6 +156,22 @@ static void gather_socket_link_operations(bNodeTree &node_tree, if (is_node_group && socket.in_out == SOCK_IN) { search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn}); + + int weight = -1; + LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) { + eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type; + eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type; + if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) { + continue; + } + search_link_ops.append( + {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name, + [interface_socket](nodes::LinkSearchOpParams ¶ms) { + add_existing_group_input_fn(params, *interface_socket); + }, + weight}); + weight--; + } } } @@ -203,9 +241,7 @@ static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) /* Ideally it would be possible to tag the node tree in some way so it updates only after the * translate operation is finished, but normally moving nodes around doesn't cause updates. */ - ntreeUpdateTree(&bmain, snode.edittree); - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, &bmain, snode.edittree); /* Start translation operator with the new node. */ wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true); @@ -288,4 +324,4 @@ void invoke_node_link_drag_add_menu(bContext &C, UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false); } -} // namespace blender::ed::space_node
\ No newline at end of file +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index c6a5e8e68c0..0aa9cd5511a 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -36,6 +36,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_texture.h" @@ -83,15 +84,8 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx nodeSetSelected(node, true); - ntreeUpdateTree(&bmain, snode.edittree); ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); - - snode_update(snode, node); - - if (snode.nodetree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(snode.edittree); - } - + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); return node; } @@ -136,7 +130,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb, { bNodeSocketLink *socklink, *prev; - socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link"); + socklink = MEM_cnew<bNodeSocketLink>("socket link"); socklink->sock = sock; socklink->link = link; copy_v2_v2(socklink->point, point); @@ -281,10 +275,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) BLI_freelistN(&input_links); /* always last */ - ntreeUpdateTree(CTX_data_main(C), &ntree); - snode_notify(*C, snode); - snode_dag_update(*C, snode); - + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); return OPERATOR_FINISHED; } @@ -383,14 +374,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op) group_node->id = &node_group->id; id_us_plus(group_node->id); + BKE_ntree_update_tag_node_property(snode->edittree, group_node); nodeSetActive(ntree, group_node); - ntreeUpdateTree(bmain, node_group); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } @@ -479,12 +466,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) id_us_plus(&object->id); nodeSetActive(ntree, object_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - - ED_node_tag_update_nodetree(bmain, ntree, object_node); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -587,14 +569,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op) id_us_plus(&texture->id); nodeSetActive(ntree, texture_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); - ED_node_tag_update_nodetree(bmain, ntree, texture_node); - return OPERATOR_FINISHED; } @@ -701,14 +678,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) id_us_plus(&collection->id); nodeSetActive(ntree, collection_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); - ED_node_tag_update_nodetree(bmain, ntree, collection_node); - return OPERATOR_FINISHED; } @@ -834,8 +806,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); } - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, snode.edittree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -937,8 +908,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) node->id = mask; id_us_plus(mask); - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, snode.edittree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index d68f16f6197..2d3c42b16d1 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -176,35 +176,6 @@ void ED_node_tag_update_id(ID *id) } } -void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node) -{ - if (!ntree) { - return; - } - - bool do_tag_update = true; - if (node != nullptr) { - if (!node_connected_to_output(*bmain, *ntree, *node)) { - do_tag_update = false; - } - } - - /* Look through all datablocks to support groups. */ - if (do_tag_update) { - FOREACH_NODETREE_BEGIN (bmain, tntree, id) { - /* Check if nodetree uses the group. */ - if (ntreeHasTree(tntree, ntree)) { - ED_node_tag_update_id(id); - } - } - FOREACH_NODETREE_END; - } - - if (ntree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(ntree); - } -} - static bool compare_nodes(const bNode *a, const bNode *b) { /* These tell if either the node or any of the parent nodes is selected. @@ -365,6 +336,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, PointerRNA nodeptr; RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr); + const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS); + const bool inputs_first = node.inputs.first && + !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options); + /* Get "global" coordinates. */ float2 loc = node_to_view(node, float2(0)); /* Round the node origin because text contents are always pixel-aligned. */ @@ -377,7 +352,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, dy -= NODE_DY; /* Add a little bit of padding above the top socket. */ - if (node.outputs.first || node.inputs.first) { + if (node.outputs.first || inputs_first) { dy -= NODE_DYS / 2; } @@ -478,7 +453,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, } /* Buttons rect? */ - if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) { + if (node_options) { dy -= NODE_DYS / 2; uiLayout *layout = UI_block_layout(&block, @@ -2405,7 +2380,6 @@ static void node_update_nodetree(const bContext &C, { /* Make sure socket "used" tags are correct, for displaying value buttons. */ SpaceNode *snode = CTX_wm_space_node(&C); - ntreeTagUsedSockets(&ntree); count_multi_input_socket_links(ntree, *snode); @@ -2414,9 +2388,11 @@ static void node_update_nodetree(const bContext &C, bNode &node = *nodes[i]; uiBlock &block = *blocks[i]; if (node.type == NODE_FRAME) { - frame_node_prepare_for_draw(node, nodes); + /* Frame sizes are calculated after all other nodes have calculating their #totr. */ + continue; } - else if (node.type == NODE_REROUTE) { + + if (node.type == NODE_REROUTE) { reroute_node_prepare_for_draw(node); } else { @@ -2428,6 +2404,13 @@ static void node_update_nodetree(const bContext &C, } } } + + /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */ + for (const int i : nodes.index_range()) { + if (nodes[i]->type == NODE_FRAME) { + frame_node_prepare_for_draw(*nodes[i], nodes); + } + } } static void frame_node_draw_label(const bNodeTree &ntree, diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index fb90e2bfe50..e83bfb43847 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -38,6 +38,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_workspace.h" @@ -78,6 +79,7 @@ #define USE_ESC_COMPO using blender::float2; +using blender::Map; /* ***************** composite job manager ********************** */ @@ -342,7 +344,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene "Compositing", WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE); - CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job"); + CompoJob *cj = MEM_cnew<CompoJob>("compo job"); /* customdata for preview thread */ cj->bmain = bmain; @@ -383,31 +385,11 @@ bool composite_node_editable(bContext *C) return false; } -void snode_dag_update(bContext &C, SpaceNode &snode) +static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree) { - Main *bmain = CTX_data_main(&C); + WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr); - /* for groups, update all ID's using this */ - if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) { - FOREACH_NODETREE_BEGIN (bmain, tntree, id) { - if (ntreeHasTree(tntree, snode.edittree)) { - DEG_id_tag_update(id, 0); - } - } - FOREACH_NODETREE_END; - } - - DEG_id_tag_update(snode.id, 0); - DEG_id_tag_update(&snode.nodetree->id, 0); -} - -void snode_notify(bContext &C, SpaceNode &snode) -{ - ID *id = snode.id; - - WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr); - - if (ED_node_is_shader(&snode)) { + if (ntree->type == NTREE_SHADER) { if (GS(id->name) == ID_MA) { WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id); } @@ -418,17 +400,38 @@ void snode_notify(bContext &C, SpaceNode &snode) WM_main_add_notifier(NC_WORLD | ND_WORLD, id); } } - else if (ED_node_is_compositor(&snode)) { - WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id); + else if (ntree->type == NTREE_COMPOSIT) { + WM_main_add_notifier(NC_SCENE | ND_NODES, id); } - else if (ED_node_is_texture(&snode)) { - WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id); + else if (ntree->type == NTREE_TEXTURE) { + WM_main_add_notifier(NC_TEXTURE | ND_NODES, id); } - else if (ED_node_is_geometry(&snode)) { + else if (ntree->type == NTREE_GEOMETRY) { WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id); } } +void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree) +{ + if (C != nullptr) { + SpaceNode *snode = CTX_wm_space_node(C); + if (snode != nullptr && root_ntree != nullptr) { + send_notifiers_after_tree_change(snode->id, root_ntree); + } + } + + NodeTreeUpdateExtraParams params = {nullptr}; + params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) { + send_notifiers_after_tree_change(id, ntree); + DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE); + }; + params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) { + DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT); + }; + + BKE_ntree_update_main_tree(bmain, root_ntree, ¶ms); +} + void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) { if (typeinfo) { @@ -477,7 +480,7 @@ void ED_node_shader_default(const bContext *C, ID *id) } ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree); - ntreeUpdateTree(bmain, ma->nodetree); + BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr); } else if (ELEM(GS(id->name), ID_WO, ID_LA)) { /* Emission */ @@ -517,7 +520,7 @@ void ED_node_shader_default(const bContext *C, ID *id) output->locx = 300.0f; output->locy = 300.0f; nodeSetActive(ntree, output); - ntreeUpdateTree(bmain, ntree); + BKE_ntree_update_main_tree(bmain, ntree, nullptr); } else { printf("ED_node_shader_default called on wrong ID type.\n"); @@ -555,7 +558,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); - ntreeUpdateTree(CTX_data_main(C), sce->nodetree); + BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr); } void ED_node_texture_default(const bContext *C, Tex *tex) @@ -583,7 +586,7 @@ void ED_node_texture_default(const bContext *C, Tex *tex) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(tex->nodetree, in, fromsock, out, tosock); - ntreeUpdateTree(CTX_data_main(C), tex->nodetree); + BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr); } /** @@ -628,28 +631,6 @@ void snode_set_context(const bContext &C) } } -void snode_update(SpaceNode &snode, bNode *node) -{ - /* XXX this only updates nodes in the current node space tree path. - * The function supposedly should update any potential group node linking to changed tree, - * this really requires a working depsgraph ... - */ - - /* update all edited group nodes */ - bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last; - if (path) { - bNodeTree *ngroup = path->nodetree; - for (path = path->prev; path; path = path->prev) { - nodeUpdateID(path->nodetree, (ID *)ngroup); - ngroup = path->nodetree; - } - } - - if (node) { - nodeUpdate(snode.edittree, node); - } -} - void ED_node_set_active( Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) { @@ -697,14 +678,10 @@ void ED_node_set_active( } node->flag |= NODE_DO_OUTPUT; - if (was_output == 0) { - ED_node_tag_update_nodetree(bmain, ntree, node); - } - } - else if (do_update) { - ED_node_tag_update_nodetree(bmain, ntree, node); } + ED_node_tree_propagate_change(nullptr, bmain, ntree); + if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { /* If active texture changed, free glsl materials. */ LISTBASE_FOREACH (Material *, ma, &bmain->materials) { @@ -750,7 +727,7 @@ void ED_node_set_active( if (r_active_texture_changed) { *r_active_texture_changed = true; } - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); WM_main_add_notifier(NC_IMAGE, nullptr); } @@ -767,7 +744,7 @@ void ED_node_set_active( node->flag |= NODE_DO_OUTPUT; if (was_output == 0) { - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* Adding a node doesn't link this yet. */ @@ -782,11 +759,11 @@ void ED_node_set_active( } node->flag |= NODE_DO_OUTPUT; - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } } else if (do_update) { - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } } else if (ntree->type == NTREE_TEXTURE) { @@ -931,7 +908,7 @@ static void node_resize_init(bContext *C, { SpaceNode *snode = CTX_wm_space_node(C); - NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__); + NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__); op->customdata = nsw; nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC; @@ -1274,7 +1251,8 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link) /* ****************** Duplicate *********************** */ -static void node_duplicate_reparent_recursive(bNode *node) +static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map, + bNode *node) { bNode *parent; @@ -1284,15 +1262,15 @@ static void node_duplicate_reparent_recursive(bNode *node) for (parent = node->parent; parent; parent = parent->parent) { if (parent->flag & SELECT) { if (!(parent->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(parent); + node_duplicate_reparent_recursive(node_map, parent); } break; } } /* reparent node copy to parent copy */ if (parent) { - nodeDetachNode(node->new_node); - nodeAttachNode(node->new_node, parent->new_node); + nodeDetachNode(node_map.lookup(node)); + nodeAttachNode(node_map.lookup(node), node_map.lookup(parent)); } } @@ -1302,17 +1280,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + bNode *lastnode = (bNode *)ntree->nodes.last; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); - - /* To ensure redraws or re-renders happen. */ - ED_node_tag_update_id(snode->id); + bNode *new_node = blender::bke::node_copy_with_mapping( + ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, new_node); } /* make sure we don't copy new nodes again! */ @@ -1321,8 +1300,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } } - /* Copy links between selected nodes. - * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ + /* Copy links between selected nodes. */ bNodeLink *lastlink = (bNodeLink *)ntree->links.last; LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. @@ -1330,13 +1308,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { - bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink"); newlink->flag = link->flag; - newlink->tonode = link->tonode->new_node; - newlink->tosock = link->tosock->new_sock; + newlink->tonode = node_map.lookup(link->tonode); + newlink->tosock = socket_map.lookup(link->tosock); if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) { - newlink->fromnode = link->fromnode->new_node; - newlink->fromsock = link->fromsock->new_sock; + newlink->fromnode = node_map.lookup(link->fromnode); + newlink->fromsock = socket_map.lookup(link->fromsock); } else { /* input node not copied, this keeps the original input linked */ @@ -1360,7 +1338,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* reparent copied nodes */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(node); + node_duplicate_reparent_recursive(node_map, node); } /* only has to check old nodes */ @@ -1373,13 +1351,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* has been set during copy above */ - bNode *newnode = node->new_node; + bNode *newnode = node_map.lookup(node); nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); - - do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode)); } /* make sure we don't copy new nodes again! */ @@ -1388,13 +1364,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } - + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1485,8 +1455,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op)) } } - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1653,7 +1622,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op)) node_flag_toggle_exec(snode, NODE_PREVIEW); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -1732,7 +1701,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -1760,23 +1729,17 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if ((node->flag & SELECT) && !node->typeinfo->no_muting) { node->flag ^= NODE_MUTED; - snode_update(*snode, node); - do_tag_update |= (do_tag_update || - node_connected_to_output(*bmain, *snode->edittree, *node)); + BKE_ntree_update_tag_node_mute(snode->edittree, node); } } - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1802,24 +1765,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { - do_tag_update |= (do_tag_update || - node_connected_to_output(*bmain, *snode->edittree, *node)); nodeRemoveNode(bmain, snode->edittree, node, true); } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1863,10 +1818,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -1901,10 +1853,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1951,7 +1900,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "file_path", file_path); ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -2000,7 +1949,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } @@ -2067,7 +2016,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) nimf->active_input++; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -2153,47 +2102,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ - bNode *new_node = BKE_node_copy_store_new_pointers( - nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN); - BKE_node_clipboard_add_node(new_node); + bNode *new_node = blender::bke::node_copy_with_mapping(nullptr, + *node, + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_MAIN, + false, + socket_map); + node_map.add_new(node, new_node); } } - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->flag & SELECT) { - bNode *new_node = node->new_node; - - /* ensure valid pointers */ - if (new_node->parent) { - /* parent pointer must be redirected to new node or detached if parent is - * not copied */ - if (new_node->parent->flag & NODE_SELECT) { - new_node->parent = new_node->parent->new_node; - } - else { - nodeDetachNode(new_node); - } + for (bNode *new_node : node_map.values()) { + BKE_node_clipboard_add_node(new_node); + + /* Parent pointer must be redirected to new node or detached if parent is not copied. */ + if (new_node->parent) { + if (node_map.contains(new_node->parent)) { + new_node->parent = node_map.lookup(new_node->parent); + } + else { + nodeDetachNode(new_node); } } } - /* Copy links between selected nodes. - * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - + /* Copy links between selected nodes. */ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - /* This creates new links between copied nodes. */ - if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode && - (link->fromnode->flag & NODE_SELECT)) { - bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + BLI_assert(link->tonode); + BLI_assert(link->fromnode); + if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) { + bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__); newlink->flag = link->flag; - newlink->tonode = link->tonode->new_node; - newlink->tosock = link->tosock->new_sock; - newlink->fromnode = link->fromnode->new_node; - newlink->fromsock = link->fromsock->new_sock; + newlink->tonode = node_map.lookup(link->tonode); + newlink->tosock = socket_map.lookup(link->tosock); + newlink->fromnode = node_map.lookup(link->fromnode); + newlink->fromsock = socket_map.lookup(link->fromsock); BKE_node_clipboard_add_link(newlink); } @@ -2288,35 +2238,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } mul_v2_fl(center, 1.0 / num_nodes); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + /* copy nodes from clipboard */ LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); + bNode *new_node = blender::bke::node_copy_with_mapping( + ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, new_node); + } + for (bNode *new_node : node_map.values()) { /* pasted nodes are selected */ nodeSetSelected(new_node, true); - } - /* reparent copied nodes */ - LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = node->new_node; + /* The parent pointer must be redirected to new node. */ if (new_node->parent) { - new_node->parent = new_node->parent->new_node; + if (node_map.contains(new_node->parent)) { + new_node->parent = node_map.lookup(new_node->parent); + } } } LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { nodeAddLink(ntree, - link->fromnode->new_node, - link->fromsock->new_sock, - link->tonode->new_node, - link->tosock->new_sock); + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); } Main *bmain = CTX_data_main(C); - ntreeUpdateTree(bmain, snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); /* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */ DEG_relations_tag_update(bmain); @@ -2384,10 +2337,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) /* make the new socket active */ sock->flag |= SELECT; - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2434,10 +2384,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op) active_sock->flag |= SELECT; } - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2488,7 +2435,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op) /* Need the extra update here because the loop above does not check for valid links in the node * group we're currently editing. */ - ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_interface(ntree); /* Deactivate sockets. */ LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) { @@ -2497,10 +2444,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op) /* Make the new socket active. */ iosock->flag |= SELECT; - ntreeUpdateTree(main, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, main, ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2611,11 +2555,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) } } - ntree->update |= NTREE_UPDATE_GROUP; - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + BKE_ntree_update_tag_interface(ntree); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2846,7 +2787,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op) btree->flag |= NTREE_VIEWER_BORDER; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, bmain, btree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); } else { @@ -2886,7 +2827,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op)) bNodeTree *btree = snode->nodetree; btree->flag &= ~NTREE_VIEWER_BORDER; - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), btree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2931,7 +2872,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op)) ntreeCompositCryptomatteAddSocket(ntree, node); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } @@ -2977,7 +2918,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 4890c3e39cf..6f96e08d749 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -125,8 +125,8 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C), 0.0f, ""); - AttributeSearchData *data = OBJECT_GUARDED_NEW( - AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data}); + AttributeSearchData *data = MEM_new<AttributeSearchData>( + __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data}); UI_but_func_search_set_results_are_suggestions(but, true); UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP); diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 704ffe1e478..f6802e64049 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -32,6 +32,7 @@ #include "BLI_linklist.h" #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_vector.hh" #include "BLT_translation.h" @@ -40,6 +41,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "DEG_depsgraph_build.h" @@ -61,6 +63,8 @@ #include "node_intern.hh" /* own include */ using blender::float2; +using blender::Map; +using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -216,24 +220,21 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha MEM_freeN(basepath_change); } -/* returns 1 if its OK */ -static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) +/** + * \return True if successful. + */ +static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) { - /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - node->new_node = nullptr; - } - ListBase anim_basepaths = {nullptr, nullptr}; - LinkNode *nodes_delayed_free = nullptr; - bNodeTree *ngroup = (bNodeTree *)gnode->id; + Vector<bNode *> nodes_delayed_free; + const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id); /* wgroup is a temporary copy of the NodeTree we're merging in * - all of wgroup's nodes are copied across to their new home * - ngroup (i.e. the source NodeTree) is left unscathed * - temp copy. do change ID usercount for the copies */ - bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true); + bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup); /* Add the nodes into the ntree */ LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) { @@ -242,7 +243,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) */ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { /* We must delay removal since sockets will reference this node. see: T52092 */ - BLI_linklist_prepend(&nodes_delayed_free, node); + nodes_delayed_free.append(node); } /* keep track of this node's RNA "base" path (the part of the path identifying the node) @@ -258,6 +259,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) /* migrate node */ BLI_remlink(&wgroup->nodes, node); BLI_addtail(&ntree->nodes, node); + BKE_ntree_update_tag_node_new(ntree, node); /* ensure unique node name in the node tree */ nodeUniqueName(ntree, node); @@ -284,6 +286,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) { BLI_remlink(&wgroup->links, link); BLI_addtail(&ntree->links, link); + BKE_ntree_update_tag_link_added(ntree, link); } bNodeLink *glinks_last = (bNodeLink *)ntree->links.last; @@ -385,17 +388,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) } } - while (nodes_delayed_free) { - bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free); + for (bNode *node : nodes_delayed_free) { nodeRemoveNode(bmain, ntree, node, false); } /* delete the group instance and dereference group tree */ nodeRemoveNode(bmain, ntree, gnode, true); - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - - return 1; + return true; } static int node_group_ungroup_exec(bContext *C, wmOperator *op) @@ -412,16 +412,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op) } if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) { - ntreeUpdateTree(bmain, snode->nodetree); + ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); } else { BKE_report(op->reports, RPT_WARNING, "Cannot ungroup"); return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - return OPERATOR_FINISHED; } @@ -457,13 +454,11 @@ static bool node_group_separate_selected( nodeSetSelected(node, false); } - /* clear new pointers, set in BKE_node_copy_ex(). */ - LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) { - node->new_node = nullptr; - } - ListBase anim_basepaths = {nullptr, nullptr}; + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + /* add selected nodes into the ntree */ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) { if (!(node->flag & NODE_SELECT)) { @@ -479,7 +474,9 @@ static bool node_group_separate_selected( bNode *newnode; if (make_copy) { /* make a copy */ - newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT); + newnode = blender::bke::node_copy_with_mapping( + &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, newnode); } else { /* use the existing node */ @@ -528,10 +525,10 @@ static bool node_group_separate_selected( /* make a copy of internal links */ if (fromselect && toselect) { nodeAddLink(&ntree, - link->fromnode->new_node, - link->fromsock->new_sock, - link->tonode->new_node, - link->tosock->new_sock); + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); } } else { @@ -558,9 +555,9 @@ static bool node_group_separate_selected( } } - ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_all(&ntree); if (!make_copy) { - ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_all(&ngroup); } return true; @@ -614,10 +611,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op) /* switch to parent tree */ ED_node_tree_pop(snode); - ntreeUpdateTree(CTX_data_main(C), snode->nodetree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); return OPERATOR_FINISHED; } @@ -812,6 +806,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* change node-collection membership */ BLI_remlink(&ntree.nodes, node); BLI_addtail(&ngroup->nodes, node); + BKE_ntree_update_tag_node_removed(&ntree); + BKE_ntree_update_tag_node_new(ngroup, node); /* ensure unique node name in the ngroup */ nodeUniqueName(ngroup, node); @@ -983,11 +979,6 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, } } } - - /* update of the group tree */ - ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; - /* update of the tree containing the group instance node */ - ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; } static bNode *node_group_make_from_selected(const bContext &C, @@ -1016,9 +1007,6 @@ static bNode *node_group_make_from_selected(const bContext &C, node_group_make_insert_selected(C, ntree, gnode); - /* update of the tree containing the group instance node */ - ntree.update |= NTREE_UPDATE_NODES; - return gnode; } @@ -1047,14 +1035,10 @@ static int node_group_make_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { sort_multi_input_socket_links(snode, *node, nullptr, nullptr); } - ntreeUpdateTree(bmain, ngroup); } } - ntreeUpdateTree(bmain, &ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, nullptr); /* We broke relations in node tree, need to rebuild them in the graphs. */ DEG_relations_tag_update(bmain); @@ -1107,12 +1091,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op) nodeSetActive(ntree, gnode); ED_node_tree_push(snode, ngroup, gnode); - ntreeUpdateTree(bmain, ngroup); - - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index 2e55bb0cb28..52dde965114 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -235,7 +235,6 @@ void sort_multi_input_socket_links(SpaceNode &snode, bNode &node, bNodeLink *drag_link, const blender::float2 *cursor); -bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node); void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); @@ -252,12 +251,8 @@ void NODE_OT_link_viewer(wmOperatorType *ot); void NODE_OT_insert_offset(wmOperatorType *ot); -void snode_notify(bContext &C, SpaceNode &snode); -void snode_dag_update(bContext &C, SpaceNode &snode); void snode_set_context(const bContext &C); -void snode_update(SpaceNode &snode, bNode *node); -/** Operator poll callback. */ bool composite_node_active(bContext *C); /** Operator poll callback. */ bool composite_node_editable(bContext *C); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 90b53258d5e..4055dfdbf9e 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -34,6 +34,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_screen.h" #include "ED_node.h" /* own include */ @@ -73,121 +74,6 @@ using blender::StringRefNull; using blender::Vector; /* -------------------------------------------------------------------- */ -/** \name Relations Helpers - * \{ */ - -static bool ntree_has_drivers(bNodeTree &ntree) -{ - const AnimData *adt = BKE_animdata_from_id(&ntree.id); - if (adt == nullptr) { - return false; - } - return !BLI_listbase_is_empty(&adt->drivers); -} - -static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to) -{ - if (from.flag & NODE_TEST) { - return false; - } - from.flag |= NODE_TEST; - LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (link->fromnode == &from) { - if (link->tonode == &to) { - return true; - } - - if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) { - return true; - } - } - } - return false; -} - -static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to) -{ - if (&from == &to) { - return true; - } - ntreeNodeFlagSet(&ntree, NODE_TEST, false); - return ntree_check_nodes_connected_dfs(ntree, from, to); -} - -static bool node_group_has_output_dfs(bNode &node) -{ - bNodeTree *ntree = (bNodeTree *)node.id; - if (ntree->id.tag & LIB_TAG_DOIT) { - return false; - } - ntree->id.tag |= LIB_TAG_DOIT; - LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) { - if (current_node->type == NODE_GROUP) { - if (current_node->id && node_group_has_output_dfs(*current_node)) { - return true; - } - } - if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) { - return true; - } - } - return false; -} - -static bool node_group_has_output(Main &bmain, bNode &node) -{ - BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP)); - bNodeTree *ntree = (bNodeTree *)node.id; - if (ntree == nullptr) { - return false; - } - BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false); - return node_group_has_output_dfs(node); -} - -bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node) -{ - /* Special case for drivers: if node tree has any drivers we assume it is - * always to be tagged for update when node changes. Otherwise we will be - * doomed to do some deep and nasty deep search of indirect dependencies, - * which will be too complicated without real benefit. - */ - if (ntree_has_drivers(ntree)) { - return true; - } - LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) { - /* Special case for group nodes -- if modified node connected to a group - * with active output inside we consider refresh is needed. - * - * We could make check more grained here by taking which socket the node - * is connected to and so eventually. - */ - if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) { - return true; - } - if (ntree_check_nodes_connected(ntree, node, *current_node) && - node_group_has_output(bmain, *current_node)) { - return true; - } - } - if (current_node->flag & NODE_DO_OUTPUT) { - if (ntree_check_nodes_connected(ntree, node, *current_node)) { - return true; - } - } - if (current_node->type == GEO_NODE_VIEWER) { - if (ntree_check_nodes_connected(ntree, node, *current_node)) { - return true; - } - } - } - return false; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Add Node * \{ */ @@ -214,9 +100,9 @@ static void clear_picking_highlight(ListBase *links) } } -static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock) +static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__); + bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__); if (sock.in_out == SOCK_OUT) { oplink->fromnode = &node; oplink->fromsock = &sock; @@ -226,27 +112,17 @@ static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, b oplink->tosock = &sock; } oplink->flag |= NODE_LINK_VALID; - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, node)) { - oplink->flag |= NODE_LINK_TEST; - } oplink->flag |= NODE_LINK_DRAGGED; return oplink; } -static void pick_link(const bContext &C, - wmOperator &op, - bNodeLinkDrag &nldrag, - SpaceNode &snode, - bNode *node, - bNodeLink &link_to_pick) +static void pick_link( + wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick) { clear_picking_highlight(&snode.edittree->links); RNA_boolean_set(op.ptr, "has_link_picked", true); - Main *bmain = CTX_data_main(&C); - bNodeLink *link = create_drag_link( - *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock); + bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock); nldrag.links.append(link); nodeRemLink(snode.edittree, &link_to_pick); @@ -258,7 +134,7 @@ static void pick_link(const bContext &C, /* Send changed event to original link->tonode. */ if (node) { - snode_update(snode, node); + BKE_ntree_update_tag_node_property(snode.edittree, node); } } @@ -324,7 +200,7 @@ static void pick_input_link_by_link_intersect(const bContext &C, ED_area_tag_redraw(CTX_wm_area(&C)); if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) { - pick_link(C, op, nldrag, *snode, node, *link_to_pick); + pick_link(op, nldrag, *snode, node, *link_to_pick); } } } @@ -566,7 +442,7 @@ static void snode_autoconnect(Main &bmain, } if (numlinks > 0) { - ntreeUpdateTree(&bmain, ntree); + BKE_ntree_update_main_tree(&bmain, ntree, nullptr); } } @@ -640,7 +516,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, (eNodeSocketDatatype)src_socket.type); BLI_assert(data_type != CD_AUTO_FROM_NAME); storage->data_type = data_type; - nodeUpdate(&ntree, &viewer_node); + viewer_node.typeinfo->updatefunc(&ntree, &viewer_node); return viewer_socket; } } @@ -810,7 +686,7 @@ static int link_socket_to_viewer(const bContext &C, else { link_to_change->fromnode = &bnode_to_view; link_to_change->fromsock = &bsocket_to_view; - btree.update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_changed(&btree); } remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode); @@ -819,10 +695,7 @@ static int link_socket_to_viewer(const bContext &C, ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode); } - ntreeUpdateTree(CTX_data_main(&C), &btree); - snode_update(snode, viewer_bnode); - DEG_id_tag_update(&btree.id, 0); - + ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree); return OPERATOR_FINISHED; } @@ -863,7 +736,7 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - snode_notify(*C, snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -1041,17 +914,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &ntree = *snode.edittree; bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata; - bool do_tag_update = false; /* avoid updates while applying links */ ntree.is_updating = true; for (bNodeLink *link : nldrag->links) { - /* See note below, but basically TEST flag means that the link - * was connected to output (or to a node which affects the - * output). - */ - do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; - link->flag &= ~NODE_LINK_DRAGGED; if (apply_links && link->tosock && link->fromsock) { @@ -1067,18 +933,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) /* add link to the node tree */ BLI_addtail(&ntree.links, link); - - ntree.update |= NTREE_UPDATE_LINKS; - - /* tag tonode for update */ - link->tonode->update |= NODE_UPDATE; + BKE_ntree_update_tag_link_added(&ntree, link); /* we might need to remove a link */ node_remove_extra_links(snode, *link); - - if (link->tonode) { - do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode)); - } } else { nodeRemLink(&ntree, link); @@ -1086,11 +944,7 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) } ntree.is_updating = false; - ntreeUpdateTree(bmain, &ntree); - snode_notify(C, snode); - if (do_tag_update) { - snode_dag_update(C, snode); - } + ED_node_tree_propagate_change(&C, bmain, &ntree); /* Ensure draglink tooltip is disabled. */ draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag); @@ -1250,8 +1104,7 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, - SpaceNode &snode, +static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode, float2 cursor, const bool detach) { @@ -1270,23 +1123,12 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, /* detach current links and store them in the operator data */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) { if (link->fromsock == sock) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); + bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link"); *oplink = *link; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; oplink->flag |= NODE_LINK_DRAGGED; - /* The link could be disconnected and in that case we - * wouldn't be able to check whether tag update is - * needed or not when releasing mouse button. So we - * cache whether the link affects output or not here - * using TEST flag. - */ - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) { - oplink->flag |= NODE_LINK_TEST; - } - nldrag->links.append(oplink); nodeRemLink(snode.edittree, link); } @@ -1296,7 +1138,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* create a new link */ - nldrag->links.append(create_drag_link(bmain, snode, *node, *sock)); + nldrag->links.append(create_drag_link(*node, *sock)); } return nldrag; } @@ -1324,22 +1166,18 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, } if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); + bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link"); *oplink = *link_to_pick; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; oplink->flag |= NODE_LINK_DRAGGED; - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) { - oplink->flag |= NODE_LINK_TEST; - } nldrag->links.append(oplink); nodeRemLink(snode.edittree, link_to_pick); /* send changed event to original link->tonode */ if (node) { - snode_update(snode, node); + BKE_ntree_update_tag_node_property(snode.edittree, node); } } } @@ -1347,7 +1185,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* create a new link */ - nldrag->links.append(create_drag_link(bmain, snode, *node, *sock)); + nldrag->links.append(create_drag_link(*node, *sock)); } return nldrag; } @@ -1370,7 +1208,7 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); + std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach); if (nldrag) { UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); @@ -1473,9 +1311,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op) node_deselect_all_input_sockets(snode, false); node_deselect_all_output_sockets(snode, false); - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -1532,7 +1368,6 @@ static int cut_links_exec(bContext *C, wmOperator *op) Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); ARegion ®ion = *CTX_wm_region(C); - bool do_tag_update = false; int i = 0; float mcoords[256][2]; @@ -1567,23 +1402,14 @@ static int cut_links_exec(bContext *C, wmOperator *op) found = true; } - do_tag_update |= (do_tag_update || - node_connected_to_output(bmain, *snode.edittree, *link->tonode)); - - snode_update(snode, link->tonode); bNode *to_node = link->tonode; nodeRemLink(snode.edittree, link); sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr); } } + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); if (found) { - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - if (do_tag_update) { - snode_dag_update(*C, snode); - } - return OPERATOR_FINISHED; } @@ -1629,7 +1455,6 @@ static int mute_links_exec(bContext *C, wmOperator *op) Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); ARegion ®ion = *CTX_wm_region(C); - bool do_tag_update = false; int i = 0; float mcoords[256][2]; @@ -1671,10 +1496,6 @@ static int mute_links_exec(bContext *C, wmOperator *op) } if (node_links_intersect(*link, mcoords, i)) { - do_tag_update |= (do_tag_update || - node_connected_to_output(bmain, *snode.edittree, *link->tonode)); - - snode_update(snode, link->tonode); nodeMuteLinkToggle(snode.edittree, link); } } @@ -1687,12 +1508,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) link->flag &= ~NODE_LINK_TEST; } - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - if (do_tag_update) { - snode_dag_update(*C, snode); - } - + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -1743,11 +1559,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), &ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); - + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); return OPERATOR_FINISHED; } @@ -2653,8 +2465,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area) /* set up insert offset data, it needs stuff from here */ if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { - NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData), - __func__); + NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__); iofsd->insert = select; iofsd->prev = link->fromnode; @@ -2663,10 +2474,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area) snode->runtime->iofsd = iofsd; } - ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */ - snode_update(*snode, select); - ED_node_tag_update_id((ID *)snode->edittree); - ED_node_tag_update_id(snode->id); + ED_node_tree_propagate_change(nullptr, bmain, snode->edittree); } } } diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 386178596af..492237477c1 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -37,6 +37,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_node_tree_update.h" #include "RNA_access.h" @@ -84,7 +85,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item) { if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { node->id = (ID *)item->ngroup; - ntreeUpdateTree(bmain, item->ngroup); + BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr); } else { /* nothing to do for now */ @@ -179,10 +180,8 @@ static void node_socket_disconnect(Main *bmain, nodeRemLink(ntree, sock_to->link); sock_to->flag |= SOCK_COLLAPSED; - nodeUpdate(ntree, node_to); - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* remove all nodes connected to this socket, if they aren't connected to other nodes */ @@ -195,10 +194,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN node_remove_linked(bmain, ntree, sock_to->link->fromnode); sock_to->flag |= SOCK_COLLAPSED; - nodeUpdate(ntree, node_to); - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* add new node connected to this socket, or replace an existing one */ @@ -299,11 +296,9 @@ static void node_socket_add_replace(const bContext *C, node_remove_linked(bmain, ntree, node_prev); } - nodeUpdate(ntree, node_from); - nodeUpdate(ntree, node_to); - ntreeUpdateTree(CTX_data_main(C), ntree); - - ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_from); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /****************************** Node Link Menu *******************************/ @@ -704,7 +699,7 @@ void uiTemplateNodeLink( uiBut *but; float socket_col[4]; - arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg"); + arg = MEM_new<NodeLinkArg>("NodeLinkArg"); arg->ntree = ntree; arg->node = node; arg->sock = input; diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index df629a983e3..12f390c47cd 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -255,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_CANCELLED; } - nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct"); + nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct"); op->customdata = nvm; nvm->mvalo[0] = event->mval[0]; nvm->mvalo[1] = event->mval[1]; @@ -643,7 +643,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"); + info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo"); info->art = region->type; info->draw_handle = ED_region_draw_cb_activate( region->type, sample_draw, info, REGION_DRAW_POST_PIXEL); diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index 4cc0bed1928..54a72a4b53d 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -63,7 +63,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) BLI_listbase_clear(&snode->treepath); if (ntree) { - bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path"); path->nodetree = ntree; path->parent_key = NODE_INSTANCE_KEY_BASE; @@ -96,7 +96,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) { - bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path"); bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last; path->nodetree = ntree; if (gnode) { @@ -220,7 +220,7 @@ float2 space_node_group_offset(const SpaceNode &snode) static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode"); + SpaceNode *snode = MEM_cnew<SpaceNode>("initnode"); snode->spacetype = SPACE_NODE; snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA; @@ -238,21 +238,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s NODE_TREE_TYPES_END; /* header */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node"); + ARegion *region = MEM_cnew<ARegion>("header for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* buttons/list view */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node"); + region = MEM_cnew<ARegion>("buttons for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; /* toolbar */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools"); + region = MEM_cnew<ARegion>("node tools"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_TOOLS; @@ -261,7 +261,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->flag = RGN_FLAG_HIDDEN; /* main region */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node"); + region = MEM_cnew<ARegion>("main region for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -309,10 +309,23 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) SpaceNode *snode = (SpaceNode *)area->spacedata.first; if (snode->runtime == nullptr) { - snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__); + snode->runtime = MEM_new<SpaceNode_Runtime>(__func__); } } +static bool any_node_uses_id(const bNodeTree *ntree, const ID *id) +{ + if (ELEM(nullptr, ntree, id)) { + return false; + } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->id == id) { + return true; + } + } + return false; +} + static void node_area_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -436,10 +449,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_IMAGE: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - /* note that nodeUpdateID is already called by BKE_image_signal() on all - * scenes so really this is just to know if the images is used in the compo else - * painting on images could become very slow when the compositor is open. */ - if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { + /* Without this check drawing on an image could become very slow when the compositor is + * open. */ + if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -449,7 +461,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { + if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -971,7 +983,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, void ED_spacetype_node() { - SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node"); + SpaceType *st = MEM_cnew<SpaceType>("spacetype node"); ARegionType *art; st->spaceid = SPACE_NODE; @@ -994,7 +1006,7 @@ void ED_spacetype_node() st->space_subtype_set = node_space_subtype_set; /* regions: main window */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; @@ -1008,7 +1020,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; @@ -1019,7 +1031,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -1030,7 +1042,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: toolbar */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); + art = MEM_cnew<ARegionType>("spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index a4d5f2635d4..85fee590447 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -123,7 +123,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode /* Find tree element to drop into, with additional before and after reorder support. */ static TreeElement *outliner_drop_insert_find(bContext *C, - const wmEvent *event, + const int xy[2], TreeElementInsertType *r_insert_type) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); @@ -136,8 +136,11 @@ static TreeElement *outliner_drop_insert_find(bContext *C, return NULL; } - UI_view2d_region_to_view( - ®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + int mval[2]; + mval[0] = xy[0] - region->winrct.xmin; + mval[1] = xy[1] - region->winrct.ymin; + + UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te_hovered) { @@ -216,10 +219,10 @@ static bool is_pchan_element(TreeElement *te) } static TreeElement *outliner_drop_insert_collection_find(bContext *C, - const wmEvent *event, + const int xy[2], TreeElementInsertType *r_insert_type) { - TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type); + TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type); if (!te) { return NULL; } @@ -707,7 +710,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData return false; } - TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type); + TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type); if (!te_target) { return false; } @@ -1088,14 +1091,12 @@ static Collection *collection_parent_from_ID(ID *id) return NULL; } -static bool collection_drop_init(bContext *C, - wmDrag *drag, - const wmEvent *event, - CollectionDrop *data) +static bool collection_drop_init( + bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data) { /* Get collection to drop into. */ TreeElementInsertType insert_type; - TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); + TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type); if (!te) { return false; } @@ -1123,7 +1124,7 @@ static bool collection_drop_init(bContext *C, /* Get collection to drag out of. */ ID *parent = drag_id->from_parent; Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl) { + if (is_link) { from_collection = NULL; } @@ -1164,7 +1165,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); CollectionDrop data; - if (!event->shift && collection_drop_init(C, drag, event, &data)) { + if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) { TreeElement *te = data.te; TreeStoreElem *tselem = TREESTORE(te); if (!data.from || event->ctrl) { @@ -1201,13 +1202,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event static char *collection_drop_tooltip(bContext *C, wmDrag *drag, - const int UNUSED(xy[2]), + const int xy[2], wmDropBox *UNUSED(drop)) { - wmWindowManager *wm = CTX_wm_manager(C); - const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL; + wmWindow *win = CTX_wm_window(C); + const wmEvent *event = win ? win->eventstate : NULL; + CollectionDrop data; - if (event && !event->shift && collection_drop_init(C, drag, event, &data)) { + if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) { TreeElement *te = data.te; if (!data.from || event->ctrl) { return BLI_strdup(TIP_("Link inside Collection")); @@ -1260,7 +1262,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE wmDrag *drag = lb->first; CollectionDrop data; - if (!collection_drop_init(C, drag, event, &data)) { + if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 9d4b14a1f57..8ddd58bcc18 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -38,6 +38,7 @@ #include "BLT_translation.h" +#include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_appdir.h" #include "BKE_armature.h" @@ -48,6 +49,7 @@ #include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_workspace.h" @@ -627,8 +629,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C, TreeStoreElem *tselem = TREESTORE(te); if ((tselem->type == TSE_SOME_ID) && tselem->id) { - printf("found id %s (%p)!\n", tselem->id->name, tselem->id); - RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); @@ -654,7 +654,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent * outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]); } - return WM_operator_props_dialog_popup(C, op, 200); + return WM_operator_props_dialog_popup(C, op, 400); } static const EnumPropertyItem *outliner_id_itemf(bContext *C, @@ -703,6 +703,9 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); + /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways. + */ + RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); @@ -1262,7 +1265,8 @@ static TreeElement *outliner_show_active_get_element(bContext *C, TreeElement *te_obact = te; if (obact->mode & OB_MODE_POSE) { - bPoseChannel *pchan = CTX_data_active_pose_bone(C); + Object *obpose = BKE_object_pose_armature_get(obact); + bPoseChannel *pchan = BKE_pose_channel_active(obpose, false); if (pchan) { te = outliner_find_posechannel(&te_obact->subtree, pchan); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 01f0feec771..bcd455de9a4 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -817,7 +817,7 @@ static void id_override_library_create_fn(bContext *C, ID *id_reference = NULL; bool is_override_instancing_object = false; if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL && - GS(tsep->id->name) == ID_OB) { + GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) { Object *ob = (Object *)tsep->id; if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) { BLI_assert(GS(id_root->name) == ID_GR); diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 616953e720a..9f31e55439d 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -627,6 +627,19 @@ static void seq_build_proxy(bContext *C, Sequence *seq) ED_area_tag_redraw(CTX_wm_area(C)); } +static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, + ListBase *seqbase, + Sequence *seq_movie, + Sequence *seq_sound) +{ + if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) { + return; + } + + SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie)); + SEQ_time_update_sequence(scene, seqbase, seq_sound); +} + static void sequencer_add_movie_multiple_strips(bContext *C, wmOperator *op, SeqLoadData *load_data) @@ -689,6 +702,7 @@ static void sequencer_add_movie_multiple_strips(bContext *C, else { load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; } + sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); seq_load_apply_generic_options(C, op, seq_sound); seq_load_apply_generic_options(C, op, seq_movie); seq_build_proxy(C, seq_movie); @@ -740,6 +754,7 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa load_data->start_frame += audio_frame_offset; seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip); } + sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); seq_load_apply_generic_options(C, op, seq_sound); seq_load_apply_generic_options(C, op, seq_movie); seq_build_proxy(C, seq_movie); diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 61cc70830af..02f7f1d71c4 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -60,15 +60,14 @@ using namespace blender::ed::spreadsheet; static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet), - "spreadsheet space"); + SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space"); spreadsheet_space->spacetype = SPACE_SPREADSHEET; spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE; { /* Header. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet header"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; @@ -76,7 +75,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Footer. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_FOOTER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; @@ -84,16 +83,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Dataset Region */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region"); BLI_addtail(&spreadsheet_space->regionbase, region); - region->regiontype = RGN_TYPE_CHANNELS; + region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; - region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); } { /* Properties region. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet right region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; @@ -102,7 +100,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Main window. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet main region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; } @@ -114,7 +112,7 @@ static void spreadsheet_free(SpaceLink *sl) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - delete sspreadsheet->runtime; + MEM_delete(sspreadsheet->runtime); LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { spreadsheet_row_filter_free(row_filter); @@ -131,7 +129,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first; if (sspreadsheet->runtime == nullptr) { - sspreadsheet->runtime = new SpaceSpreadsheet_Runtime(); + sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__); } } @@ -140,10 +138,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl; SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old); if (sspreadsheet_old->runtime) { - sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime); + sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__, + *sspreadsheet_old->runtime); } else { - sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(); + sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__); } BLI_listbase_clear(&sspreadsheet_new->row_filters); @@ -621,7 +620,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS void ED_spacetype_spreadsheet() { - SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet"); + SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet"); ARegionType *art; st->spaceid = SPACE_SPREADSHEET; @@ -636,7 +635,7 @@ void ED_spacetype_spreadsheet() st->id_remap = spreadsheet_id_remap; /* regions: main window */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; @@ -646,7 +645,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet header region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = 0; @@ -659,7 +658,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: footer */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region"); art->regionid = RGN_TYPE_FOOTER; art->prefsizey = HEADERY; art->keymapflag = 0; @@ -672,7 +671,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: right panel buttons */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet right region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -687,10 +686,10 @@ void ED_spacetype_spreadsheet() register_row_filter_panels(*art); /* regions: channels */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region"); - art->regionid = RGN_TYPE_CHANNELS; + art = MEM_cnew<ARegionType>("spreadsheet dataset region"); + art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 150 + V2D_SCROLL_WIDTH; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; + art->keymapflag = ED_KEYMAP_UI; art->init = ED_region_panels_init; art->draw = spreadsheet_dataset_region_draw; art->listener = spreadsheet_dataset_region_listener; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index 7551593ef38..ee623083db7 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -66,8 +66,7 @@ eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type) SpreadsheetColumnID *spreadsheet_column_id_new() { - SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID), - __func__); + SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__); return column_id; } @@ -88,8 +87,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id) SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id) { - SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn), - __func__); + SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__); column->id = column_id; return column; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc index e55a7cae6a6..5cec016b727 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc @@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet { static SpreadsheetContextObject *spreadsheet_context_object_new() { - SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN( - sizeof(SpreadsheetContextObject), __func__); + SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__); context->base.type = SPREADSHEET_CONTEXT_OBJECT; return context; } @@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context) static SpreadsheetContextModifier *spreadsheet_context_modifier_new() { - SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN( - sizeof(SpreadsheetContextModifier), __func__); + SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__); context->base.type = SPREADSHEET_CONTEXT_MODIFIER; return context; } @@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex static SpreadsheetContextNode *spreadsheet_context_node_new() { - SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN( - sizeof(SpreadsheetContextNode), __func__); + SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__); context->base.type = SPREADSHEET_CONTEXT_NODE; return context; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc index 854c3d4aba6..db8265a33ce 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc @@ -25,7 +25,7 @@ namespace blender::ed::spreadsheet { void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type) { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); strcpy(panel_type->label, N_("Data Set")); strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index a6a0266fcc1..36c7f1057df 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -311,8 +311,7 @@ IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, SpreadsheetRowFilter *spreadsheet_row_filter_new() { - SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN( - sizeof(SpreadsheetRowFilter), __func__); + SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__); row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED); row_filter->operation = SPREADSHEET_ROW_FILTER_LESS; row_filter->threshold = 0.01f; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index bcced7b5937..56722104b4f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -331,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor void register_row_filter_panels(ARegionType ®ion_type) { { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters"); strcpy(panel_type->label, N_("Filters")); strcpy(panel_type->category, "Filters"); @@ -342,7 +342,7 @@ void register_row_filter_panels(ARegionType ®ion_type) } { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_filter"); strcpy(panel_type->label, ""); strcpy(panel_type->category, "Filters"); diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 41eddd32854..7f0f30624cb 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -35,6 +35,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -236,6 +237,59 @@ static void recent_files_menu_register(void) WM_menutype_add(mt); } +static void undo_history_draw_menu(const bContext *C, Menu *menu) +{ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + return; + } + int undo_step_count = 0; + for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next) { + if (us->skip) { + continue; + } + undo_step_count += 1; + } + + uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false); + uiLayout *column = NULL; + + const int col_size = 20 + (undo_step_count / 12); + int i = 0; + + undo_step_count = 0; + for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { + if (us->skip) { + continue; + } + if (!(undo_step_count % col_size)) { + column = uiLayoutColumn(split, false); + } + const bool is_active = (us == wm->undo_stack->step_active); + uiLayout *row = uiLayoutRow(column, false); + uiLayoutSetEnabled(row, !is_active); + uiItemIntO(row, + IFACE_(us->name), + is_active ? ICON_LAYER_ACTIVE : ICON_NONE, + "ED_OT_undo_history", + "item", + i); + undo_step_count += 1; + } +} + +static void undo_history_menu_register(void) +{ + MenuType *mt; + + mt = MEM_callocN(sizeof(MenuType), __func__); + strcpy(mt->idname, "TOPBAR_MT_undo_history"); + strcpy(mt->label, N_("Undo History")); + strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + mt->draw = undo_history_draw_menu; + WM_menutype_add(mt); +} + void ED_spacetype_topbar(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar"); @@ -278,6 +332,7 @@ void ED_spacetype_topbar(void) BLI_addhead(&st->regiontypes, art); recent_files_menu_register(); + undo_history_menu_register(); BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index b79303551a1..5451aa5a2e0 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -1552,7 +1552,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob) PointerRNA pchanptr; uiLayout *col; - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); if (!pchan) { uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index a7d170982ed..b1f19581543 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1581,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) view3d_draw_view(C, region); + DRW_cache_free_old_subdiv(); DRW_cache_free_old_batches(bmain); BKE_image_free_old_gputextures(bmain); GPU_pass_cache_garbage_collect(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 830f7cbeff1..80089815284 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3216,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) if (obact->mode & OB_MODE_POSE) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact); - bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval); + bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval); if (pcham_act) { BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone)); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 83d3286c8b3..31ae8a92f81 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType if (ob) { const bArmature *arm = ob->data; if (arm->drawtype == ARM_B_BONE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && pchan->bone->segments > 1) { return true; } @@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g { ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = BKE_object_pose_armature_get(OBACT(view_layer)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); @@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup } struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata; - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); /* Handles */ for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 8f3d13176a3..4107cc3a71c 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -914,6 +914,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) case TC_SEQ_DATA: special_aftertrans_update__sequencer(C, t); break; + case TC_SEQ_IMAGE_DATA: + special_aftertrans_update__sequencer_image(C, t); + break; case TC_TRACKING_DATA: special_aftertrans_update__movieclip(C, t); break; @@ -930,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t) case TC_OBJECT_TEXSPACE: case TC_PAINT_CURVE_VERTS: case TC_PARTICLE_VERTS: - case TC_SEQ_IMAGE_DATA: case TC_NONE: default: break; diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 5ed8182857d..12f3b39927e 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -304,6 +304,7 @@ void special_aftertrans_update__sequencer(bContext *C, TransInfo *t); /* transform_convert_sequencer_image.c */ void createTransSeqImageData(TransInfo *t); void recalcData_sequencer_image(TransInfo *t); +void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t); /* transform_convert_tracking.c */ void createTransTrackingData(bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 63aada0f797..5d0a3bd9dd1 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) /* Rule: allow multiple Bones * (but they must be selected, and only one ik-solver per chain should get added) */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->layer & arm->layer) { + if (BKE_pose_is_layer_visible(arm, pchan)) { if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) { /* Rule: no IK for solitary (unconnected) bones. */ for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) { diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 1a25cfd1efb..e26172cd764 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t) } if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ - // if (nodeUpdateID(t->scene->nodetree, &mask->id)) - { - WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); - } + WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); } /* TODO: don't key all masks. */ diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index da11666d445..e8cdfaf1f40 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -31,6 +31,7 @@ #include "BKE_context.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "ED_node.h" @@ -246,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t) nodeRemoveNode(bmain, ntree, node, true); } } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(C, bmain, ntree); } } diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c index d5a59885014..3a5770c2863 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.c +++ b/source/blender/editors/transform/transform_convert_sequencer_image.c @@ -38,8 +38,12 @@ #include "SEQ_transform.h" #include "SEQ_utils.h" +#include "ED_keyframing.h" + #include "UI_view2d.h" +#include "RNA_access.h" + #include "transform.h" #include "transform_convert.h" @@ -215,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t) SEQ_relations_invalidate_cache_preprocessed(t->scene, seq); } } + +void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t) +{ + if (t->state == TRANS_CANCEL) { + return; + } + + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + TransData *td = NULL; + TransData2D *td2d = NULL; + int i; + + PointerRNA ptr; + PropertyRNA *prop; + + for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) { + TransDataSeq *tdseq = td->extra; + Sequence *seq = tdseq->seq; + StripTransform *transform = seq->strip->transform; + Scene *scene = t->scene; + + RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr); + + if (t->mode == TFM_ROTATION) { + prop = RNA_struct_find_property(&ptr, "rotation"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + if (t->mode == TFM_TRANSLATION) { + prop = RNA_struct_find_property(&ptr, "offset_x"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + prop = RNA_struct_find_property(&ptr, "offset_y"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + if (t->mode == TFM_RESIZE) { + prop = RNA_struct_find_property(&ptr, "scale_x"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + prop = RNA_struct_find_property(&ptr, "scale_y"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + } +} diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c index dc37f2796bf..f2d0fb7ac2f 100644 --- a/source/blender/editors/transform/transform_convert_tracking.c +++ b/source/blender/editors/transform/transform_convert_tracking.c @@ -29,8 +29,10 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_tracking.h" #include "ED_clip.h" @@ -793,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) /* Tracks can be used for stabilization nodes, * flush update for such nodes. */ - nodeUpdateID(t->scene->nodetree, &clip->id); - WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + if (t->context != NULL) { + Main *bmain = CTX_data_main(C); + BKE_ntree_update_tag_id_changed(bmain, &clip->id); + BKE_ntree_update_main(bmain, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + } } } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index d2e7f9f83df..2ab4cdff5e6 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1042,7 +1042,7 @@ void ElementResize(const TransInfo *t, applyNumInput(&num_evil, values_final_evil); float ratio = values_final_evil[0]; - *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; + *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff; CLAMP_MIN(*td->val, 0.001f); } } diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c index 5f2a2e472c5..84ca5d3ae54 100644 --- a/source/blender/editors/transform/transform_mode_timetranslate.c +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; float val = ival + t->values_final[0]; - float snap_val = val; - snapFrameTransform(t, autosnap, ival, val, &snap_val); + snapFrameTransform(t, autosnap, ival, val, &val); + float delta_x = val - ival; if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) { /* Convert to seconds. */ const Scene *scene = t->scene; const double secf = FPS; - snap_val /= secf; + delta_x /= secf; + val /= secf; } if (autosnap == SACTSNAP_FRAME) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val); } else if (autosnap == SACTSNAP_SECOND) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val); } else if (autosnap == SACTSNAP_TSTEP) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x); } else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x); } } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 19d0c6d39a3..b8b043c650f 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ if (t->spacetype == SPACE_GRAPH) { /* WORKAROUND: * Special case where snapping is done in #recalData. - * Update the header based on the first element. */ + * Update the header based on the #center_local. */ const short autosnap = getAnimEdit_SnapMode(t); - float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; + float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0]; float val = ival + dvec[0]; - snapFrameTransform(t, autosnap, ival, val, &dvec[0]); + snapFrameTransform(t, autosnap, ival, val, &val); + dvec[0] = val - ival; } if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index fa2485c33c2..5ac5bccd69c 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -513,7 +513,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, if (ob) { if (ob->mode & OB_MODE_POSE) { - const bPoseChannel *pchan = BKE_pose_channel_active(ob); + const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) { break; } @@ -1224,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer, float imat[3][3], mat[3][3]; bool ok = false; - if (activeOnly && (pchan = BKE_pose_channel_active(ob))) { + if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) { add_v3_v3(normal, pchan->pose_mat[2]); add_v3_v3(plane, pchan->pose_mat[1]); ok = true; diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 9cdec357afd..40be8e6e641 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -505,9 +505,9 @@ void applySnapping(TransInfo *t, float *vec) if (t->tsnap.targetSnap) { t->tsnap.targetSnap(t); } - } - t->tsnap.last = current; + t->tsnap.last = current; + } if (validSnap(t)) { t->tsnap.applySnap(t, vec); @@ -693,6 +693,15 @@ static void initSnappingMode(TransInfo *t) bm_face_is_snap_target, POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } + else { + /* Ignore hidden geometry in the general case. */ + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled, + POINTER_FROM_UINT(BM_ELEM_HIDDEN)); + } } } else if (t->spacetype == SPACE_SEQ) { diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 350d3a2676c..e3a2d1f6531 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -146,7 +146,7 @@ struct SnapObjectContext { * If NULL the BMesh should be used. */ static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) { - Mesh *me_eval = ob_eval->data; + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); bool use_hide = false; if (BKE_object_is_in_editmode(ob_eval)) { if (edit_mode_type == SNAP_GEOM_EDIT) { diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index aca99f81e7b..c6fa5acfff5 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -64,6 +64,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "UI_interface.h" #include "UI_resources.h" @@ -759,81 +760,16 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un /* -------------------------------------------------------------------- */ /** \name Undo History Operator + * + * See `TOPBAR_MT_undo_history` which is used to access this operator. * \{ */ -/* create enum based on undo items */ -static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) -{ - EnumPropertyItem item_tmp = {0}, *item = NULL; - int i = 0; - - wmWindowManager *wm = CTX_wm_manager(C); - if (wm->undo_stack == NULL) { - return NULL; - } - - for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { - if (us->skip == false) { - item_tmp.identifier = us->name; - item_tmp.name = IFACE_(us->name); - if (us == wm->undo_stack->step_active) { - item_tmp.icon = ICON_LAYER_ACTIVE; - } - else { - item_tmp.icon = ICON_NONE; - } - item_tmp.value = i; - RNA_enum_item_add(&item, totitem, &item_tmp); - } - } - RNA_enum_item_end(&item, totitem); - - return item; -} - -static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) -{ - int totitem = 0; - - { - const EnumPropertyItem *item = rna_undo_itemf(C, &totitem); - - if (totitem > 0) { - uiPopupMenu *pup = UI_popup_menu_begin( - C, WM_operatortype_name(op->type, op->ptr), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - uiLayout *split = uiLayoutSplit(layout, 0.0f, false); - uiLayout *column = NULL; - const int col_size = 20 + totitem / 12; - int i, c; - bool add_col = true; - - for (c = 0, i = totitem; i--;) { - if (add_col && !(c % col_size)) { - column = uiLayoutColumn(split, false); - add_col = false; - } - if (item[i].identifier) { - uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value); - c++; - add_col = true; - } - } - - MEM_freeN((void *)item); - - UI_popup_menu_end(C, pup); - } - } - return OPERATOR_CANCELLED; -} - /* NOTE: also check #ed_undo_step() in top if you change notifiers. */ static int undo_history_exec(bContext *C, wmOperator *op) { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); if (RNA_property_is_set(op->ptr, prop)) { - int item = RNA_property_int_get(op->ptr, prop); + const int item = RNA_property_int_get(op->ptr, prop); const int ret = ed_undo_step_by_index(C, item, op->reports); if (ret & OPERATOR_FINISHED) { ed_undo_refresh_for_op(C); @@ -845,14 +781,15 @@ static int undo_history_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } -static bool undo_history_poll(bContext *C) +static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { - if (!ed_undo_is_init_and_screenactive_poll(C)) { - return false; + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); + if (RNA_property_is_set(op->ptr, prop)) { + return undo_history_exec(C, op); } - UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; - /* More than just original state entry. */ - return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1; + + WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT); + return OPERATOR_FINISHED; } void ED_OT_undo_history(wmOperatorType *ot) @@ -865,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; - ot->poll = undo_history_poll; + ot->poll = ed_undo_is_init_and_screenactive_poll; RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c index 38ae98c678f..2e983eeff39 100644 --- a/source/blender/editors/util/ed_util_imbuf.c +++ b/source/blender/editors/util/ed_util_imbuf.c @@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event /* XXX node curve integration. */ #if 0 { - ScrArea *sa, *cur = curarea; + ScrArea *area, *cur = curarea; node_curvemap_sample(fp); /* sends global to node editor */ - for (sa = G.curscreen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_NODE) { - areawinset(sa->win); - scrarea_do_windraw(sa); + for (area = G.curscreen->areabase.first; area; area = area->next) { + if (area->spacetype == SPACE_NODE) { + areawinset(area->win); + scrarea_do_windraw(area); } } node_curvemap_sample(NULL); /* clears global in node editor */ @@ -385,12 +385,12 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { - ScrArea *sa = CTX_wm_area(C); - if (sa == NULL) { + ScrArea *area = CTX_wm_area(C); + if (area == NULL) { return; } - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { image_sample_apply(C, op, event); break; @@ -432,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info) info->zfp); if (info->sample_size > 1) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_IMAGE) { + if (area && area->spacetype == SPACE_IMAGE) { const wmWindow *win = CTX_wm_window(C); const wmEvent *event = win->eventstate; @@ -482,11 +482,11 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op) int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *region = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); - if (sa) { - switch (sa->spacetype) { + ScrArea *area = CTX_wm_area(C); + if (area) { + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; if (region->regiontype == RGN_TYPE_WINDOW) { if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) { return OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 342afa847b4..64e1fa2f768 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i if (node && is_image_texture_node(node)) { node->id = &ima->id; - ED_node_tag_update_nodetree(bmain, ma->nodetree, node); + ED_node_tree_propagate_change(NULL, bmain, ma->nodetree); } } diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 0a82c237256..a2d5ffb1392 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -48,6 +48,7 @@ #include "BKE_material.h" #include "BKE_mesh.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_object.h" #include "BKE_scene.h" @@ -415,7 +416,7 @@ Material *BlenderStrokeRenderer::GetStrokeShader(Main *bmain, } nodeSetActive(ntree, output_material); - ntreeUpdateTree(bmain, ntree); + BKE_ntree_update_main_tree(bmain, ntree, nullptr); return ma; } diff --git a/source/blender/freestyle/intern/image/GaussianFilter.h b/source/blender/freestyle/intern/image/GaussianFilter.h index af537cf2d86..f6bfdbd31b0 100644 --- a/source/blender/freestyle/intern/image/GaussianFilter.h +++ b/source/blender/freestyle/intern/image/GaussianFilter.h @@ -123,7 +123,7 @@ class GaussianFilter { template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int y) { - float sum = 0.0f; + // float sum = 0.0f; float L = 0.0f; int w = (int)map->width(); // soc int h = (int)map->height(); // soc @@ -142,7 +142,7 @@ template<class Map> float GaussianFilter::getSmoothedPixel(Map *map, int x, int float tmpL = map->pixel(x + j, y + i); float m = _mask[abs(i) * _storedMaskSize + abs(j)]; L += m * tmpL; - sum += m; + // sum += m; } } // L /= sum; diff --git a/source/blender/freestyle/intern/stroke/Operators.cpp b/source/blender/freestyle/intern/stroke/Operators.cpp index c73bb739e47..cdb85817a85 100644 --- a/source/blender/freestyle/intern/stroke/Operators.cpp +++ b/source/blender/freestyle/intern/stroke/Operators.cpp @@ -885,7 +885,7 @@ static int __recursiveSplit(Chain *_curve, #endif real _min = FLT_MAX; ++it; - real mean = 0.0f; + // real mean = 0.0f; // soc unused - real variance = 0.0f; unsigned count = 0; CurveInternal::CurvePointIterator next = it; @@ -904,14 +904,14 @@ static int __recursiveSplit(Chain *_curve, if (func(it0d) < 0) { return -1; } - mean += func.result; + // mean += func.result; if (func.result < _min) { _min = func.result; split = it; bsplit = true; } } - mean /= (float)count; + // mean /= (float)count; // if ((!bsplit) || (mean - _min > mean)) { // we didn't find any minimum if (!bsplit) { // we didn't find any minimum diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index a591aaed34a..11f8a7e9b94 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -60,11 +60,21 @@ class FieldInput; struct FieldInputs; /** + * Have a fixed set of base node types, because all code that works with field nodes has to + * understand those. + */ +enum class FieldNodeType { + Input, + Operation, + Constant, +}; + +/** * A node in a field-tree. It has at least one output that can be referenced by fields. */ class FieldNode { private: - bool is_input_; + FieldNodeType node_type_; protected: /** @@ -76,14 +86,13 @@ class FieldNode { std::shared_ptr<const FieldInputs> field_inputs_; public: - FieldNode(bool is_input); + FieldNode(FieldNodeType node_type); virtual ~FieldNode() = default; virtual const CPPType &output_cpp_type(int output_index) const = 0; - bool is_input() const; - bool is_operation() const; + FieldNodeType node_type() const; bool depends_on_input() const; const std::shared_ptr<const FieldInputs> &field_inputs() const; @@ -267,6 +276,20 @@ class FieldInput : public FieldNode { const CPPType &output_cpp_type(int output_index) const override; }; +class FieldConstant : public FieldNode { + private: + const CPPType &type_; + void *value_; + + public: + FieldConstant(const CPPType &type, const void *value); + ~FieldConstant(); + + const CPPType &output_cpp_type(int output_index) const override; + const CPPType &type() const; + GPointer value() const; +}; + /** * Keeps track of the inputs of a field. */ @@ -468,9 +491,7 @@ template<typename T> T evaluate_constant_field(const Field<T> &field) template<typename T> Field<T> make_constant_field(T value) { - auto constant_fn = std::make_unique<fn::CustomMF_Constant<T>>(std::forward<T>(value)); - auto operation = std::make_shared<FieldOperation>(std::move(constant_fn)); - return Field<T>{GField{std::move(operation), 0}}; + return make_constant_field(CPPType::get<T>(), &value); } GField make_constant_field(const CPPType &type, const void *value); @@ -552,18 +573,13 @@ template<typename T> struct ValueOrField { /** \name #FieldNode Inline Methods * \{ */ -inline FieldNode::FieldNode(bool is_input) : is_input_(is_input) -{ -} - -inline bool FieldNode::is_input() const +inline FieldNode::FieldNode(const FieldNodeType node_type) : node_type_(node_type) { - return is_input_; } -inline bool FieldNode::is_operation() const +inline FieldNodeType FieldNode::node_type() const { - return !is_input_; + return node_type_; } inline bool FieldNode::depends_on_input() const diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index fc8612d6f87..6aebca51219 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -753,8 +753,7 @@ namespace detail { template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get() { static_assert(std::is_base_of_v<GVArrayImpl, StorageT> || - std::is_same_v<StorageT, const GVArrayImpl *> || - std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>); + is_same_any_v<StorageT, const GVArrayImpl *, std::shared_ptr<const GVArrayImpl>>); if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) { return {[](const void *buffer) { diff --git a/source/blender/functions/FN_multi_function_procedure.hh b/source/blender/functions/FN_multi_function_procedure.hh index a26eb1045a7..d73bc089278 100644 --- a/source/blender/functions/FN_multi_function_procedure.hh +++ b/source/blender/functions/FN_multi_function_procedure.hh @@ -268,6 +268,7 @@ class MFProcedure : NonCopyable, NonMovable { Vector<MFReturnInstruction *> return_instructions_; Vector<MFVariable *> variables_; Vector<MFParameter> params_; + Vector<destruct_ptr<MultiFunction>> owned_functions_; MFInstruction *entry_ = nullptr; friend class MFProcedureDotExport; @@ -284,9 +285,10 @@ class MFProcedure : NonCopyable, NonMovable { MFReturnInstruction &new_return_instruction(); void add_parameter(MFParamType::InterfaceType interface_type, MFVariable &variable); - Span<ConstMFParameter> params() const; + template<typename T, typename... Args> const MultiFunction &construct_function(Args &&...args); + MFInstruction *entry(); const MFInstruction *entry() const; void set_entry(MFInstruction &entry); @@ -550,6 +552,15 @@ inline Span<const MFVariable *> MFProcedure::variables() const return variables_; } +template<typename T, typename... Args> +inline const MultiFunction &MFProcedure::construct_function(Args &&...args) +{ + destruct_ptr<T> fn = allocator_.construct<T>(std::forward<Args>(args)...); + const MultiFunction &fn_ref = *fn; + owned_functions_.append(std::move(fn)); + return fn_ref; +} + /** \} */ } // namespace blender::fn diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 604e5c6d13f..d6b83c42294 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -64,17 +64,26 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields) while (!fields_to_check.is_empty()) { GFieldRef field = fields_to_check.pop(); - if (field.node().is_input()) { - const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); - field_tree_info.deduplicated_field_inputs.add(field_input); - continue; - } - BLI_assert(field.node().is_operation()); - const FieldOperation &operation = static_cast<const FieldOperation &>(field.node()); - for (const GFieldRef operation_input : operation.inputs()) { - field_tree_info.field_users.add(operation_input, field); - if (handled_fields.add(operation_input)) { - fields_to_check.push(operation_input); + const FieldNode &field_node = field.node(); + switch (field_node.node_type()) { + case FieldNodeType::Input: { + const FieldInput &field_input = static_cast<const FieldInput &>(field_node); + field_tree_info.deduplicated_field_inputs.add(field_input); + break; + } + case FieldNodeType::Operation: { + const FieldOperation &operation = static_cast<const FieldOperation &>(field_node); + for (const GFieldRef operation_input : operation.inputs()) { + field_tree_info.field_users.add(operation_input, field); + if (handled_fields.add(operation_input)) { + fields_to_check.push(operation_input); + } + } + break; + } + case FieldNodeType::Constant: { + /* Nothing to do. */ + break; } } } @@ -179,56 +188,71 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, fields_to_check.pop(); continue; } - /* Field inputs should already be handled above. */ - BLI_assert(field.node().is_operation()); - - const FieldOperation &operation = static_cast<const FieldOperation &>(field.node()); - const Span<GField> operation_inputs = operation.inputs(); - - if (field_with_index.current_input_index < operation_inputs.size()) { - /* Not all inputs are handled yet. Push the next input field to the stack and increment the - * input index. */ - fields_to_check.push({operation_inputs[field_with_index.current_input_index]}); - field_with_index.current_input_index++; - } - else { - /* All inputs variables are ready, now gather all variables that are used by the function - * and call it. */ - const MultiFunction &multi_function = operation.multi_function(); - Vector<MFVariable *> variables(multi_function.param_amount()); - - int param_input_index = 0; - int param_output_index = 0; - for (const int param_index : multi_function.param_indices()) { - const MFParamType param_type = multi_function.param_type(param_index); - const MFParamType::InterfaceType interface_type = param_type.interface_type(); - if (interface_type == MFParamType::Input) { - const GField &input_field = operation_inputs[param_input_index]; - variables[param_index] = variable_by_field.lookup(input_field); - param_input_index++; - } - else if (interface_type == MFParamType::Output) { - const GFieldRef output_field{operation, param_output_index}; - const bool output_is_ignored = - field_tree_info.field_users.lookup(output_field).is_empty() && - !output_fields.contains(output_field); - if (output_is_ignored) { - /* Ignored outputs don't need a variable. */ - variables[param_index] = nullptr; - } - else { - /* Create a new variable for used outputs. */ - MFVariable &new_variable = procedure.new_variable(param_type.data_type()); - variables[param_index] = &new_variable; - variable_by_field.add_new(output_field, &new_variable); - } - param_output_index++; + const FieldNode &field_node = field.node(); + switch (field_node.node_type()) { + case FieldNodeType::Input: { + /* Field inputs should already be handled above. */ + break; + } + case FieldNodeType::Operation: { + const FieldOperation &operation_node = static_cast<const FieldOperation &>(field.node()); + const Span<GField> operation_inputs = operation_node.inputs(); + + if (field_with_index.current_input_index < operation_inputs.size()) { + /* Not all inputs are handled yet. Push the next input field to the stack and increment + * the input index. */ + fields_to_check.push({operation_inputs[field_with_index.current_input_index]}); + field_with_index.current_input_index++; } else { - BLI_assert_unreachable(); + /* All inputs variables are ready, now gather all variables that are used by the + * function and call it. */ + const MultiFunction &multi_function = operation_node.multi_function(); + Vector<MFVariable *> variables(multi_function.param_amount()); + + int param_input_index = 0; + int param_output_index = 0; + for (const int param_index : multi_function.param_indices()) { + const MFParamType param_type = multi_function.param_type(param_index); + const MFParamType::InterfaceType interface_type = param_type.interface_type(); + if (interface_type == MFParamType::Input) { + const GField &input_field = operation_inputs[param_input_index]; + variables[param_index] = variable_by_field.lookup(input_field); + param_input_index++; + } + else if (interface_type == MFParamType::Output) { + const GFieldRef output_field{operation_node, param_output_index}; + const bool output_is_ignored = + field_tree_info.field_users.lookup(output_field).is_empty() && + !output_fields.contains(output_field); + if (output_is_ignored) { + /* Ignored outputs don't need a variable. */ + variables[param_index] = nullptr; + } + else { + /* Create a new variable for used outputs. */ + MFVariable &new_variable = procedure.new_variable(param_type.data_type()); + variables[param_index] = &new_variable; + variable_by_field.add_new(output_field, &new_variable); + } + param_output_index++; + } + else { + BLI_assert_unreachable(); + } + } + builder.add_call_with_all_variables(multi_function, variables); } + break; + } + case FieldNodeType::Constant: { + const FieldConstant &constant_node = static_cast<const FieldConstant &>(field_node); + const MultiFunction &fn = procedure.construct_function<CustomMF_GenericConstant>( + constant_node.type(), constant_node.value().get(), false); + MFVariable &new_variable = *builder.add_call<1>(fn)[0]; + variable_by_field.add_new(field, &new_variable); + break; } - builder.add_call_with_all_variables(multi_function, variables); } } } @@ -301,17 +325,29 @@ Vector<GVArray> evaluate_fields(ResourceScope &scope, Vector<GVArray> field_context_inputs = get_field_context_inputs( scope, mask, context, field_tree_info.deduplicated_field_inputs); - /* Finish fields that output an input varray directly. For those we don't have to do any further - * processing. */ + /* Finish fields that don't need any processing directly. */ for (const int out_index : fields_to_evaluate.index_range()) { const GFieldRef &field = fields_to_evaluate[out_index]; - if (!field.node().is_input()) { - continue; + const FieldNode &field_node = field.node(); + switch (field_node.node_type()) { + case FieldNodeType::Input: { + const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); + const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of( + field_input); + const GVArray &varray = field_context_inputs[field_input_index]; + r_varrays[out_index] = varray; + break; + } + case FieldNodeType::Constant: { + const FieldConstant &field_constant = static_cast<const FieldConstant &>(field.node()); + r_varrays[out_index] = GVArray::ForSingleRef( + field_constant.type(), mask.min_array_size(), field_constant.value().get()); + break; + } + case FieldNodeType::Operation: { + break; + } } - const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); - const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input); - const GVArray &varray = field_context_inputs[field_input_index]; - r_varrays[out_index] = varray; } Set<GFieldRef> varying_fields = find_varying_fields(field_tree_info, field_context_inputs); @@ -491,9 +527,8 @@ GField make_field_constant_if_possible(GField field) GField make_constant_field(const CPPType &type, const void *value) { - auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true); - auto operation = std::make_shared<FieldOperation>(std::move(constant_fn)); - return GField{std::move(operation), 0}; + auto constant_node = std::make_shared<FieldConstant>(type, value); + return GField{std::move(constant_node)}; } GVArray FieldContext::get_varray_for_input(const FieldInput &field_input, @@ -602,7 +637,7 @@ static std::shared_ptr<const FieldInputs> combine_field_inputs(Span<GField> fiel } FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inputs) - : FieldNode(false), function_(&function), inputs_(std::move(inputs)) + : FieldNode(FieldNodeType::Operation), function_(&function), inputs_(std::move(inputs)) { field_inputs_ = combine_field_inputs(inputs_); } @@ -612,7 +647,7 @@ FieldOperation::FieldOperation(const MultiFunction &function, Vector<GField> inp */ FieldInput::FieldInput(const CPPType &type, std::string debug_name) - : FieldNode(true), type_(&type), debug_name_(std::move(debug_name)) + : FieldNode(FieldNodeType::Input), type_(&type), debug_name_(std::move(debug_name)) { std::shared_ptr<FieldInputs> field_inputs = std::make_shared<FieldInputs>(); field_inputs->nodes.add_new(this); @@ -621,6 +656,40 @@ FieldInput::FieldInput(const CPPType &type, std::string debug_name) } /* -------------------------------------------------------------------- + * FieldConstant. + */ + +FieldConstant::FieldConstant(const CPPType &type, const void *value) + : FieldNode(FieldNodeType::Constant), type_(type) +{ + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_construct(value, value_); +} + +FieldConstant::~FieldConstant() +{ + type_.destruct(value_); + MEM_freeN(value_); +} + +const CPPType &FieldConstant::output_cpp_type(int output_index) const +{ + BLI_assert(output_index == 0); + UNUSED_VARS_NDEBUG(output_index); + return type_; +} + +const CPPType &FieldConstant::type() const +{ + return type_; +} + +GPointer FieldConstant::value() const +{ + return {type_, value_}; +} + +/* -------------------------------------------------------------------- * FieldEvaluator. */ diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 0cbec35ec7a..965c09984fa 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -16,6 +16,7 @@ #include "BLI_array.hh" #include "BLI_set.hh" +#include "BLI_string_ref.hh" #include "BLI_task.hh" #include "DNA_mesh_types.h" @@ -41,11 +42,22 @@ static void copy_attribute_to_points(const VArray<T> &source_data, } } -static void copy_attributes_to_points(CurveEval &curve, - const MeshComponent &mesh_component, - Span<Vector<int>> point_to_vert_maps) +static std::unique_ptr<CurveEval> create_curve_from_vert_indices( + const MeshComponent &mesh_component, Span<Vector<int>> vert_indices, IndexRange cyclic_splines) { - MutableSpan<SplinePtr> splines = curve.splines(); + std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); + curve->resize(vert_indices.size()); + + MutableSpan<SplinePtr> splines = curve->splines(); + + for (const int i : vert_indices.index_range()) { + splines[i] = std::make_unique<PolySpline>(); + splines[i]->resize(vert_indices[i].size()); + } + for (const int i : cyclic_splines) { + splines[i]->set_cyclic(true); + } + Set<bke::AttributeIDRef> source_attribute_ids = mesh_component.attribute_ids(); /* Copy builtin control point attributes. */ @@ -54,27 +66,44 @@ static void copy_attributes_to_points(CurveEval &curve, "tilt", ATTR_DOMAIN_POINT, 0.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { - copy_attribute_to_points<float>( - tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); + copy_attribute_to_points<float>(tilt_attribute, vert_indices[i], splines[i]->tilts()); } }); source_attribute_ids.remove_contained("tilt"); } + else { + for (SplinePtr &spline : splines) { + spline->tilts().fill(0.0f); + } + } + if (source_attribute_ids.contains("radius")) { const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>( "radius", ATTR_DOMAIN_POINT, 1.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { - copy_attribute_to_points<float>( - radius_attribute, point_to_vert_maps[i], splines[i]->radii()); + copy_attribute_to_points<float>(radius_attribute, vert_indices[i], splines[i]->radii()); } }); source_attribute_ids.remove_contained("radius"); } + else { + for (SplinePtr &spline : splines) { + spline->radii().fill(1.0f); + } + } + + VArray<float3> mesh_positions = mesh_component.attribute_get_for_read( + "position", ATTR_DOMAIN_POINT, float3(0)); + threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { + for (const int i : range) { + copy_attribute_to_points(mesh_positions, vert_indices[i], splines[i]->positions()); + } + }); for (const bke::AttributeIDRef &attribute_id : source_attribute_ids) { - /* Don't copy attributes that are built-in on meshes but not on curves. */ if (mesh_component.attribute_is_builtin(attribute_id)) { + /* Don't copy attributes that are built-in on meshes but not on curves. */ continue; } @@ -104,24 +133,27 @@ static void copy_attributes_to_points(CurveEval &curve, attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); copy_attribute_to_points<T>( - mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); + mesh_attribute.typed<T>(), vert_indices[i], spline_attribute->typed<T>()); }); } }); } - curve.assert_valid_point_attributes(); + curve->assert_valid_point_attributes(); + return curve; } struct CurveFromEdgesOutput { - std::unique_ptr<CurveEval> curve; - Vector<Vector<int>> point_to_vert_maps; + /** The indices in the mesh for each control point of each result splines. */ + Vector<Vector<int>> vert_indices; + /** A subset of splines that should be set cyclic. */ + IndexRange cyclic_splines; }; -static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges) +static CurveFromEdgesOutput edges_to_curve_point_indices(Span<MVert> verts, + Span<std::pair<int, int>> edges) { - std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); - Vector<Vector<int>> point_to_vert_maps; + Vector<Vector<int>> vert_indices; /* Compute the number of edges connecting to each vertex. */ Array<int> neighbor_count(verts.size(), 0); @@ -173,19 +205,15 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int continue; } - std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); - Vector<int> point_to_vert_map; - - spline->add_point(verts[current_vert].co, 1.0f, 0.0f); - point_to_vert_map.append(current_vert); + Vector<int> spline_indices; + spline_indices.append(current_vert); /* Follow connected edges until we read a vertex with more than two connected edges. */ while (true) { int last_vert = current_vert; current_vert = next_vert; - spline->add_point(verts[current_vert].co, 1.0f, 0.0f); - point_to_vert_map.append(current_vert); + spline_indices.append(current_vert); unused_edges[current_vert]--; unused_edges[last_vert]--; @@ -199,12 +227,13 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int next_vert = (last_vert == next_a) ? next_b : next_a; } - spline->attributes.reallocate(spline->size()); - curve->add_spline(std::move(spline)); - point_to_vert_maps.append(std::move(point_to_vert_map)); + vert_indices.append(std::move(spline_indices)); } } + /* All splines added after this are cyclic. */ + const int cyclic_start = vert_indices.size(); + /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */ for (const int start_vert : verts.index_range()) { if (unused_edges[start_vert] != 2) { @@ -214,20 +243,16 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int int current_vert = start_vert; int next_vert = neighbors[neighbor_offsets[current_vert]]; - std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); - Vector<int> point_to_vert_map; - spline->set_cyclic(true); + Vector<int> spline_indices; - spline->add_point(verts[current_vert].co, 1.0f, 0.0f); - point_to_vert_map.append(current_vert); + spline_indices.append(current_vert); /* Follow connected edges until we loop back to the start vertex. */ while (next_vert != start_vert) { const int last_vert = current_vert; current_vert = next_vert; - spline->add_point(verts[current_vert].co, 1.0f, 0.0f); - point_to_vert_map.append(current_vert); + spline_indices.append(current_vert); unused_edges[current_vert]--; unused_edges[last_vert]--; @@ -237,13 +262,12 @@ static CurveFromEdgesOutput edges_to_curve(Span<MVert> verts, Span<std::pair<int next_vert = (last_vert == next_a) ? next_b : next_a; } - spline->attributes.reallocate(spline->size()); - curve->add_spline(std::move(spline)); - point_to_vert_maps.append(std::move(point_to_vert_map)); + vert_indices.append(std::move(spline_indices)); } - curve->attributes.reallocate(curve->splines().size()); - return {std::move(curve), std::move(point_to_vert_maps)}; + const int final_size = vert_indices.size(); + + return {std::move(vert_indices), IndexRange(cyclic_start, final_size - cyclic_start)}; } /** @@ -266,9 +290,11 @@ std::unique_ptr<CurveEval> mesh_to_curve_convert(const MeshComponent &mesh_compo const Mesh &mesh = *mesh_component.get_for_read(); Vector<std::pair<int, int>> selected_edges = get_selected_edges(*mesh_component.get_for_read(), selection); - CurveFromEdgesOutput output = edges_to_curve({mesh.mvert, mesh.totvert}, selected_edges); - copy_attributes_to_points(*output.curve, mesh_component, output.point_to_vert_maps); - return std::move(output.curve); + CurveFromEdgesOutput output = edges_to_curve_point_indices({mesh.mvert, mesh.totvert}, + selected_edges); + + return create_curve_from_vert_indices( + mesh_component, output.vert_indices, output.cyclic_splines); } } // namespace blender::geometry diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc index ae513bf88e9..4022794d53f 100644 --- a/source/blender/geometry/intern/realize_instances.cc +++ b/source/blender/geometry/intern/realize_instances.cc @@ -1167,7 +1167,7 @@ static void execute_realize_curve_task(const RealizeInstancesOptions &options, const AttributeIDRef &attribute_id = ordered_attributes.ids[attribute_index]; const void *attribute_fallback = task.attribute_fallbacks.array[attribute_index]; const std::optional<GSpan> src_span_opt = src_point_attributes.get_for_read(attribute_id); - void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), __func__); + void *dst_buffer = MEM_malloc_arrayN(spline_size, cpp_type.size(), "Curve Attribute"); if (src_span_opt.has_value()) { const GSpan src_span = *src_span_opt; cpp_type.copy_construct_n(src_span.data(), dst_buffer, spline_size); diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c index f6a85919de4..c583a45a27d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.c @@ -40,6 +40,8 @@ #include "MOD_gpencil_modifiertypes.h" #include "MOD_gpencil_util.h" +#include "DEG_depsgraph_query.h" + void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) { #define INIT_GP_TYPE(typeName) \ @@ -73,7 +75,7 @@ void gpencil_modifier_type_init(GpencilModifierTypeInfo *types[]) bool is_stroke_affected_by_modifier(Object *ob, char *mlayername, - const Material *material, + Material *material, const int mpassindex, const int gpl_passindex, const int minpoints, @@ -84,8 +86,8 @@ bool is_stroke_affected_by_modifier(Object *ob, const bool inv3, const bool inv4) { - Material *ma = BKE_gpencil_material(ob, gps->mat_nr + 1); - MaterialGPencilStyle *gp_style = ma->gp_style; + Material *ma_gps = BKE_gpencil_material(ob, gps->mat_nr + 1); + MaterialGPencilStyle *gp_style = ma_gps->gp_style; /* omit if filter by layer */ if (mlayername[0] != '\0') { @@ -102,13 +104,16 @@ bool is_stroke_affected_by_modifier(Object *ob, } /* Omit if filter by material. */ if (material != NULL) { + /* Requires to use the original material to compare the same pointer address. */ + Material *ma_md_orig = (Material *)DEG_get_original_id(&material->id); + Material *ma_gps_orig = (Material *)DEG_get_original_id(&ma_gps->id); if (inv4 == false) { - if (material != ma) { + if (ma_md_orig != ma_gps_orig) { return false; } } else { - if (material == ma) { + if (ma_md_orig == ma_gps_orig) { return false; } } diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h index 59ed11a02f3..722574929c0 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_util.h @@ -34,7 +34,7 @@ struct bGPDstroke; */ bool is_stroke_affected_by_modifier(struct Object *ob, char *mlayername, - const struct Material *material, + struct Material *material, const int mpassindex, const int gpl_passindex, const int minpoints, diff --git a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h index 2ef72da03fd..dadeebeff0a 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h +++ b/source/blender/gpencil_modifiers/intern/lineart/MOD_lineart.h @@ -450,10 +450,10 @@ typedef struct LineartBoundingArea { ListBase up; ListBase bp; - int16_t triangle_count; - int16_t max_triangle_count; - int16_t line_count; - int16_t max_line_count; + uint16_t triangle_count; + uint16_t max_triangle_count; + uint16_t line_count; + uint16_t max_line_count; /* Use array for speeding up multiple accesses. */ struct LineartTriangle **linked_triangles; diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index d9a32711833..2f82a22754d 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -327,7 +327,12 @@ BLI_INLINE bool lineart_occlusion_is_adjacent_intersection(LineartEdge *e, Linea static void lineart_bounding_area_triangle_add(LineartRenderBuffer *rb, LineartBoundingArea *ba, LineartTriangle *tri) -{ +{ /* In case of too many triangles concentrating in one point, do not add anymore, these triangles + * will be either narrower than a single pixel, or will still be added into the list of other + * less dense areas. */ + if (ba->triangle_count >= 65535) { + return; + } if (ba->triangle_count >= ba->max_triangle_count) { LineartTriangle **new_array = lineart_mem_acquire( &rb->render_data_pool, sizeof(LineartTriangle *) * ba->max_triangle_count * 2); @@ -343,6 +348,12 @@ static void lineart_bounding_area_line_add(LineartRenderBuffer *rb, LineartBoundingArea *ba, LineartEdge *e) { + /* In case of too many lines concentrating in one point, do not add anymore, these lines will + * be either shorter than a single pixel, or will still be added into the list of other less + * dense areas. */ + if (ba->line_count >= 65535) { + return; + } if (ba->line_count >= ba->max_line_count) { LineartEdge **new_array = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartEdge *) * ba->max_line_count * 2); @@ -1959,13 +1970,12 @@ static uchar lineart_intersection_mask_check(Collection *c, Object *ob) } } - if (c->children.first == NULL) { - if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) { - if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) { - return c->lineart_intersection_mask; - } + if (BKE_collection_has_object(c, (Object *)(ob->id.orig_id))) { + if (c->lineart_flags & COLLECTION_LRT_USE_INTERSECTION_MASK) { + return c->lineart_intersection_mask; } } + return 0; } @@ -2574,8 +2584,12 @@ static bool lineart_triangle_edge_image_space_occlusion(SpinLock *UNUSED(spl), INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); } else { - INTERSECT_JUST_GREATER(is, order, is[LCross], LCross); - INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + if (LCross >= 0) { + INTERSECT_JUST_GREATER(is, order, is[LCross], LCross); + if (LCross >= 0) { + INTERSECT_JUST_GREATER(is, order, is[LCross], RCross); + } + } } } } @@ -2930,15 +2944,7 @@ static LineartEdge *lineart_triangle_intersect(LineartRenderBuffer *rb, result->intersection_mask = (tri->intersection_mask | testing->intersection_mask); lineart_prepend_edge_direct(&rb->intersection.first, result); - int r1, r2, c1, c2, row, col; - if (lineart_get_edge_bounding_areas(rb, result, &r1, &r2, &c1, &c2)) { - for (row = r1; row != r2 + 1; row++) { - for (col = c1; col != c2 + 1; col++) { - lineart_bounding_area_link_edge( - rb, &rb->initial_bounding_areas[row * LRT_BA_ROWS + col], result); - } - } - } + return result; } @@ -3409,7 +3415,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb, LineartBoundingArea *ba = lineart_mem_acquire(&rb->render_data_pool, sizeof(LineartBoundingArea) * 4); LineartTriangle *tri; - LineartEdge *e; ba[0].l = root->cx; ba[0].r = root->r; @@ -3475,11 +3480,6 @@ static void lineart_bounding_area_split(LineartRenderBuffer *rb, } } - for (int i = 0; i < root->line_count; i++) { - e = root->linked_lines[i]; - lineart_bounding_area_link_edge(rb, root, e); - } - rb->bounding_area_count += 3; } diff --git a/source/blender/gpu/GPU_context.h b/source/blender/gpu/GPU_context.h index 5189fa1ae41..5e67441be27 100644 --- a/source/blender/gpu/GPU_context.h +++ b/source/blender/gpu/GPU_context.h @@ -40,6 +40,8 @@ typedef enum eGPUBackendType { void GPU_backend_init(eGPUBackendType backend); void GPU_backend_exit(void); +eGPUBackendType GPU_backend_get_type(void); + /** Opaque type hiding blender::gpu::Context. */ typedef struct GPUContext GPUContext; diff --git a/source/blender/gpu/GPU_index_buffer.h b/source/blender/gpu/GPU_index_buffer.h index e4f1709173e..0f83e590597 100644 --- a/source/blender/gpu/GPU_index_buffer.h +++ b/source/blender/gpu/GPU_index_buffer.h @@ -53,6 +53,8 @@ void GPU_indexbuf_init_ex(GPUIndexBufBuilder *, GPUPrimType, uint index_len, uin void GPU_indexbuf_init(GPUIndexBufBuilder *, GPUPrimType, uint prim_len, uint vertex_len); GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len); +void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len); + /* * Thread safe. * @@ -82,6 +84,16 @@ void GPU_indexbuf_build_in_place(GPUIndexBufBuilder *, GPUIndexBuf *); void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding); +/* Upload data to the GPU (if not built on the device) and bind the buffer to its default target. + */ +void GPU_indexbuf_use(GPUIndexBuf *elem); + +/* Partially update the GPUIndexBuf which was already sent to the device, or built directly on the + * device. The data needs to be compatible with potential compression applied to the original + * indices when the index buffer was built, i.e., if the data was compressed to use shorts instead + * of ints, shorts should passed here. */ +void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data); + /* Create a sub-range of an existing index-buffer. */ GPUIndexBuf *GPU_indexbuf_create_subrange(GPUIndexBuf *elem_src, uint start, uint length); void GPU_indexbuf_create_subrange_in_place(GPUIndexBuf *elem, diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index ea3028e539b..f7a01fadadc 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -24,6 +24,7 @@ #pragma once #include "DNA_customdata_types.h" /* for CustomDataType */ +#include "DNA_image_types.h" #include "DNA_listBase.h" #include "BLI_sys_types.h" /* for bool */ @@ -256,7 +257,8 @@ typedef struct GPUMaterialAttribute { typedef struct GPUMaterialTexture { struct GPUMaterialTexture *next, *prev; struct Image *ima; - struct ImageUser *iuser; + struct ImageUser iuser; + bool iuser_available; struct GPUTexture **colorband; char sampler_name[32]; /* Name of sampler in GLSL. */ char tiled_mapping_name[32]; /* Name of tile mapping sampler in GLSL. */ diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index fa70a8934db..7b69012dcbc 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -40,9 +40,11 @@ typedef enum eGPUBarrier { GPU_BARRIER_SHADER_IMAGE_ACCESS = (1 << 0), GPU_BARRIER_TEXTURE_FETCH = (1 << 1), GPU_BARRIER_SHADER_STORAGE = (1 << 2), + GPU_BARRIER_VERTEX_ATTRIB_ARRAY = (1 << 3), + GPU_BARRIER_ELEMENT_ARRAY = (1 << 4), } eGPUBarrier; -ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_SHADER_STORAGE) +ENUM_OPERATORS(eGPUBarrier, GPU_BARRIER_ELEMENT_ARRAY) /** * Defines the fixed pipeline blending equation. diff --git a/source/blender/gpu/GPU_vertex_buffer.h b/source/blender/gpu/GPU_vertex_buffer.h index 62a495abfb3..43a8e7fc4cb 100644 --- a/source/blender/gpu/GPU_vertex_buffer.h +++ b/source/blender/gpu/GPU_vertex_buffer.h @@ -91,6 +91,8 @@ void GPU_vertbuf_handle_ref_remove(GPUVertBuf *verts); void GPU_vertbuf_init_with_format_ex(GPUVertBuf *, const GPUVertFormat *, GPUUsageType); +void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len); + #define GPU_vertbuf_init_with_format(verts, format) \ GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_STATIC) @@ -172,6 +174,7 @@ const GPUVertFormat *GPU_vertbuf_get_format(const GPUVertBuf *verts); uint GPU_vertbuf_get_vertex_alloc(const GPUVertBuf *verts); uint GPU_vertbuf_get_vertex_len(const GPUVertBuf *verts); GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts); +void GPU_vertbuf_tag_dirty(GPUVertBuf *verts); /** * Should be rename to #GPU_vertbuf_data_upload. @@ -179,12 +182,14 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts); void GPU_vertbuf_use(GPUVertBuf *); void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding); +void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle); + /** * XXX: do not use! * This is just a wrapper for the use of the Hair refine workaround. * To be used with #GPU_vertbuf_use(). */ -void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data); +void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data); /* Metrics */ uint GPU_vertbuf_get_memory_usage(void); diff --git a/source/blender/gpu/intern/gpu_context.cc b/source/blender/gpu/intern/gpu_context.cc index 5af15d1bc3d..98714269402 100644 --- a/source/blender/gpu/intern/gpu_context.cc +++ b/source/blender/gpu/intern/gpu_context.cc @@ -186,6 +186,15 @@ void GPU_backend_exit() g_backend = nullptr; } +eGPUBackendType GPU_backend_get_type() +{ + if (g_backend && dynamic_cast<GLBackend *>(g_backend) != nullptr) { + return GPU_BACKEND_OPENGL; + } + + return GPU_BACKEND_NONE; +} + GPUBackend *GPUBackend::get() { return g_backend; diff --git a/source/blender/gpu/intern/gpu_framebuffer.cc b/source/blender/gpu/intern/gpu_framebuffer.cc index 3404eb67e28..5b1eac2e82f 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.cc +++ b/source/blender/gpu/intern/gpu_framebuffer.cc @@ -563,7 +563,7 @@ static GPUFrameBuffer *gpu_offscreen_fb_get(GPUOffScreen *ofs) GPUOffScreen *GPU_offscreen_create( int width, int height, bool depth, eGPUTextureFormat format, char err_out[256]) { - GPUOffScreen *ofs = (GPUOffScreen *)MEM_callocN(sizeof(GPUOffScreen), __func__); + GPUOffScreen *ofs = MEM_cnew<GPUOffScreen>(__func__); /* Sometimes areas can have 0 height or width and this will * create a 1D texture which we don't want. */ diff --git a/source/blender/gpu/intern/gpu_index_buffer.cc b/source/blender/gpu/intern/gpu_index_buffer.cc index 3472cc24a74..895b2a8461b 100644 --- a/source/blender/gpu/intern/gpu_index_buffer.cc +++ b/source/blender/gpu/intern/gpu_index_buffer.cc @@ -74,11 +74,16 @@ void GPU_indexbuf_init(GPUIndexBufBuilder *builder, GPUIndexBuf *GPU_indexbuf_build_on_device(uint index_len) { GPUIndexBuf *elem_ = GPU_indexbuf_calloc(); - IndexBuf *elem = unwrap(elem_); - elem->init_build_on_device(index_len); + GPU_indexbuf_init_build_on_device(elem_, index_len); return elem_; } +void GPU_indexbuf_init_build_on_device(GPUIndexBuf *elem, uint index_len) +{ + IndexBuf *elem_ = unwrap(elem); + elem_->init_build_on_device(index_len); +} + void GPU_indexbuf_join(GPUIndexBufBuilder *builder_to, const GPUIndexBufBuilder *builder_from) { BLI_assert(builder_to->data == builder_from->data); @@ -410,9 +415,19 @@ int GPU_indexbuf_primitive_len(GPUPrimType prim_type) return indices_per_primitive(prim_type); } +void GPU_indexbuf_use(GPUIndexBuf *elem) +{ + unwrap(elem)->upload_data(); +} + void GPU_indexbuf_bind_as_ssbo(GPUIndexBuf *elem, int binding) { unwrap(elem)->bind_as_ssbo(binding); } +void GPU_indexbuf_update_sub(GPUIndexBuf *elem, uint start, uint len, const void *data) +{ + unwrap(elem)->update_sub(start, len, data); +} + /** \} */ diff --git a/source/blender/gpu/intern/gpu_index_buffer_private.hh b/source/blender/gpu/intern/gpu_index_buffer_private.hh index ed7dd830c8c..adc0145f867 100644 --- a/source/blender/gpu/intern/gpu_index_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_index_buffer_private.hh @@ -92,11 +92,15 @@ class IndexBuf { return is_init_; }; + virtual void upload_data(void) = 0; + virtual void bind_as_ssbo(uint binding) = 0; virtual const uint32_t *read() const = 0; uint32_t *unmap(const uint32_t *mapped_memory) const; + virtual void update_sub(uint start, uint len, const void *data) = 0; + private: inline void squeeze_indices_short(uint min_idx, uint max_idx); inline uint index_range(uint *r_min, uint *r_max); diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index 50ff450ac79..e0d60aa5fda 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -439,7 +439,10 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, if (tex == NULL) { tex = MEM_callocN(sizeof(*tex), __func__); tex->ima = ima; - tex->iuser = iuser; + if (iuser != NULL) { + tex->iuser = *iuser; + tex->iuser_available = true; + } tex->colorband = colorband; tex->sampler_state = sampler_state; BLI_snprintf(tex->sampler_name, sizeof(tex->sampler_name), "samp%d", num_textures); diff --git a/source/blender/gpu/intern/gpu_shader.cc b/source/blender/gpu/intern/gpu_shader.cc index 1b6cb196534..3f5a639d2a0 100644 --- a/source/blender/gpu/intern/gpu_shader.cc +++ b/source/blender/gpu/intern/gpu_shader.cc @@ -339,7 +339,7 @@ void GPU_shader_bind(GPUShader *gpu_shader) } } -void GPU_shader_unbind(void) +void GPU_shader_unbind() { #ifndef NDEBUG Context *ctx = Context::get(); diff --git a/source/blender/gpu/intern/gpu_shader_interface.cc b/source/blender/gpu/intern/gpu_shader_interface.cc index 1648446d21b..937f49ccaec 100644 --- a/source/blender/gpu/intern/gpu_shader_interface.cc +++ b/source/blender/gpu/intern/gpu_shader_interface.cc @@ -74,6 +74,8 @@ void ShaderInterface::sort_inputs() sort_input_list(MutableSpan<ShaderInput>(inputs_, attr_len_)); sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_, ubo_len_)); sort_input_list(MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_, uniform_len_)); + sort_input_list( + MutableSpan<ShaderInput>(inputs_ + attr_len_ + ubo_len_ + uniform_len_, ssbo_len_)); } void ShaderInterface::debug_print() diff --git a/source/blender/gpu/intern/gpu_texture.cc b/source/blender/gpu/intern/gpu_texture.cc index c7e2043b790..1b8b28bf04c 100644 --- a/source/blender/gpu/intern/gpu_texture.cc +++ b/source/blender/gpu/intern/gpu_texture.cc @@ -190,7 +190,7 @@ using namespace blender::gpu; /* ------ Memory Management ------ */ -uint GPU_texture_memory_usage_get(void) +uint GPU_texture_memory_usage_get() { /* TODO(fclem): Do that inside the new Texture class. */ return 0; @@ -424,7 +424,7 @@ void GPU_texture_unbind(GPUTexture *tex_) Context::get()->state_manager->texture_unbind(tex); } -void GPU_texture_unbind_all(void) +void GPU_texture_unbind_all() { Context::get()->state_manager->texture_unbind_all(); } @@ -439,7 +439,7 @@ void GPU_texture_image_unbind(GPUTexture *tex) Context::get()->state_manager->image_unbind(unwrap(tex)); } -void GPU_texture_image_unbind_all(void) +void GPU_texture_image_unbind_all() { Context::get()->state_manager->image_unbind_all(); } @@ -613,7 +613,7 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *r_size) * Override texture sampler state for one sampler unit only. * \{ */ -void GPU_samplers_update(void) +void GPU_samplers_update() { GPUBackend::get()->samplers_update(); } diff --git a/source/blender/gpu/intern/gpu_vertex_buffer.cc b/source/blender/gpu/intern/gpu_vertex_buffer.cc index 5ed9648387f..dba31f501f2 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer.cc +++ b/source/blender/gpu/intern/gpu_vertex_buffer.cc @@ -144,6 +144,12 @@ void GPU_vertbuf_init_with_format_ex(GPUVertBuf *verts_, unwrap(verts_)->init(format, usage); } +void GPU_vertbuf_init_build_on_device(GPUVertBuf *verts, GPUVertFormat *format, uint v_len) +{ + GPU_vertbuf_init_with_format_ex(verts, format, GPU_USAGE_DEVICE_ONLY); + GPU_vertbuf_data_alloc(verts, v_len); +} + GPUVertBuf *GPU_vertbuf_duplicate(GPUVertBuf *verts_) { return wrap(unwrap(verts_)->duplicate()); @@ -313,6 +319,11 @@ GPUVertBufStatus GPU_vertbuf_get_status(const GPUVertBuf *verts) return unwrap(verts)->flag; } +void GPU_vertbuf_tag_dirty(GPUVertBuf *verts) +{ + unwrap(verts)->flag |= GPU_VERTBUF_DATA_DIRTY; +} + uint GPU_vertbuf_get_memory_usage() { return VertBuf::memory_usage; @@ -323,12 +334,17 @@ void GPU_vertbuf_use(GPUVertBuf *verts) unwrap(verts)->upload(); } +void GPU_vertbuf_wrap_handle(GPUVertBuf *verts, uint64_t handle) +{ + unwrap(verts)->wrap_handle(handle); +} + void GPU_vertbuf_bind_as_ssbo(struct GPUVertBuf *verts, int binding) { unwrap(verts)->bind_as_ssbo(binding); } -void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, void *data) +void GPU_vertbuf_update_sub(GPUVertBuf *verts, uint start, uint len, const void *data) { unwrap(verts)->update_sub(start, len, data); } diff --git a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh index 9531c2c1a5f..2f46295f45a 100644 --- a/source/blender/gpu/intern/gpu_vertex_buffer_private.hh +++ b/source/blender/gpu/intern/gpu_vertex_buffer_private.hh @@ -68,6 +68,8 @@ class VertBuf { void upload(void); virtual void bind_as_ssbo(uint binding) = 0; + virtual void wrap_handle(uint64_t handle) = 0; + VertBuf *duplicate(void); /* Size of the data allocated. */ @@ -96,7 +98,7 @@ class VertBuf { } } - virtual void update_sub(uint start, uint len, void *data) = 0; + virtual void update_sub(uint start, uint len, const void *data) = 0; virtual const void *read() const = 0; virtual void *unmap(const void *mapped_data) const = 0; diff --git a/source/blender/gpu/opengl/gl_index_buffer.cc b/source/blender/gpu/opengl/gl_index_buffer.cc index e305f765ad9..82bab460ae3 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.cc +++ b/source/blender/gpu/opengl/gl_index_buffer.cc @@ -81,4 +81,14 @@ bool GLIndexBuf::is_active() const return ibo_id_ == active_ibo_id; } +void GLIndexBuf::upload_data() +{ + bind(); +} + +void GLIndexBuf::update_sub(uint start, uint len, const void *data) +{ + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, start, len, data); +} + } // namespace blender::gpu diff --git a/source/blender/gpu/opengl/gl_index_buffer.hh b/source/blender/gpu/opengl/gl_index_buffer.hh index 0dbdaa6d398..85d52447bc6 100644 --- a/source/blender/gpu/opengl/gl_index_buffer.hh +++ b/source/blender/gpu/opengl/gl_index_buffer.hh @@ -61,6 +61,10 @@ class GLIndexBuf : public IndexBuf { return (index_type_ == GPU_INDEX_U16) ? 0xFFFFu : 0xFFFFFFFFu; } + void upload_data(void) override; + + void update_sub(uint start, uint len, const void *data) override; + private: bool is_active() const; diff --git a/source/blender/gpu/opengl/gl_shader.cc b/source/blender/gpu/opengl/gl_shader.cc index cd2c3caad46..8367b0de02b 100644 --- a/source/blender/gpu/opengl/gl_shader.cc +++ b/source/blender/gpu/opengl/gl_shader.cc @@ -47,7 +47,7 @@ GLShader::GLShader(const char *name) : Shader(name) { #if 0 /* Would be nice to have, but for now the Deferred compilation \ * does not have a GPUContext. */ - BLI_assert(GLContext::get() != NULL); + BLI_assert(GLContext::get() != nullptr); #endif shader_program_ = glCreateProgram(); @@ -58,7 +58,7 @@ GLShader::~GLShader() { #if 0 /* Would be nice to have, but for now the Deferred compilation \ * does not have a GPUContext. */ - BLI_assert(GLContext::get() != NULL); + BLI_assert(GLContext::get() != nullptr); #endif /* Invalid handles are silently ignored. */ glDeleteShader(vert_shader_); diff --git a/source/blender/gpu/opengl/gl_state.hh b/source/blender/gpu/opengl/gl_state.hh index 979644b41c9..f5c38a33628 100644 --- a/source/blender/gpu/opengl/gl_state.hh +++ b/source/blender/gpu/opengl/gl_state.hh @@ -130,6 +130,12 @@ static inline GLbitfield to_gl(eGPUBarrier barrier_bits) if (barrier_bits & GPU_BARRIER_SHADER_STORAGE) { barrier |= GL_SHADER_STORAGE_BARRIER_BIT; } + if (barrier_bits & GPU_BARRIER_VERTEX_ATTRIB_ARRAY) { + barrier |= GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT; + } + if (barrier_bits & GPU_BARRIER_ELEMENT_ARRAY) { + barrier |= GL_ELEMENT_ARRAY_BARRIER_BIT; + } return barrier; } diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.cc b/source/blender/gpu/opengl/gl_vertex_buffer.cc index ce16a491528..469ac2cf8d6 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.cc +++ b/source/blender/gpu/opengl/gl_vertex_buffer.cc @@ -49,6 +49,10 @@ void GLVertBuf::resize_data() void GLVertBuf::release_data() { + if (is_wrapper_) { + return; + } + if (vbo_id_ != 0) { GLContext::buf_free(vbo_id_); vbo_id_ = 0; @@ -137,6 +141,16 @@ void *GLVertBuf::unmap(const void *mapped_data) const return result; } +void GLVertBuf::wrap_handle(uint64_t handle) +{ + BLI_assert(vbo_id_ == 0); + BLI_assert(glIsBuffer(static_cast<uint>(handle))); + is_wrapper_ = true; + vbo_id_ = static_cast<uint>(handle); + /* We assume the data is already on the device, so no need to allocate or send it. */ + flag = GPU_VERTBUF_DATA_UPLOADED; +} + bool GLVertBuf::is_active() const { if (!vbo_id_) { @@ -147,7 +161,7 @@ bool GLVertBuf::is_active() const return vbo_id_ == active_vbo_id; } -void GLVertBuf::update_sub(uint start, uint len, void *data) +void GLVertBuf::update_sub(uint start, uint len, const void *data) { glBufferSubData(GL_ARRAY_BUFFER, start, len, data); } diff --git a/source/blender/gpu/opengl/gl_vertex_buffer.hh b/source/blender/gpu/opengl/gl_vertex_buffer.hh index 6c38a2225b3..27e4cc4f8e2 100644 --- a/source/blender/gpu/opengl/gl_vertex_buffer.hh +++ b/source/blender/gpu/opengl/gl_vertex_buffer.hh @@ -39,17 +39,22 @@ class GLVertBuf : public VertBuf { private: /** OpenGL buffer handle. Init on first upload. Immutable after that. */ GLuint vbo_id_ = 0; + /** Defines whether the buffer handle is wrapped by this GLVertBuf, i.e. we do not own it and + * should not free it. */ + bool is_wrapper_ = false; /** Size on the GPU. */ size_t vbo_size_ = 0; public: void bind(void); - void update_sub(uint start, uint len, void *data) override; + void update_sub(uint start, uint len, const void *data) override; const void *read() const override; void *unmap(const void *mapped_data) const override; + void wrap_handle(uint64_t handle) override; + protected: void acquire_data(void) override; void resize_data(void) override; diff --git a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl index 5b6a890ccc8..91f986d23ad 100644 --- a/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl +++ b/source/blender/gpu/shaders/gpu_shader_3D_flat_color_vert.glsl @@ -5,11 +5,7 @@ uniform mat4 ModelMatrix; #endif in vec3 pos; -#if defined(USE_COLOR_U32) -in uint color; -#else in vec4 color; -#endif flat out vec4 finalColor; @@ -17,15 +13,7 @@ void main() { vec4 pos_4d = vec4(pos, 1.0); gl_Position = ModelViewProjectionMatrix * pos_4d; - -#if defined(USE_COLOR_U32) - finalColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f), - ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f), - ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f), - ((color >> 24)) * (1.0f / 255.0f)); -#else finalColor = color; -#endif #ifdef USE_WORLD_CLIP_PLANES world_clip_planes_calc_clip_distance((ModelMatrix * pos_4d).xyz); diff --git a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl index 2033401db67..08623fa9935 100644 --- a/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_uniform_color_frag.glsl @@ -1,21 +1,9 @@ -#if defined(USE_COLOR_U32) -uniform uint color; -#else uniform vec4 color; -#endif out vec4 fragColor; void main() { -#if defined(USE_COLOR_U32) - fragColor = vec4(((color)&uint(0xFF)) * (1.0f / 255.0f), - ((color >> 8) & uint(0xFF)) * (1.0f / 255.0f), - ((color >> 16) & uint(0xFF)) * (1.0f / 255.0f), - ((color >> 24)) * (1.0f / 255.0f)); -#else - fragColor = color; -#endif - fragColor = blender_srgb_to_framebuffer_space(fragColor); + fragColor = blender_srgb_to_framebuffer_space(color); } diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index 949efb522f3..4a4e22ed884 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -284,7 +284,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co /* setup the chain data */ /* create a target */ - target = (PoseTarget *)MEM_callocN(sizeof(PoseTarget), "posetarget"); + target = MEM_cnew<PoseTarget>("posetarget"); target->con = con; /* by construction there can be only one tree per channel * and each channel can be part of at most one tree. */ @@ -292,7 +292,7 @@ static int initialize_chain(Object *ob, bPoseChannel *pchan_tip, bConstraint *co if (tree == nullptr) { /* make new tree */ - tree = (PoseTree *)MEM_callocN(sizeof(PoseTree), "posetree"); + tree = MEM_cnew<PoseTree>("posetree"); tree->iterations = data->iterations; tree->totchannel = segcount; diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index e1b9853ac21..ec8cf36dd49 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -683,7 +683,7 @@ static bool imb_exr_multilayer_parse_channels_from_file(ExrHandle *data); void *IMB_exr_get_handle(void) { - ExrHandle *data = (ExrHandle *)MEM_callocN(sizeof(ExrHandle), "exr handle"); + ExrHandle *data = MEM_cnew<ExrHandle>("exr handle"); data->multiView = new StringVector(); BLI_addtail(&exrhandles, data); @@ -789,7 +789,7 @@ void IMB_exr_add_channel(void *handle, ExrHandle *data = (ExrHandle *)handle; ExrChannel *echan; - echan = (ExrChannel *)MEM_callocN(sizeof(ExrChannel), "exr channel"); + echan = MEM_cnew<ExrChannel>("exr channel"); echan->m = new MultiViewChannelName(); if (layname && layname[0] != '\0') { @@ -1496,7 +1496,7 @@ static ExrLayer *imb_exr_get_layer(ListBase *lb, char *layname) ExrLayer *lay = (ExrLayer *)BLI_findstring(lb, layname, offsetof(ExrLayer, name)); if (lay == nullptr) { - lay = (ExrLayer *)MEM_callocN(sizeof(ExrLayer), "exr layer"); + lay = MEM_cnew<ExrLayer>("exr layer"); BLI_addtail(lb, lay); BLI_strncpy(lay->name, layname, EXR_LAY_MAXNAME); } @@ -1509,7 +1509,7 @@ static ExrPass *imb_exr_get_pass(ListBase *lb, char *passname) ExrPass *pass = (ExrPass *)BLI_findstring(lb, passname, offsetof(ExrPass, name)); if (pass == nullptr) { - pass = (ExrPass *)MEM_callocN(sizeof(ExrPass), "exr pass"); + pass = MEM_cnew<ExrPass>("exr pass"); if (STREQ(passname, "Combined")) { BLI_addhead(lb, pass); diff --git a/source/blender/imbuf/intern/transform.cc b/source/blender/imbuf/intern/transform.cc index 3e071a9e4d7..e1c451a8412 100644 --- a/source/blender/imbuf/intern/transform.cc +++ b/source/blender/imbuf/intern/transform.cc @@ -305,19 +305,22 @@ class Sampler { void sample(const ImBuf *source, const float u, const float v, SampleType &r_sample) { - const float wrapped_u = uv_wrapper.modify_u(source, u); - const float wrapped_v = uv_wrapper.modify_v(source, v); - if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float> && NumChannels == 4) { + const float wrapped_u = uv_wrapper.modify_u(source, u); + const float wrapped_v = uv_wrapper.modify_v(source, v); bilinear_interpolation_color_fl(source, nullptr, &r_sample[0], wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, unsigned char> && NumChannels == 4) { + const float wrapped_u = uv_wrapper.modify_u(source, u); + const float wrapped_v = uv_wrapper.modify_v(source, v); nearest_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, unsigned char> && NumChannels == 4) { + const float wrapped_u = uv_wrapper.modify_u(source, u); + const float wrapped_v = uv_wrapper.modify_v(source, v); bilinear_interpolation_color_char(source, &r_sample[0], nullptr, wrapped_u, wrapped_v); } else if constexpr (Filter == IMB_FILTER_BILINEAR && std::is_same_v<StorageType, float>) { @@ -326,6 +329,8 @@ class Sampler { source->rect_float, &r_sample[0], source->x, source->y, NumChannels, u, v, true, true); } else { + const float wrapped_u = uv_wrapper.modify_u(source, u); + const float wrapped_v = uv_wrapper.modify_v(source, v); BLI_bilinear_interpolation_fl(source->rect_float, &r_sample[0], source->x, @@ -336,6 +341,8 @@ class Sampler { } } else if constexpr (Filter == IMB_FILTER_NEAREST && std::is_same_v<StorageType, float>) { + const float wrapped_u = uv_wrapper.modify_u(source, u); + const float wrapped_v = uv_wrapper.modify_v(source, v); sample_nearest_float(source, wrapped_u, wrapped_v, r_sample); } else { diff --git a/source/blender/io/CMakeLists.txt b/source/blender/io/CMakeLists.txt index f11ad7627b9..b97b3ef97de 100644 --- a/source/blender/io/CMakeLists.txt +++ b/source/blender/io/CMakeLists.txt @@ -19,6 +19,7 @@ # ***** END GPL LICENSE BLOCK ***** add_subdirectory(common) +add_subdirectory(wavefront_obj) if(WITH_ALEMBIC) add_subdirectory(alembic) diff --git a/source/blender/io/collada/AnimationImporter.cpp b/source/blender/io/collada/AnimationImporter.cpp index 870db4a15d3..49a4b22dbc3 100644 --- a/source/blender/io/collada/AnimationImporter.cpp +++ b/source/blender/io/collada/AnimationImporter.cpp @@ -237,7 +237,7 @@ void AnimationImporter::add_fcurves_to_object(Main *bmain, /* no matching groups, so add one */ if (grp == nullptr) { /* Add a new group, and make it active */ - grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + grp = MEM_cnew<bActionGroup>("bActionGroup"); grp->flag = AGRP_SELECTED; BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); @@ -2177,7 +2177,7 @@ void AnimationImporter::add_bone_fcurve(Object *ob, COLLADAFW::Node *node, FCurv /* no matching groups, so add one */ if (grp == nullptr) { /* Add a new group, and make it active */ - grp = (bActionGroup *)MEM_callocN(sizeof(bActionGroup), "bActionGroup"); + grp = MEM_cnew<bActionGroup>("bActionGroup"); grp->flag = AGRP_SELECTED; BLI_strncpy(grp->name, bone_name, sizeof(grp->name)); diff --git a/source/blender/io/collada/Materials.cpp b/source/blender/io/collada/Materials.cpp index 1f358accc4e..6e17172f642 100644 --- a/source/blender/io/collada/Materials.cpp +++ b/source/blender/io/collada/Materials.cpp @@ -16,6 +16,8 @@ #include "Materials.h" +#include "BKE_node_tree_update.h" + MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) : mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map) { @@ -106,7 +108,7 @@ bNodeTree *MaterialNode::prepare_material_nodetree() void MaterialNode::update_material_nodetree() { - ntreeUpdateTree(CTX_data_main(mContext), ntree); + BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr); } bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label) diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc index 7539fba1343..c856e60c4b8 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_pdf.cc @@ -238,7 +238,7 @@ void GpencilExporterPDF::export_stroke_to_polyline(bGPDlayer *gpl, /* Get the thickness in pixels using a simple 1 point stroke. */ bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false); gps_temp->totpoints = 1; - gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); + gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points"); const bGPDspoint *pt_src = &gps->points[0]; bGPDspoint *pt_dst = &gps_temp->points[0]; copy_v3_v3(&pt_dst->x, &pt_src->x); diff --git a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc index 09eac7a2813..3ca6ed6cd45 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_export_svg.cc @@ -308,7 +308,7 @@ void GpencilExporterSVG::export_stroke_to_polyline(bGPDlayer *gpl, /* Get the thickness in pixels using a simple 1 point stroke. */ bGPDstroke *gps_temp = BKE_gpencil_stroke_duplicate(gps, false, false); gps_temp->totpoints = 1; - gps_temp->points = (bGPDspoint *)MEM_callocN(sizeof(bGPDspoint), "gp_stroke_points"); + gps_temp->points = MEM_cnew<bGPDspoint>("gp_stroke_points"); bGPDspoint *pt_src = &gps->points[0]; bGPDspoint *pt_dst = &gps_temp->points[0]; copy_v3_v3(&pt_dst->x, &pt_src->x); diff --git a/source/blender/io/usd/intern/usd_reader_material.cc b/source/blender/io/usd/intern/usd_reader_material.cc index db0c5785a68..645dea42971 100644 --- a/source/blender/io/usd/intern/usd_reader_material.cc +++ b/source/blender/io/usd/intern/usd_reader_material.cc @@ -23,6 +23,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BLI_math_vector.h" #include "BLI_string.h" @@ -339,7 +340,7 @@ void USDMaterialReader::import_usd_preview(Material *mtl, nodeSetActive(ntree, output); - ntreeUpdateTree(bmain_, ntree); + BKE_ntree_update_main_tree(bmain_, ntree, nullptr); /* Optionally, set the material blend mode. */ diff --git a/source/blender/io/wavefront_obj/CMakeLists.txt b/source/blender/io/wavefront_obj/CMakeLists.txt new file mode 100644 index 00000000000..190475c5550 --- /dev/null +++ b/source/blender/io/wavefront_obj/CMakeLists.txt @@ -0,0 +1,84 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ./exporter + ../../blenkernel + ../../blenlib + ../../bmesh + ../../bmesh/intern + ../../depsgraph + ../../editors/include + ../../makesdna + ../../makesrna + ../../nodes + ../../windowmanager + ../../../../intern/guardedalloc +) + +set(INC_SYS + +) + +set(SRC + IO_wavefront_obj.cc + exporter/obj_exporter.cc + exporter/obj_export_file_writer.cc + exporter/obj_export_mesh.cc + exporter/obj_export_mtl.cc + exporter/obj_export_nurbs.cc + + IO_wavefront_obj.h + exporter/obj_exporter.hh + exporter/obj_export_file_writer.hh + exporter/obj_export_io.hh + exporter/obj_export_mesh.hh + exporter/obj_export_mtl.hh + exporter/obj_export_nurbs.hh +) + +set(LIB + bf_blenkernel +) + +blender_add_lib(bf_wavefront_obj "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +if(WITH_GTESTS) + set(TEST_SRC + tests/obj_exporter_tests.cc + tests/obj_exporter_tests.hh + ) + + set(TEST_INC + ${INC} + + ../../blenloader + ../../../../tests/gtests + ) + + set(TEST_LIB + ${LIB} + + bf_blenloader_tests + bf_wavefront_obj + ) + + include(GTestTesting) + blender_add_test_lib(bf_wavefront_obj_tests "${TEST_SRC}" "${TEST_INC}" "${INC_SYS}" "${TEST_LIB}") + add_dependencies(bf_wavefront_obj_tests bf_wavefront_obj) +endif() diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.cc b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc new file mode 100644 index 00000000000..1c93eafe91a --- /dev/null +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.cc @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include "BLI_timeit.hh" + +#include "IO_wavefront_obj.h" + +#include "obj_exporter.hh" + +/** + * C-interface for the exporter. + */ +void OBJ_export(bContext *C, const OBJExportParams *export_params) +{ + SCOPED_TIMER("OBJ export"); + blender::io::obj::exporter_main(C, *export_params); +} diff --git a/source/blender/io/wavefront_obj/IO_wavefront_obj.h b/source/blender/io/wavefront_obj/IO_wavefront_obj.h new file mode 100644 index 00000000000..25687fd957c --- /dev/null +++ b/source/blender/io/wavefront_obj/IO_wavefront_obj.h @@ -0,0 +1,97 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include "BKE_context.h" +#include "BLI_path_util.h" +#include "DEG_depsgraph.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + OBJ_AXIS_X_UP = 0, + OBJ_AXIS_Y_UP = 1, + OBJ_AXIS_Z_UP = 2, + OBJ_AXIS_NEGATIVE_X_UP = 3, + OBJ_AXIS_NEGATIVE_Y_UP = 4, + OBJ_AXIS_NEGATIVE_Z_UP = 5, +} eTransformAxisUp; + +typedef enum { + OBJ_AXIS_X_FORWARD = 0, + OBJ_AXIS_Y_FORWARD = 1, + OBJ_AXIS_Z_FORWARD = 2, + OBJ_AXIS_NEGATIVE_X_FORWARD = 3, + OBJ_AXIS_NEGATIVE_Y_FORWARD = 4, + OBJ_AXIS_NEGATIVE_Z_FORWARD = 5, +} eTransformAxisForward; + +const int TOTAL_AXES = 3; + +struct OBJExportParams { + /** Full path to the destination .OBJ file. */ + char filepath[FILE_MAX]; + + /** Full path to current blender file (used for comments in output). */ + const char *blen_filepath; + + /** Whether multiple frames should be exported. */ + bool export_animation; + /** The first frame to be exported. */ + int start_frame; + /** The last frame to be exported. */ + int end_frame; + + /* Geometry Transform options. */ + eTransformAxisForward forward_axis; + eTransformAxisUp up_axis; + float scaling_factor; + + /* File Write Options. */ + bool export_selected_objects; + eEvaluationMode export_eval_mode; + bool export_uv; + bool export_normals; + bool export_materials; + bool export_triangulated_mesh; + bool export_curves_as_nurbs; + + /* Grouping options. */ + bool export_object_groups; + bool export_material_groups; + bool export_vertex_groups; + /** + * Calculate smooth groups from sharp edges. + */ + bool export_smooth_groups; + /** + * Create bitflags instead of the default "0"/"1" group IDs. + */ + bool smooth_groups_bitflags; +}; + +void OBJ_export(bContext *C, const struct OBJExportParams *export_params); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc new file mode 100644 index 00000000000..d92d1c5ad48 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.cc @@ -0,0 +1,626 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include <algorithm> +#include <cstdio> + +#include "BKE_blender_version.h" + +#include "BLI_path_util.h" + +#include "obj_export_mesh.hh" +#include "obj_export_mtl.hh" +#include "obj_export_nurbs.hh" + +#include "obj_export_file_writer.hh" + +namespace blender::io::obj { +/** + * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec: + * To turn off smoothing groups, use a value of 0 or off. + * Polygonal elements use group numbers to put elements in different smoothing groups. + * For free-form surfaces, smoothing groups are either turned on or off; + * there is no difference between values greater than 0. + */ +const int SMOOTH_GROUP_DISABLED = 0; +const int SMOOTH_GROUP_DEFAULT = 1; + +const char *DEFORM_GROUP_DISABLED = "off"; +/* There is no deform group default name. Use what the user set in the UI. */ + +/** + * Per reference http://www.martinreddy.net/gfx/3d/OBJ.spec: + * Once a material is assigned, it cannot be turned off; it can only be changed. + * If a material name is not specified, a white material is used. + * So an empty material name is written. */ +const char *MATERIAL_GROUP_DISABLED = ""; + +/** + * Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...". + */ +void OBJWriter::write_vert_uv_normal_indices(Span<int> vert_indices, + Span<int> uv_indices, + Span<int> normal_indices) const +{ + BLI_assert(vert_indices.size() == uv_indices.size() && + vert_indices.size() == normal_indices.size()); + file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + for (int j = 0; j < vert_indices.size(); j++) { + file_handler_->write<eOBJSyntaxElement::vertex_uv_normal_indices>( + vert_indices[j] + index_offsets_.vertex_offset + 1, + uv_indices[j] + index_offsets_.uv_vertex_offset + 1, + normal_indices[j] + index_offsets_.normal_offset + 1); + } + file_handler_->write<eOBJSyntaxElement::poly_element_end>(); +} + +/** + * Write one line of polygon indices as "f v1//vn1 v2//vn2 ...". + */ +void OBJWriter::write_vert_normal_indices(Span<int> vert_indices, + Span<int> /*uv_indices*/, + Span<int> normal_indices) const +{ + BLI_assert(vert_indices.size() == normal_indices.size()); + file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + for (int j = 0; j < vert_indices.size(); j++) { + file_handler_->write<eOBJSyntaxElement::vertex_normal_indices>( + vert_indices[j] + index_offsets_.vertex_offset + 1, + normal_indices[j] + index_offsets_.normal_offset + 1); + } + file_handler_->write<eOBJSyntaxElement::poly_element_end>(); +} + +/** + * Write one line of polygon indices as "f v1/vt1 v2/vt2 ...". + */ +void OBJWriter::write_vert_uv_indices(Span<int> vert_indices, + Span<int> uv_indices, + Span<int> /*normal_indices*/) const +{ + BLI_assert(vert_indices.size() == uv_indices.size()); + file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + for (int j = 0; j < vert_indices.size(); j++) { + file_handler_->write<eOBJSyntaxElement::vertex_uv_indices>( + vert_indices[j] + index_offsets_.vertex_offset + 1, + uv_indices[j] + index_offsets_.uv_vertex_offset + 1); + } + file_handler_->write<eOBJSyntaxElement::poly_element_end>(); +} + +/** + * Write one line of polygon indices as "f v1 v2 ...". + */ +void OBJWriter::write_vert_indices(Span<int> vert_indices, + Span<int> /*uv_indices*/, + Span<int> /*normal_indices*/) const +{ + file_handler_->write<eOBJSyntaxElement::poly_element_begin>(); + for (const int vert_index : vert_indices) { + file_handler_->write<eOBJSyntaxElement::vertex_indices>(vert_index + + index_offsets_.vertex_offset + 1); + } + file_handler_->write<eOBJSyntaxElement::poly_element_end>(); +} + +void OBJWriter::write_header() const +{ + using namespace std::string_literals; + file_handler_->write<eOBJSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + + "\n"); + file_handler_->write<eOBJSyntaxElement::string>("# www.blender.org\n"); +} + +/** + * Write file name of Material Library in .OBJ file. + */ +void OBJWriter::write_mtllib_name(const StringRefNull mtl_filepath) const +{ + /* Split .MTL file path into parent directory and filename. */ + char mtl_file_name[FILE_MAXFILE]; + char mtl_dir_name[FILE_MAXDIR]; + BLI_split_dirfile(mtl_filepath.data(), mtl_dir_name, mtl_file_name, FILE_MAXDIR, FILE_MAXFILE); + file_handler_->write<eOBJSyntaxElement::mtllib>(mtl_file_name); +} + +/** + * Write an object's group with mesh and/or material name appended conditionally. + */ +void OBJWriter::write_object_group(const OBJMesh &obj_mesh_data) const +{ + /* "o object_name" is not mandatory. A valid .OBJ file may contain neither + * "o name" nor "g group_name". */ + BLI_assert(export_params_.export_object_groups); + if (!export_params_.export_object_groups) { + return; + } + const std::string object_name = obj_mesh_data.get_object_name(); + const char *object_mesh_name = obj_mesh_data.get_object_mesh_name(); + const char *object_material_name = obj_mesh_data.get_object_material_name(0); + if (export_params_.export_materials && export_params_.export_material_groups && + object_material_name) { + file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name + + "_" + object_material_name); + return; + } + file_handler_->write<eOBJSyntaxElement::object_group>(object_name + "_" + object_mesh_name); +} + +/** + * Write object's name or group. + */ +void OBJWriter::write_object_name(const OBJMesh &obj_mesh_data) const +{ + const char *object_name = obj_mesh_data.get_object_name(); + if (export_params_.export_object_groups) { + write_object_group(obj_mesh_data); + return; + } + file_handler_->write<eOBJSyntaxElement::object_name>(object_name); +} + +/** + * Write vertex coordinates for all vertices as "v x y z". + */ +void OBJWriter::write_vertex_coords(const OBJMesh &obj_mesh_data) const +{ + const int tot_vertices = obj_mesh_data.tot_vertices(); + for (int i = 0; i < tot_vertices; i++) { + float3 vertex = obj_mesh_data.calc_vertex_coords(i, export_params_.scaling_factor); + file_handler_->write<eOBJSyntaxElement::vertex_coords>(vertex[0], vertex[1], vertex[2]); + } +} + +/** + * Write UV vertex coordinates for all vertices as "vt u v". + * \note UV indices are stored here, but written later. + */ +void OBJWriter::write_uv_coords(OBJMesh &r_obj_mesh_data) const +{ + Vector<std::array<float, 2>> uv_coords; + /* UV indices are calculated and stored in an OBJMesh member here. */ + r_obj_mesh_data.store_uv_coords_and_indices(uv_coords); + + for (const std::array<float, 2> &uv_vertex : uv_coords) { + file_handler_->write<eOBJSyntaxElement::uv_vertex_coords>(uv_vertex[0], uv_vertex[1]); + } +} + +/** + * Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z". + */ +void OBJWriter::write_poly_normals(const OBJMesh &obj_mesh_data) const +{ + obj_mesh_data.ensure_mesh_normals(); + Vector<float3> lnormals; + const int tot_polygons = obj_mesh_data.tot_polygons(); + for (int i = 0; i < tot_polygons; i++) { + if (obj_mesh_data.is_ith_poly_smooth(i)) { + obj_mesh_data.calc_loop_normals(i, lnormals); + for (const float3 &lnormal : lnormals) { + file_handler_->write<eOBJSyntaxElement::normal>(lnormal[0], lnormal[1], lnormal[2]); + } + } + else { + float3 poly_normal = obj_mesh_data.calc_poly_normal(i); + file_handler_->write<eOBJSyntaxElement::normal>( + poly_normal[0], poly_normal[1], poly_normal[2]); + } + } +} + +/** + * Write smooth group if polygon at the given index is shaded smooth else "s 0" + */ +int OBJWriter::write_smooth_group(const OBJMesh &obj_mesh_data, + const int poly_index, + const int last_poly_smooth_group) const +{ + int current_group = SMOOTH_GROUP_DISABLED; + if (!export_params_.export_smooth_groups && obj_mesh_data.is_ith_poly_smooth(poly_index)) { + /* Smooth group calculation is disabled, but polygon is smooth-shaded. */ + current_group = SMOOTH_GROUP_DEFAULT; + } + else if (obj_mesh_data.is_ith_poly_smooth(poly_index)) { + /* Smooth group calc is enabled and polygon is smooth–shaded, so find the group. */ + current_group = obj_mesh_data.ith_smooth_group(poly_index); + } + + if (current_group == last_poly_smooth_group) { + /* Group has already been written, even if it is "s 0". */ + return current_group; + } + file_handler_->write<eOBJSyntaxElement::smooth_group>(current_group); + return current_group; +} + +/** + * Write material name and material group of a polygon in the .OBJ file. + * \return #mat_nr of the polygon at the given index. + * \note It doesn't write to the material library. + */ +int16_t OBJWriter::write_poly_material(const OBJMesh &obj_mesh_data, + const int poly_index, + const int16_t last_poly_mat_nr, + std::function<const char *(int)> matname_fn) const +{ + if (!export_params_.export_materials || obj_mesh_data.tot_materials() <= 0) { + return last_poly_mat_nr; + } + const int16_t current_mat_nr = obj_mesh_data.ith_poly_matnr(poly_index); + /* Whenever a polygon with a new material is encountered, write its material + * and/or group, otherwise pass. */ + if (last_poly_mat_nr == current_mat_nr) { + return current_mat_nr; + } + if (current_mat_nr == NOT_FOUND) { + file_handler_->write<eOBJSyntaxElement::poly_usemtl>(MATERIAL_GROUP_DISABLED); + return current_mat_nr; + } + if (export_params_.export_object_groups) { + write_object_group(obj_mesh_data); + } + const char *mat_name = matname_fn(current_mat_nr); + if (!mat_name) { + mat_name = MATERIAL_GROUP_DISABLED; + } + file_handler_->write<eOBJSyntaxElement::poly_usemtl>(mat_name); + + return current_mat_nr; +} + +/** + * Write the name of the deform group of a polygon. + */ +int16_t OBJWriter::write_vertex_group(const OBJMesh &obj_mesh_data, + const int poly_index, + const int16_t last_poly_vertex_group) const +{ + if (!export_params_.export_vertex_groups) { + return last_poly_vertex_group; + } + const int16_t current_group = obj_mesh_data.get_poly_deform_group_index(poly_index); + + if (current_group == last_poly_vertex_group) { + /* No vertex group found in this polygon, just like in the last iteration. */ + return current_group; + } + if (current_group == NOT_FOUND) { + file_handler_->write<eOBJSyntaxElement::object_group>(DEFORM_GROUP_DISABLED); + return current_group; + } + file_handler_->write<eOBJSyntaxElement::object_group>( + obj_mesh_data.get_poly_deform_group_name(current_group)); + return current_group; +} + +/** + * \return Writer function with appropriate polygon-element syntax. + */ +OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer( + const int total_uv_vertices) const +{ + if (export_params_.export_normals) { + if (export_params_.export_uv && (total_uv_vertices > 0)) { + /* Write both normals and UV indices. */ + return &OBJWriter::write_vert_uv_normal_indices; + } + /* Write normals indices. */ + return &OBJWriter::write_vert_normal_indices; + } + /* Write UV indices. */ + if (export_params_.export_uv && (total_uv_vertices > 0)) { + return &OBJWriter::write_vert_uv_indices; + } + /* Write neither normals nor UV indices. */ + return &OBJWriter::write_vert_indices; +} + +/** + * Write polygon elements with at least vertex indices, and conditionally with UV vertex + * indices and polygon normal indices. Also write groups: smooth, vertex, material. + * The matname_fn turns a 0-indexed material slot number in an Object into the + * name used in the .obj file. + * \note UV indices were stored while writing UV vertices. + */ +void OBJWriter::write_poly_elements(const OBJMesh &obj_mesh_data, + std::function<const char *(int)> matname_fn) +{ + int last_poly_smooth_group = NEGATIVE_INIT; + int16_t last_poly_vertex_group = NEGATIVE_INIT; + int16_t last_poly_mat_nr = NEGATIVE_INIT; + + const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer( + obj_mesh_data.tot_uv_vertices()); + + /* Number of normals may not be equal to number of polygons due to smooth shading. */ + int per_object_tot_normals = 0; + const int tot_polygons = obj_mesh_data.tot_polygons(); + for (int i = 0; i < tot_polygons; i++) { + Vector<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i); + Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i); + /* For an Object, a normal index depends on how many of its normals have been written before + * it. This is unknown because of smooth shading. So pass "per object total normals" + * and update it after each call. */ + int new_normals = 0; + Vector<int> poly_normal_indices; + std::tie(new_normals, poly_normal_indices) = obj_mesh_data.calc_poly_normal_indices( + i, per_object_tot_normals); + per_object_tot_normals += new_normals; + + last_poly_smooth_group = write_smooth_group(obj_mesh_data, i, last_poly_smooth_group); + last_poly_vertex_group = write_vertex_group(obj_mesh_data, i, last_poly_vertex_group); + last_poly_mat_nr = write_poly_material(obj_mesh_data, i, last_poly_mat_nr, matname_fn); + (this->*poly_element_writer)(poly_vertex_indices, poly_uv_indices, poly_normal_indices); + } + /* Unusual: Other indices are updated in #OBJWriter::update_index_offsets. */ + index_offsets_.normal_offset += per_object_tot_normals; +} + +/** + * Write loose edges of a mesh as "l v1 v2". + */ +void OBJWriter::write_edges_indices(const OBJMesh &obj_mesh_data) const +{ + obj_mesh_data.ensure_mesh_edges(); + const int tot_edges = obj_mesh_data.tot_edges(); + for (int edge_index = 0; edge_index < tot_edges; edge_index++) { + const std::optional<std::array<int, 2>> vertex_indices = + obj_mesh_data.calc_loose_edge_vert_indices(edge_index); + if (!vertex_indices) { + continue; + } + file_handler_->write<eOBJSyntaxElement::edge>( + (*vertex_indices)[0] + index_offsets_.vertex_offset + 1, + (*vertex_indices)[1] + index_offsets_.vertex_offset + 1); + } +} + +/** + * Write a NURBS curve to the .OBJ file in parameter form. + */ +void OBJWriter::write_nurbs_curve(const OBJCurve &obj_nurbs_data) const +{ + const int total_splines = obj_nurbs_data.total_splines(); + for (int spline_idx = 0; spline_idx < total_splines; spline_idx++) { + const int total_vertices = obj_nurbs_data.total_spline_vertices(spline_idx); + for (int vertex_idx = 0; vertex_idx < total_vertices; vertex_idx++) { + const float3 vertex_coords = obj_nurbs_data.vertex_coordinates( + spline_idx, vertex_idx, export_params_.scaling_factor); + file_handler_->write<eOBJSyntaxElement::vertex_coords>( + vertex_coords[0], vertex_coords[1], vertex_coords[2]); + } + + const char *nurbs_name = obj_nurbs_data.get_curve_name(); + const int nurbs_degree = obj_nurbs_data.get_nurbs_degree(spline_idx); + file_handler_->write<eOBJSyntaxElement::object_group>(nurbs_name); + file_handler_->write<eOBJSyntaxElement::cstype>(); + file_handler_->write<eOBJSyntaxElement::nurbs_degree>(nurbs_degree); + /** + * The numbers written here are indices into the vertex coordinates written + * earlier, relative to the line that is going to be written. + * [0.0 - 1.0] is the curve parameter range. + * 0.0 1.0 -1 -2 -3 -4 for a non-cyclic curve with 4 vertices. + * 0.0 1.0 -1 -2 -3 -4 -1 -2 -3 for a cyclic curve with 4 vertices. + */ + const int total_control_points = obj_nurbs_data.total_spline_control_points(spline_idx); + file_handler_->write<eOBJSyntaxElement::curve_element_begin>(); + for (int i = 0; i < total_control_points; i++) { + /* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the + * last vertex coordinate, -2 second last. */ + file_handler_->write<eOBJSyntaxElement::vertex_indices>(-((i % total_vertices) + 1)); + } + file_handler_->write<eOBJSyntaxElement::curve_element_end>(); + + /** + * In "parm u 0 0.1 .." line:, (total control points + 2) equidistant numbers in the + * parameter range are inserted. + */ + file_handler_->write<eOBJSyntaxElement::nurbs_parameter_begin>(); + for (int i = 1; i <= total_control_points + 2; i++) { + file_handler_->write<eOBJSyntaxElement::nurbs_parameters>(1.0f * i / + (total_control_points + 2 + 1)); + } + file_handler_->write<eOBJSyntaxElement::nurbs_parameter_end>(); + + file_handler_->write<eOBJSyntaxElement::nurbs_group_end>(); + } +} + +/** + * When there are multiple objects in a frame, the indices of previous objects' coordinates or + * normals add up. + */ +void OBJWriter::update_index_offsets(const OBJMesh &obj_mesh_data) +{ + index_offsets_.vertex_offset += obj_mesh_data.tot_vertices(); + index_offsets_.uv_vertex_offset += obj_mesh_data.tot_uv_vertices(); + /* Normal index is updated right after writing the normals. */ +} + +/* -------------------------------------------------------------------- */ +/** \name .MTL writers. + * \{ */ + +/** + * Convert #float3 to string of space-separated numbers, with no leading or trailing space. + * Only to be used in NON-performance-critical code. + */ +static std::string float3_to_string(const float3 &numbers) +{ + std::ostringstream r_string; + r_string << numbers[0] << " " << numbers[1] << " " << numbers[2]; + return r_string.str(); +}; + +/* + * Create the .MTL file. + */ +MTLWriter::MTLWriter(const char *obj_filepath) noexcept(false) +{ + mtl_filepath_ = obj_filepath; + const bool ok = BLI_path_extension_replace(mtl_filepath_.data(), FILE_MAX, ".mtl"); + if (!ok) { + throw std::system_error(ENAMETOOLONG, std::system_category(), ""); + } + file_handler_ = std::make_unique<FileHandler<eFileType::MTL>>(mtl_filepath_); +} + +void MTLWriter::write_header(const char *blen_filepath) const +{ + using namespace std::string_literals; + const char *blen_basename = (blen_filepath && blen_filepath[0] != '\0') ? + BLI_path_basename(blen_filepath) : + "None"; + file_handler_->write<eMTLSyntaxElement::string>("# Blender "s + BKE_blender_version_string() + + " MTL File: '" + blen_basename + "'\n"); + file_handler_->write<eMTLSyntaxElement::string>("# www.blender.org\n"); +} + +StringRefNull MTLWriter::mtl_file_path() const +{ + return mtl_filepath_; +} + +/** + * Write properties sourced from p-BSDF node or #Object.Material. + */ +void MTLWriter::write_bsdf_properties(const MTLMaterial &mtl_material) +{ + file_handler_->write<eMTLSyntaxElement::Ns>(mtl_material.Ns); + file_handler_->write<eMTLSyntaxElement::Ka>( + mtl_material.Ka.x, mtl_material.Ka.y, mtl_material.Ka.z); + file_handler_->write<eMTLSyntaxElement::Kd>( + mtl_material.Kd.x, mtl_material.Kd.y, mtl_material.Kd.z); + file_handler_->write<eMTLSyntaxElement::Ks>( + mtl_material.Ks.x, mtl_material.Ks.y, mtl_material.Ks.z); + file_handler_->write<eMTLSyntaxElement::Ke>( + mtl_material.Ke.x, mtl_material.Ke.y, mtl_material.Ke.z); + file_handler_->write<eMTLSyntaxElement::Ni>(mtl_material.Ni); + file_handler_->write<eMTLSyntaxElement::d>(mtl_material.d); + file_handler_->write<eMTLSyntaxElement::illum>(mtl_material.illum); +} + +/** + * Write a texture map in the form "map_XX -s 1. 1. 1. -o 0. 0. 0. [-bm 1.] path/to/image". + */ +void MTLWriter::write_texture_map( + const MTLMaterial &mtl_material, + const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map) +{ + std::string translation; + std::string scale; + std::string map_bump_strength; + /* Optional strings should have their own leading spaces. */ + if (texture_map.value.translation != float3{0.0f, 0.0f, 0.0f}) { + translation.append(" -s ").append(float3_to_string(texture_map.value.translation)); + } + if (texture_map.value.scale != float3{1.0f, 1.0f, 1.0f}) { + scale.append(" -o ").append(float3_to_string(texture_map.value.scale)); + } + if (texture_map.key == eMTLSyntaxElement::map_Bump && mtl_material.map_Bump_strength > 0.0001f) { + map_bump_strength.append(" -bm ").append(std::to_string(mtl_material.map_Bump_strength)); + } + +#define SYNTAX_DISPATCH(eMTLSyntaxElement) \ + if (texture_map.key == eMTLSyntaxElement) { \ + file_handler_->write<eMTLSyntaxElement>(translation + scale + map_bump_strength, \ + texture_map.value.image_path); \ + return; \ + } + + SYNTAX_DISPATCH(eMTLSyntaxElement::map_Kd); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ks); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ns); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_d); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_refl); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_Ke); + SYNTAX_DISPATCH(eMTLSyntaxElement::map_Bump); + + BLI_assert(!"This map type was not written to the file."); +} + +/** + * Write all of the material specifications to the MTL file. + * For consistency of output from run to run (useful for testing), + * the materials are sorted by name before writing. + */ +void MTLWriter::write_materials() +{ + if (mtlmaterials_.size() == 0) { + return; + } + std::sort(mtlmaterials_.begin(), + mtlmaterials_.end(), + [](const MTLMaterial &a, const MTLMaterial &b) { return a.name < b.name; }); + for (const MTLMaterial &mtlmat : mtlmaterials_) { + file_handler_->write<eMTLSyntaxElement::string>("\n"); + file_handler_->write<eMTLSyntaxElement::newmtl>(mtlmat.name); + write_bsdf_properties(mtlmat); + for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map : + mtlmat.texture_maps.items()) { + if (!texture_map.value.image_path.empty()) { + write_texture_map(mtlmat, texture_map); + } + } + } +} + +/** + * Add the materials of the given object to MTLWriter, deduping + * against ones that are already there. + * Return a Vector of indices into mtlmaterials_ that hold the MTLMaterial + * that corresponds to each material slot, in order, of the given Object. + * Indexes are returned rather than pointers to the MTLMaterials themselves + * because the mtlmaterials_ Vector may move around when resized. + */ +Vector<int> MTLWriter::add_materials(const OBJMesh &mesh_to_export) +{ + Vector<int> r_mtl_indices; + r_mtl_indices.resize(mesh_to_export.tot_materials()); + for (int16_t i = 0; i < mesh_to_export.tot_materials(); i++) { + const Material *material = mesh_to_export.get_object_material(i); + if (!material) { + r_mtl_indices[i] = -1; + continue; + } + int mtlmat_index = material_map_.lookup_default(material, -1); + if (mtlmat_index != -1) { + r_mtl_indices[i] = mtlmat_index; + } + else { + mtlmaterials_.append(mtlmaterial_for_material(material)); + r_mtl_indices[i] = mtlmaterials_.size() - 1; + material_map_.add_new(material, r_mtl_indices[i]); + } + } + return r_mtl_indices; +} + +const char *MTLWriter::mtlmaterial_name(int index) +{ + if (index < 0 || index >= mtlmaterials_.size()) { + return nullptr; + } + return mtlmaterials_[index].name.c_str(); +} +/** \} */ + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh new file mode 100644 index 00000000000..36d35ae370b --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_file_writer.hh @@ -0,0 +1,132 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include "DNA_meshdata_types.h" + +#include "BLI_map.hh" +#include "BLI_vector.hh" + +#include "IO_wavefront_obj.h" +#include "obj_export_io.hh" +#include "obj_export_mtl.hh" + +namespace blender::io::obj { + +class OBJCurve; +class OBJMesh; +/** + * Total vertices/ UV vertices/ normals of previous Objects + * should be added to the current Object's indices. + */ +struct IndexOffsets { + int vertex_offset; + int uv_vertex_offset; + int normal_offset; +}; + +/** + * Responsible for writing a .OBJ file. + */ +class OBJWriter : NonMovable, NonCopyable { + private: + const OBJExportParams &export_params_; + std::unique_ptr<FileHandler<eFileType::OBJ>> file_handler_ = nullptr; + IndexOffsets index_offsets_{0, 0, 0}; + + public: + OBJWriter(const char *filepath, const OBJExportParams &export_params) noexcept(false) + : export_params_(export_params) + { + file_handler_ = std::make_unique<FileHandler<eFileType::OBJ>>(filepath); + } + + void write_header() const; + + void write_object_name(const OBJMesh &obj_mesh_data) const; + void write_object_group(const OBJMesh &obj_mesh_data) const; + void write_mtllib_name(const StringRefNull mtl_filepath) const; + void write_vertex_coords(const OBJMesh &obj_mesh_data) const; + void write_uv_coords(OBJMesh &obj_mesh_data) const; + void write_poly_normals(const OBJMesh &obj_mesh_data) const; + int write_smooth_group(const OBJMesh &obj_mesh_data, + int poly_index, + const int last_poly_smooth_group) const; + int16_t write_poly_material(const OBJMesh &obj_mesh_data, + const int poly_index, + const int16_t last_poly_mat_nr, + std::function<const char *(int)> matname_fn) const; + int16_t write_vertex_group(const OBJMesh &obj_mesh_data, + const int poly_index, + const int16_t last_poly_vertex_group) const; + void write_poly_elements(const OBJMesh &obj_mesh_data, + std::function<const char *(int)> matname_fn); + void write_edges_indices(const OBJMesh &obj_mesh_data) const; + void write_nurbs_curve(const OBJCurve &obj_nurbs_data) const; + + void update_index_offsets(const OBJMesh &obj_mesh_data); + + private: + using func_vert_uv_normal_indices = void (OBJWriter::*)(Span<int> vert_indices, + Span<int> uv_indices, + Span<int> normal_indices) const; + func_vert_uv_normal_indices get_poly_element_writer(const int total_uv_vertices) const; + + void write_vert_uv_normal_indices(Span<int> vert_indices, + Span<int> uv_indices, + Span<int> normal_indices) const; + void write_vert_normal_indices(Span<int> vert_indices, + Span<int> /*uv_indices*/, + Span<int> normal_indices) const; + void write_vert_uv_indices(Span<int> vert_indices, + Span<int> uv_indices, + Span<int> /*normal_indices*/) const; + void write_vert_indices(Span<int> vert_indices, + Span<int> /*uv_indices*/, + Span<int> /*normal_indices*/) const; +}; + +/** + * Responsible for writing a .MTL file. + */ +class MTLWriter : NonMovable, NonCopyable { + private: + std::unique_ptr<FileHandler<eFileType::MTL>> file_handler_ = nullptr; + std::string mtl_filepath_; + Vector<MTLMaterial> mtlmaterials_; + /* Map from a Material* to an index into mtlmaterials_. */ + Map<const Material *, int> material_map_; + + public: + MTLWriter(const char *obj_filepath) noexcept(false); + + void write_header(const char *blen_filepath) const; + void write_materials(); + StringRefNull mtl_file_path() const; + Vector<int> add_materials(const OBJMesh &mesh_to_export); + const char *mtlmaterial_name(int index); + + private: + void write_bsdf_properties(const MTLMaterial &mtl_material); + void write_texture_map(const MTLMaterial &mtl_material, + const Map<const eMTLSyntaxElement, tex_map_XX>::Item &texture_map); +}; +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_io.hh b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh new file mode 100644 index 00000000000..83571d8aa46 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_io.hh @@ -0,0 +1,340 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include <cstdio> +#include <string> +#include <system_error> +#include <type_traits> + +#include "BLI_compiler_attrs.h" +#include "BLI_string_ref.hh" +#include "BLI_utility_mixins.hh" + +namespace blender::io::obj { + +enum class eFileType { + OBJ, + MTL, +}; + +enum class eOBJSyntaxElement { + vertex_coords, + uv_vertex_coords, + normal, + poly_element_begin, + vertex_uv_normal_indices, + vertex_normal_indices, + vertex_uv_indices, + vertex_indices, + poly_element_end, + poly_usemtl, + edge, + cstype, + nurbs_degree, + curve_element_begin, + curve_element_end, + nurbs_parameter_begin, + nurbs_parameters, + nurbs_parameter_end, + nurbs_group_end, + new_line, + mtllib, + smooth_group, + object_group, + object_name, + /* Use rarely. New line is NOT included for string. */ + string, +}; + +enum class eMTLSyntaxElement { + newmtl, + Ni, + d, + Ns, + illum, + Ka, + Kd, + Ks, + Ke, + map_Kd, + map_Ks, + map_Ns, + map_d, + map_refl, + map_Ke, + map_Bump, + /* Use rarely. New line is NOT included for string. */ + string, +}; + +template<eFileType filetype> struct FileTypeTraits; + +template<> struct FileTypeTraits<eFileType::OBJ> { + using SyntaxType = eOBJSyntaxElement; +}; + +template<> struct FileTypeTraits<eFileType::MTL> { + using SyntaxType = eMTLSyntaxElement; +}; + +template<eFileType type> struct Formatting { + const char *fmt = nullptr; + const int total_args = 0; + /* Fail to compile by default. */ + const bool is_type_valid = false; +}; + +/** + * Type dependent but always false. Use to add a conditional compile-time error. + */ +template<typename T> struct always_false : std::false_type { +}; + +template<typename... T> +constexpr bool is_type_float = (... && std::is_floating_point_v<std::decay_t<T>>); + +template<typename... T> +constexpr bool is_type_integral = (... && std::is_integral_v<std::decay_t<T>>); + +template<typename... T> +constexpr bool is_type_string_related = (... && std::is_constructible_v<std::string, T>); + +template<eFileType filetype, typename... T> +constexpr std::enable_if_t<filetype == eFileType::OBJ, Formatting<filetype>> +syntax_elem_to_formatting(const eOBJSyntaxElement key) +{ + switch (key) { + case eOBJSyntaxElement::vertex_coords: { + return {"v %f %f %f\n", 3, is_type_float<T...>}; + } + case eOBJSyntaxElement::uv_vertex_coords: { + return {"vt %f %f\n", 2, is_type_float<T...>}; + } + case eOBJSyntaxElement::normal: { + return {"vn %f %f %f\n", 3, is_type_float<T...>}; + } + case eOBJSyntaxElement::poly_element_begin: { + return {"f", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::vertex_uv_normal_indices: { + return {" %d/%d/%d", 3, is_type_integral<T...>}; + } + case eOBJSyntaxElement::vertex_normal_indices: { + return {" %d//%d", 2, is_type_integral<T...>}; + } + case eOBJSyntaxElement::vertex_uv_indices: { + return {" %d/%d", 2, is_type_integral<T...>}; + } + case eOBJSyntaxElement::vertex_indices: { + return {" %d", 1, is_type_integral<T...>}; + } + case eOBJSyntaxElement::poly_usemtl: { + return {"usemtl %s\n", 1, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::edge: { + return {"l %d %d\n", 2, is_type_integral<T...>}; + } + case eOBJSyntaxElement::cstype: { + return {"cstype bspline\n", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::nurbs_degree: { + return {"deg %d\n", 1, is_type_integral<T...>}; + } + case eOBJSyntaxElement::curve_element_begin: { + return {"curv 0.0 1.0", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::nurbs_parameter_begin: { + return {"parm 0.0", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::nurbs_parameters: { + return {" %f", 1, is_type_float<T...>}; + } + case eOBJSyntaxElement::nurbs_parameter_end: { + return {" 1.0\n", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::nurbs_group_end: { + return {"end\n", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::poly_element_end: { + ATTR_FALLTHROUGH; + } + case eOBJSyntaxElement::curve_element_end: { + ATTR_FALLTHROUGH; + } + case eOBJSyntaxElement::new_line: { + return {"\n", 0, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::mtllib: { + return {"mtllib %s\n", 1, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::smooth_group: { + return {"s %d\n", 1, is_type_integral<T...>}; + } + case eOBJSyntaxElement::object_group: { + return {"g %s\n", 1, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::object_name: { + return {"o %s\n", 1, is_type_string_related<T...>}; + } + case eOBJSyntaxElement::string: { + return {"%s", 1, is_type_string_related<T...>}; + } + } +} + +template<eFileType filetype, typename... T> +constexpr std::enable_if_t<filetype == eFileType::MTL, Formatting<filetype>> +syntax_elem_to_formatting(const eMTLSyntaxElement key) +{ + switch (key) { + case eMTLSyntaxElement::newmtl: { + return {"newmtl %s\n", 1, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::Ni: { + return {"Ni %.6f\n", 1, is_type_float<T...>}; + } + case eMTLSyntaxElement::d: { + return {"d %.6f\n", 1, is_type_float<T...>}; + } + case eMTLSyntaxElement::Ns: { + return {"Ns %.6f\n", 1, is_type_float<T...>}; + } + case eMTLSyntaxElement::illum: { + return {"illum %d\n", 1, is_type_integral<T...>}; + } + case eMTLSyntaxElement::Ka: { + return {"Ka %.6f %.6f %.6f\n", 3, is_type_float<T...>}; + } + case eMTLSyntaxElement::Kd: { + return {"Kd %.6f %.6f %.6f\n", 3, is_type_float<T...>}; + } + case eMTLSyntaxElement::Ks: { + return {"Ks %.6f %.6f %.6f\n", 3, is_type_float<T...>}; + } + case eMTLSyntaxElement::Ke: { + return {"Ke %.6f %.6f %.6f\n", 3, is_type_float<T...>}; + } + /* Keep only one space between options since filepaths may have leading spaces too. */ + case eMTLSyntaxElement::map_Kd: { + return {"map_Kd %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_Ks: { + return {"map_Ks %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_Ns: { + return {"map_Ns %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_d: { + return {"map_d %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_refl: { + return {"map_refl %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_Ke: { + return {"map_Ke %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::map_Bump: { + return {"map_Bump %s %s\n", 2, is_type_string_related<T...>}; + } + case eMTLSyntaxElement::string: { + return {"%s", 1, is_type_string_related<T...>}; + } + } +} + +template<eFileType filetype> class FileHandler : NonCopyable, NonMovable { + private: + FILE *outfile_ = nullptr; + std::string outfile_path_; + + public: + FileHandler(std::string outfile_path) noexcept(false) : outfile_path_(std::move(outfile_path)) + { + outfile_ = std::fopen(outfile_path_.c_str(), "w"); + if (!outfile_) { + throw std::system_error(errno, std::system_category(), "Cannot open file"); + } + } + + ~FileHandler() + { + if (outfile_ && std::fclose(outfile_)) { + std::cerr << "Error: could not close the file '" << outfile_path_ + << "' properly, it may be corrupted." << std::endl; + } + } + + template<typename FileTypeTraits<filetype>::SyntaxType key, typename... T> + constexpr void write(T &&...args) const + { + constexpr Formatting<filetype> fmt_nargs_valid = syntax_elem_to_formatting<filetype, T...>( + key); + write__impl<fmt_nargs_valid.total_args>(fmt_nargs_valid.fmt, std::forward<T>(args)...); + /* Types of all arguments and the number of arguments should match + * what the formatting specifies. */ + return std::enable_if_t < fmt_nargs_valid.is_type_valid && + (sizeof...(T) == fmt_nargs_valid.total_args), + void > (); + } + + private: + /* Remove this after upgrading to C++20. */ + template<typename T> using remove_cvref_t = std::remove_cv_t<std::remove_reference_t<T>>; + + /** + * Make #std::string etc., usable for fprintf-family. + * \return: `const char *` or the original argument if the argument is + * not related to #std::string. + */ + template<typename T> constexpr auto string_to_primitive(T &&arg) const + { + if constexpr (std::is_same_v<remove_cvref_t<T>, std::string> || + std::is_same_v<remove_cvref_t<T>, blender::StringRefNull>) { + return arg.c_str(); + } + else if constexpr (std::is_same_v<remove_cvref_t<T>, blender::StringRef>) { + BLI_STATIC_ASSERT( + (always_false<T>::value), + "Null-terminated string not present. Please use blender::StringRefNull instead."); + /* Another trick to cause a compile-time error: returning nothing to #std::printf. */ + return; + } + else { + return std::forward<T>(arg); + } + } + + template<int total_args, typename... T> + constexpr std::enable_if_t<(total_args != 0), void> write__impl(const char *fmt, + T &&...args) const + { + std::fprintf(outfile_, fmt, string_to_primitive(std::forward<T>(args))...); + } + template<int total_args, typename... T> + constexpr std::enable_if_t<(total_args == 0), void> write__impl(const char *fmt, + T &&...args) const + { + std::fputs(fmt, outfile_); + } +}; + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc new file mode 100644 index 00000000000..0947d1132b0 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.cc @@ -0,0 +1,489 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include "BKE_customdata.h" +#include "BKE_deform.h" +#include "BKE_lib_id.h" +#include "BKE_material.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_object.h" + +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DEG_depsgraph_query.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_object_types.h" + +#include "obj_export_mesh.hh" + +namespace blender::io::obj { +/** + * Store evaluated Object and Mesh pointers. Conditionally triangulate a mesh, or + * create a new Mesh from a Curve. + */ +OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object) +{ + export_object_eval_ = DEG_get_evaluated_object(depsgraph, mesh_object); + export_mesh_eval_ = BKE_object_get_evaluated_mesh(export_object_eval_); + mesh_eval_needs_free_ = false; + + if (!export_mesh_eval_) { + /* Curves and NURBS surfaces need a new mesh when they're + * exported in the form of vertices and edges. + */ + export_mesh_eval_ = BKE_mesh_new_from_object(depsgraph, export_object_eval_, true, true); + /* Since a new mesh been allocated, it needs to be freed in the destructor. */ + mesh_eval_needs_free_ = true; + } + if (export_params.export_triangulated_mesh && + ELEM(export_object_eval_->type, OB_MESH, OB_SURF)) { + std::tie(export_mesh_eval_, mesh_eval_needs_free_) = triangulate_mesh_eval(); + } + set_world_axes_transform(export_params.forward_axis, export_params.up_axis); +} + +/** + * Free new meshes allocated for triangulated meshes, or Curve converted to Mesh. + */ +OBJMesh::~OBJMesh() +{ + free_mesh_if_needed(); + if (poly_smooth_groups_) { + MEM_freeN(poly_smooth_groups_); + } +} + +/** + * Free the mesh if _the exporter_ created it. + */ +void OBJMesh::free_mesh_if_needed() +{ + if (mesh_eval_needs_free_ && export_mesh_eval_) { + BKE_id_free(nullptr, export_mesh_eval_); + } +} + +/** + * Allocate a new Mesh with triangulated polygons. + * + * The returned mesh can be the same as the old one. + * \return Owning pointer to the new Mesh, and whether a new Mesh was created. + */ +std::pair<Mesh *, bool> OBJMesh::triangulate_mesh_eval() +{ + if (export_mesh_eval_->totpoly <= 0) { + return {export_mesh_eval_, false}; + } + const struct BMeshCreateParams bm_create_params = {0u}; + const struct BMeshFromMeshParams bm_convert_params = {1u, 0, 0, 0}; + /* Lower threshold where triangulation of a polygon starts, i.e. a quadrilateral will be + * triangulated here. */ + const int triangulate_min_verts = 4; + + unique_bmesh_ptr bmesh( + BKE_mesh_to_bmesh_ex(export_mesh_eval_, &bm_create_params, &bm_convert_params)); + BM_mesh_triangulate(bmesh.get(), + MOD_TRIANGULATE_NGON_BEAUTY, + MOD_TRIANGULATE_QUAD_SHORTEDGE, + triangulate_min_verts, + false, + nullptr, + nullptr, + nullptr); + + Mesh *triangulated = BKE_mesh_from_bmesh_for_eval_nomain( + bmesh.get(), nullptr, export_mesh_eval_); + free_mesh_if_needed(); + return {triangulated, true}; +} + +/** + * Set the final transform after applying axes settings and an Object's world transform. + */ +void OBJMesh::set_world_axes_transform(const eTransformAxisForward forward, + const eTransformAxisUp up) +{ + float axes_transform[3][3]; + unit_m3(axes_transform); + /* +Y-forward and +Z-up are the default Blender axis settings. */ + mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); + /* mat3_from_axis_conversion returns a transposed matrix! */ + transpose_m3(axes_transform); + mul_m4_m3m4(world_and_axes_transform_, axes_transform, export_object_eval_->obmat); + /* mul_m4_m3m4 does not transform last row of obmat, i.e. location data. */ + mul_v3_m3v3(world_and_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); + world_and_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; +} + +int OBJMesh::tot_vertices() const +{ + return export_mesh_eval_->totvert; +} + +int OBJMesh::tot_polygons() const +{ + return export_mesh_eval_->totpoly; +} + +int OBJMesh::tot_uv_vertices() const +{ + return tot_uv_vertices_; +} + +int OBJMesh::tot_edges() const +{ + return export_mesh_eval_->totedge; +} + +/** + * \return Total materials in the object. + */ +int16_t OBJMesh::tot_materials() const +{ + return export_mesh_eval_->totcol; +} + +/** + * \return Smooth group of the polygon at the given index. + */ +int OBJMesh::ith_smooth_group(const int poly_index) const +{ + /* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */ + BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT); + BLI_assert(poly_smooth_groups_); + return poly_smooth_groups_[poly_index]; +} + +void OBJMesh::ensure_mesh_normals() const +{ + BKE_mesh_ensure_normals(export_mesh_eval_); + BKE_mesh_calc_normals_split(export_mesh_eval_); +} + +void OBJMesh::ensure_mesh_edges() const +{ + BKE_mesh_calc_edges(export_mesh_eval_, true, false); + BKE_mesh_calc_edges_loose(export_mesh_eval_); +} + +/** + * Calculate smooth groups of a smooth-shaded object. + * \return A polygon aligned array of smooth group numbers. + */ +void OBJMesh::calc_smooth_groups(const bool use_bitflags) +{ + poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(export_mesh_eval_->medge, + export_mesh_eval_->totedge, + export_mesh_eval_->mpoly, + export_mesh_eval_->totpoly, + export_mesh_eval_->mloop, + export_mesh_eval_->totloop, + &tot_smooth_groups_, + use_bitflags); +} + +/** + * Return mat_nr-th material of the object. The given index should be zero-based. + */ +const Material *OBJMesh::get_object_material(const int16_t mat_nr) const +{ + /* "+ 1" as material getter needs one-based indices. */ + const Material *r_mat = BKE_object_material_get(export_object_eval_, mat_nr + 1); +#ifdef DEBUG + if (!r_mat) { + std::cerr << "Material not found for mat_nr = " << mat_nr << std::endl; + } +#endif + return r_mat; +} + +bool OBJMesh::is_ith_poly_smooth(const int poly_index) const +{ + return export_mesh_eval_->mpoly[poly_index].flag & ME_SMOOTH; +} + +/** + * Returns a zero-based index of a polygon's material indexing into + * the Object's material slots. + */ +int16_t OBJMesh::ith_poly_matnr(const int poly_index) const +{ + BLI_assert(poly_index < export_mesh_eval_->totpoly); + const int16_t r_mat_nr = export_mesh_eval_->mpoly[poly_index].mat_nr; + return r_mat_nr >= 0 ? r_mat_nr : NOT_FOUND; +} + +/** + * Get object name as it appears in the outliner. + */ +const char *OBJMesh::get_object_name() const +{ + return export_object_eval_->id.name + 2; +} + +/** + * Get Object's Mesh's name. + */ +const char *OBJMesh::get_object_mesh_name() const +{ + return export_mesh_eval_->id.name + 2; +} + +/** + * Get object's material (at the given index) name. The given index should be zero-based. + */ +const char *OBJMesh::get_object_material_name(const int16_t mat_nr) const +{ + const Material *mat = get_object_material(mat_nr); + if (!mat) { + return nullptr; + } + return mat->id.name + 2; +} + +/** + * Calculate coordinates of the vertex at the given index. + */ +float3 OBJMesh::calc_vertex_coords(const int vert_index, const float scaling_factor) const +{ + float3 r_coords; + copy_v3_v3(r_coords, export_mesh_eval_->mvert[vert_index].co); + mul_v3_fl(r_coords, scaling_factor); + mul_m4_v3(world_and_axes_transform_, r_coords); + return r_coords; +} + +/** + * Calculate vertex indices of all vertices of the polygon at the given index. + */ +Vector<int> OBJMesh::calc_poly_vertex_indices(const int poly_index) const +{ + const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; + const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart]; + const int totloop = mpoly.totloop; + Vector<int> r_poly_vertex_indices(totloop); + for (int loop_index = 0; loop_index < totloop; loop_index++) { + r_poly_vertex_indices[loop_index] = mloop[loop_index].v; + } + return r_poly_vertex_indices; +} + +/** + * Calculate UV vertex coordinates of an Object. + * + * \note Also store the UV vertex indices in the member variable. + */ +void OBJMesh::store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords) +{ + const MPoly *mpoly = export_mesh_eval_->mpoly; + const MLoop *mloop = export_mesh_eval_->mloop; + const int totpoly = export_mesh_eval_->totpoly; + const int totvert = export_mesh_eval_->totvert; + const MLoopUV *mloopuv = static_cast<MLoopUV *>( + CustomData_get_layer(&export_mesh_eval_->ldata, CD_MLOOPUV)); + if (!mloopuv) { + tot_uv_vertices_ = 0; + return; + } + const float limit[2] = {STD_UV_CONNECT_LIMIT, STD_UV_CONNECT_LIMIT}; + + UvVertMap *uv_vert_map = BKE_mesh_uv_vert_map_create( + mpoly, mloop, mloopuv, totpoly, totvert, limit, false, false); + + uv_indices_.resize(totpoly); + /* At least total vertices of a mesh will be present in its texture map. So + * reserve minimum space early. */ + r_uv_coords.reserve(totvert); + + tot_uv_vertices_ = 0; + for (int vertex_index = 0; vertex_index < totvert; vertex_index++) { + const UvMapVert *uv_vert = BKE_mesh_uv_vert_map_get_vert(uv_vert_map, vertex_index); + for (; uv_vert; uv_vert = uv_vert->next) { + if (uv_vert->separate) { + tot_uv_vertices_ += 1; + } + const int vertices_in_poly = mpoly[uv_vert->poly_index].totloop; + + /* Store UV vertex coordinates. */ + r_uv_coords.resize(tot_uv_vertices_); + const int loopstart = mpoly[uv_vert->poly_index].loopstart; + Span<float> vert_uv_coords(mloopuv[loopstart + uv_vert->loop_of_poly_index].uv, 2); + r_uv_coords[tot_uv_vertices_ - 1][0] = vert_uv_coords[0]; + r_uv_coords[tot_uv_vertices_ - 1][1] = vert_uv_coords[1]; + + /* Store UV vertex indices. */ + uv_indices_[uv_vert->poly_index].resize(vertices_in_poly); + /* Keep indices zero-based and let the writer handle the "+ 1" as per OBJ spec. */ + uv_indices_[uv_vert->poly_index][uv_vert->loop_of_poly_index] = tot_uv_vertices_ - 1; + } + } + BKE_mesh_uv_vert_map_free(uv_vert_map); +} + +Span<int> OBJMesh::calc_poly_uv_indices(const int poly_index) const +{ + if (uv_indices_.size() <= 0) { + return {}; + } + BLI_assert(poly_index < export_mesh_eval_->totpoly); + BLI_assert(poly_index < uv_indices_.size()); + return uv_indices_[poly_index]; +} +/** + * Calculate polygon normal of a polygon at given index. + * + * Should be used for flat-shaded polygons. + */ +float3 OBJMesh::calc_poly_normal(const int poly_index) const +{ + float3 r_poly_normal; + const MPoly &poly = export_mesh_eval_->mpoly[poly_index]; + const MLoop &mloop = export_mesh_eval_->mloop[poly.loopstart]; + const MVert &mvert = *(export_mesh_eval_->mvert); + BKE_mesh_calc_poly_normal(&poly, &mloop, &mvert, r_poly_normal); + mul_mat3_m4_v3(world_and_axes_transform_, r_poly_normal); + return r_poly_normal; +} + +/** + * Calculate loop normals of a polygon at the given index. + * + * Should be used for smooth-shaded polygons. + */ +void OBJMesh::calc_loop_normals(const int poly_index, Vector<float3> &r_loop_normals) const +{ + r_loop_normals.clear(); + const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; + const float( + *lnors)[3] = (const float(*)[3])(CustomData_get_layer(&export_mesh_eval_->ldata, CD_NORMAL)); + for (int loop_of_poly = 0; loop_of_poly < mpoly.totloop; loop_of_poly++) { + float3 loop_normal; + copy_v3_v3(loop_normal, lnors[mpoly.loopstart + loop_of_poly]); + mul_mat3_m4_v3(world_and_axes_transform_, loop_normal); + r_loop_normals.append(loop_normal); + } +} + +/** + * Calculate a polygon's polygon/loop normal indices. + * \param object_tot_prev_normals Number of normals of this Object written so far. + * \return Number of distinct normal indices. + */ +std::pair<int, Vector<int>> OBJMesh::calc_poly_normal_indices( + const int poly_index, const int object_tot_prev_normals) const +{ + const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; + const int totloop = mpoly.totloop; + Vector<int> r_poly_normal_indices(totloop); + + if (is_ith_poly_smooth(poly_index)) { + for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) { + /* Using polygon loop index is fine because polygon/loop normals and their normal indices are + * written by looping over #Mesh.mpoly /#Mesh.mloop in the same order. */ + r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals + poly_loop_index; + } + /* For a smooth-shaded polygon, #Mesh.totloop -many loop normals are written. */ + return {totloop, r_poly_normal_indices}; + } + for (int poly_loop_index = 0; poly_loop_index < totloop; poly_loop_index++) { + r_poly_normal_indices[poly_loop_index] = object_tot_prev_normals; + } + /* For a flat-shaded polygon, one polygon normal is written. */ + return {1, r_poly_normal_indices}; +} + +/** + * Find the index of the vertex group with the maximum number of vertices in a polygon. + * The index indices into the #Object.defbase. + * + * If two or more groups have the same number of vertices (maximum), group name depends on the + * implementation of #std::max_element. + */ +int16_t OBJMesh::get_poly_deform_group_index(const int poly_index) const +{ + BLI_assert(poly_index < export_mesh_eval_->totpoly); + const MPoly &mpoly = export_mesh_eval_->mpoly[poly_index]; + const MLoop *mloop = &export_mesh_eval_->mloop[mpoly.loopstart]; + const Object *obj = export_object_eval_; + const int tot_deform_groups = BKE_object_defgroup_count(obj); + /* Indices of the vector index into deform groups of an object; values are the] + * number of vertex members in one deform group. */ + Vector<int16_t> deform_group_members(tot_deform_groups, 0); + /* Whether at least one vertex in the polygon belongs to any group. */ + bool found_group = false; + + const MDeformVert *dvert_orig = static_cast<MDeformVert *>( + CustomData_get_layer(&export_mesh_eval_->vdata, CD_MDEFORMVERT)); + if (!dvert_orig) { + return NOT_FOUND; + } + + const MDeformWeight *curr_weight = nullptr; + const MDeformVert *dvert = nullptr; + for (int loop_index = 0; loop_index < mpoly.totloop; loop_index++) { + dvert = &dvert_orig[(mloop + loop_index)->v]; + curr_weight = dvert->dw; + if (curr_weight) { + bDeformGroup *vertex_group = static_cast<bDeformGroup *>( + BLI_findlink(BKE_object_defgroup_list(obj), curr_weight->def_nr)); + if (vertex_group) { + deform_group_members[curr_weight->def_nr] += 1; + found_group = true; + } + } + } + + if (!found_group) { + return NOT_FOUND; + } + /* Index of the group with maximum vertices. */ + int16_t max_idx = std::max_element(deform_group_members.begin(), deform_group_members.end()) - + deform_group_members.begin(); + return max_idx; +} + +/** + * Find the name of the vertex deform group at the given index. + * The index indices into the #Object.defbase. + */ +const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const +{ + const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>( + BLI_findlink(BKE_object_defgroup_list(export_object_eval_), def_group_index))); + return vertex_group.name; +} + +/** + * Calculate vertex indices of an edge's corners if it is a loose edge. + */ +std::optional<std::array<int, 2>> OBJMesh::calc_loose_edge_vert_indices(const int edge_index) const +{ + const MEdge &edge = export_mesh_eval_->medge[edge_index]; + if (edge.flag & ME_LOOSEEDGE) { + return std::array<int, 2>{static_cast<int>(edge.v1), static_cast<int>(edge.v2)}; + } + return std::nullopt; +} +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh new file mode 100644 index 00000000000..d72dd76d447 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mesh.hh @@ -0,0 +1,131 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include <optional> + +#include "BLI_float3.hh" +#include "BLI_utility_mixins.hh" +#include "BLI_vector.hh" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "IO_wavefront_obj.h" + +namespace blender::io::obj { +/* Denote absence for usually non-negative numbers. */ +const int NOT_FOUND = -1; +/* Any negative number other than `NOT_FOUND` to initialise usually non-negative numbers. */ +const int NEGATIVE_INIT = -10; + +/** + * #std::unique_ptr deleter for BMesh. + */ +struct CustomBMeshDeleter { + void operator()(BMesh *bmesh) + { + if (bmesh) { + BM_mesh_free(bmesh); + } + } +}; + +using unique_bmesh_ptr = std::unique_ptr<BMesh, CustomBMeshDeleter>; + +class OBJMesh : NonCopyable { + private: + Object *export_object_eval_; + Mesh *export_mesh_eval_; + /** + * For curves which are converted to mesh, and triangulated meshes, a new mesh is allocated. + */ + bool mesh_eval_needs_free_ = false; + /** + * Final transform of an object obtained from export settings (up_axis, forward_axis) and the + * object's world transform matrix. + */ + float world_and_axes_transform_[4][4]; + + /** + * Total UV vertices in a mesh's texture map. + */ + int tot_uv_vertices_ = 0; + /** + * Per-polygon-per-vertex UV vertex indices. + */ + Vector<Vector<int>> uv_indices_; + /** + * Total smooth groups in an object. + */ + int tot_smooth_groups_ = NEGATIVE_INIT; + /** + * Polygon aligned array of their smooth groups. + */ + int *poly_smooth_groups_ = nullptr; + + public: + OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Object *mesh_object); + ~OBJMesh(); + + int tot_vertices() const; + int tot_polygons() const; + int tot_uv_vertices() const; + int tot_edges() const; + + int16_t tot_materials() const; + const Material *get_object_material(const int16_t mat_nr) const; + int16_t ith_poly_matnr(const int poly_index) const; + + void ensure_mesh_normals() const; + void ensure_mesh_edges() const; + + void calc_smooth_groups(const bool use_bitflags); + int ith_smooth_group(const int poly_index) const; + bool is_ith_poly_smooth(const int poly_index) const; + + const char *get_object_name() const; + const char *get_object_mesh_name() const; + const char *get_object_material_name(const int16_t mat_nr) const; + + float3 calc_vertex_coords(const int vert_index, const float scaling_factor) const; + Vector<int> calc_poly_vertex_indices(const int poly_index) const; + void store_uv_coords_and_indices(Vector<std::array<float, 2>> &r_uv_coords); + Span<int> calc_poly_uv_indices(const int poly_index) const; + float3 calc_poly_normal(const int poly_index) const; + std::pair<int, Vector<int>> calc_poly_normal_indices(const int poly_index, + const int object_tot_prev_normals) const; + void calc_loop_normals(const int poly_index, Vector<float3> &r_loop_normals) const; + int16_t get_poly_deform_group_index(const int poly_index) const; + const char *get_poly_deform_group_name(const int16_t def_group_index) const; + + std::optional<std::array<int, 2>> calc_loose_edge_vert_indices(const int edge_index) const; + + private: + void free_mesh_if_needed(); + std::pair<Mesh *, bool> triangulate_mesh_eval(); + void set_world_axes_transform(const eTransformAxisForward forward, const eTransformAxisUp up); +}; +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc new file mode 100644 index 00000000000..b60f8976177 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.cc @@ -0,0 +1,362 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include "BKE_image.h" +#include "BKE_node.h" + +#include "BLI_float3.hh" +#include "BLI_map.hh" +#include "BLI_path_util.h" + +#include "DNA_material_types.h" +#include "DNA_node_types.h" + +#include "NOD_node_tree_ref.hh" + +#include "obj_export_mesh.hh" +#include "obj_export_mtl.hh" + +namespace blender::io::obj { + +/** + * Copy a float property of the given type from the bNode to given buffer. + */ +static void copy_property_from_node(const eNodeSocketDatatype property_type, + const bNode *node, + const char *identifier, + MutableSpan<float> r_property) +{ + if (!node) { + return; + } + bNodeSocket *socket{nodeFindSocket(node, SOCK_IN, identifier)}; + BLI_assert(socket && socket->type == property_type); + if (!socket) { + return; + } + switch (property_type) { + case SOCK_FLOAT: { + BLI_assert(r_property.size() == 1); + bNodeSocketValueFloat *socket_def_value = static_cast<bNodeSocketValueFloat *>( + socket->default_value); + r_property[0] = socket_def_value->value; + break; + } + case SOCK_RGBA: { + BLI_assert(r_property.size() == 3); + bNodeSocketValueRGBA *socket_def_value = static_cast<bNodeSocketValueRGBA *>( + socket->default_value); + copy_v3_v3(r_property.data(), socket_def_value->value); + break; + } + case SOCK_VECTOR: { + BLI_assert(r_property.size() == 3); + bNodeSocketValueVector *socket_def_value = static_cast<bNodeSocketValueVector *>( + socket->default_value); + copy_v3_v3(r_property.data(), socket_def_value->value); + break; + } + default: { + /* Other socket types are not handled here. */ + BLI_assert(0); + break; + } + } +} + +/** + * Collect all the source sockets linked to the destination socket in a destination node. + */ +static void linked_sockets_to_dest_id(const bNode *dest_node, + const nodes::NodeTreeRef &node_tree, + StringRefNull dest_socket_id, + Vector<const nodes::OutputSocketRef *> &r_linked_sockets) +{ + r_linked_sockets.clear(); + if (!dest_node) { + return; + } + Span<const nodes::NodeRef *> object_dest_nodes = node_tree.nodes_by_type(dest_node->idname); + Span<const nodes::InputSocketRef *> dest_inputs = object_dest_nodes.first()->inputs(); + const nodes::InputSocketRef *dest_socket = nullptr; + for (const nodes::InputSocketRef *curr_socket : dest_inputs) { + if (STREQ(curr_socket->bsocket()->identifier, dest_socket_id.c_str())) { + dest_socket = curr_socket; + break; + } + } + if (dest_socket) { + Span<const nodes::OutputSocketRef *> linked_sockets = dest_socket->directly_linked_sockets(); + r_linked_sockets.resize(linked_sockets.size()); + r_linked_sockets = linked_sockets; + } +} + +/** + * From a list of sockets, get the parent node which is of the given node type. + */ +static const bNode *get_node_of_type(Span<const nodes::OutputSocketRef *> sockets_list, + const int node_type) +{ + for (const nodes::SocketRef *socket : sockets_list) { + const bNode *parent_node = socket->bnode(); + if (parent_node->typeinfo->type == node_type) { + return parent_node; + } + } + return nullptr; +} + +/** + * From a texture image shader node, get the image's filepath. + * Returned filepath is stripped of initial "//". If packed image is found, + * only the file "name" is returned. + */ +static const char *get_image_filepath(const bNode *tex_node) +{ + if (!tex_node) { + return nullptr; + } + Image *tex_image = reinterpret_cast<Image *>(tex_node->id); + if (!tex_image || !BKE_image_has_filepath(tex_image)) { + return nullptr; + } + const char *path = tex_image->filepath; + if (BKE_image_has_packedfile(tex_image)) { + /* Put image in the same directory as the .MTL file. */ + path = BLI_path_slash_rfind(path) + 1; + fprintf(stderr, + "Packed image found:'%s'. Unpack and place the image in the same " + "directory as the .MTL file.\n", + path); + } + if (path[0] == '/' && path[1] == '/') { + path += 2; + } + return path; +} + +/** + * Find the Principled-BSDF Node in nodetree. + * We only want one that feeds directly into a Material Output node + * (that is the behavior of the legacy Python exporter). + */ +static const nodes::NodeRef *find_bsdf_node(const nodes::NodeTreeRef *nodetree) +{ + if (!nodetree) { + return nullptr; + } + for (const nodes::NodeRef *node : nodetree->nodes_by_type("ShaderNodeOutputMaterial")) { + const nodes::InputSocketRef *node_input_socket0 = node->inputs()[0]; + for (const nodes::OutputSocketRef *out_sock : node_input_socket0->directly_linked_sockets()) { + const nodes::NodeRef &in_node = out_sock->node(); + if (in_node.typeinfo()->type == SH_NODE_BSDF_PRINCIPLED) { + return &in_node; + } + } + } + return nullptr; +} + +/** + * Store properties found either in bNode or material into r_mtl_mat. + */ +static void store_bsdf_properties(const nodes::NodeRef *bsdf_node, + const Material *material, + MTLMaterial &r_mtl_mat) +{ + const bNode *bnode = nullptr; + if (bsdf_node) { + bnode = bsdf_node->bnode(); + } + + /* If p-BSDF is not present, fallback to #Object.Material. */ + float roughness = material->roughness; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "Roughness", {&roughness, 1}); + } + /* Emperical approximation. Importer should use the inverse of this method. */ + float spec_exponent = (1.0f - roughness) * 30; + spec_exponent *= spec_exponent; + + float specular = material->spec; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "Specular", {&specular, 1}); + } + + float metallic = material->metallic; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "Metallic", {&metallic, 1}); + } + + float refraction_index = 1.0f; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "IOR", {&refraction_index, 1}); + } + + float dissolved = material->a; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "Alpha", {&dissolved, 1}); + } + const bool transparent = dissolved != 1.0f; + + float3 diffuse_col = {material->r, material->g, material->b}; + if (bnode) { + copy_property_from_node(SOCK_RGBA, bnode, "Base Color", {diffuse_col, 3}); + } + + float3 emission_col{0.0f}; + float emission_strength = 0.0f; + if (bnode) { + copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); + copy_property_from_node(SOCK_RGBA, bnode, "Emission", {emission_col, 3}); + } + mul_v3_fl(emission_col, emission_strength); + + /* See https://wikipedia.org/wiki/Wavefront_.obj_file for all possible values of illum. */ + /* Highlight on. */ + int illum = 2; + if (specular == 0.0f) { + /* Color on and Ambient on. */ + illum = 1; + } + else if (metallic > 0.0f) { + /* Metallic ~= Reflection. */ + if (transparent) { + /* Transparency: Refraction on, Reflection: ~~Fresnel off and Ray trace~~ on. */ + illum = 6; + } + else { + /* Reflection on and Ray trace on. */ + illum = 3; + } + } + else if (transparent) { + /* Transparency: Glass on, Reflection: Ray trace off */ + illum = 9; + } + r_mtl_mat.Ns = spec_exponent; + if (metallic != 0.0f) { + r_mtl_mat.Ka = {metallic, metallic, metallic}; + } + else { + r_mtl_mat.Ka = {1.0f, 1.0f, 1.0f}; + } + r_mtl_mat.Kd = diffuse_col; + r_mtl_mat.Ks = {specular, specular, specular}; + r_mtl_mat.Ke = emission_col; + r_mtl_mat.Ni = refraction_index; + r_mtl_mat.d = dissolved; + r_mtl_mat.illum = illum; +} + +/** + * Store image texture options and filepaths in r_mtl_mat. + */ +static void store_image_textures(const nodes::NodeRef *bsdf_node, + const nodes::NodeTreeRef *node_tree, + const Material *material, + MTLMaterial &r_mtl_mat) +{ + if (!material || !node_tree || !bsdf_node) { + /* No nodetree, no images, or no Principled BSDF node. */ + return; + } + const bNode *bnode = bsdf_node->bnode(); + + /* Normal Map Texture has two extra tasks of: + * - finding a Normal Map node before finding a texture node. + * - finding "Strength" property of the node for `-bm` option. + */ + + for (Map<const eMTLSyntaxElement, tex_map_XX>::MutableItem texture_map : + r_mtl_mat.texture_maps.items()) { + Vector<const nodes::OutputSocketRef *> linked_sockets; + const bNode *normal_map_node{nullptr}; + + if (texture_map.key == eMTLSyntaxElement::map_Bump) { + /* Find sockets linked to destination "Normal" socket in p-bsdf node. */ + linked_sockets_to_dest_id(bnode, *node_tree, "Normal", linked_sockets); + /* Among the linked sockets, find Normal Map shader node. */ + normal_map_node = get_node_of_type(linked_sockets, SH_NODE_NORMAL_MAP); + + /* Find sockets linked to "Color" socket in normal map node. */ + linked_sockets_to_dest_id(normal_map_node, *node_tree, "Color", linked_sockets); + } + else if (texture_map.key == eMTLSyntaxElement::map_Ke) { + float emission_strength = 0.0f; + copy_property_from_node(SOCK_FLOAT, bnode, "Emission Strength", {&emission_strength, 1}); + if (emission_strength == 0.0f) { + continue; + } + } + else { + /* Find sockets linked to the destination socket of interest, in p-bsdf node. */ + linked_sockets_to_dest_id( + bnode, *node_tree, texture_map.value.dest_socket_id, linked_sockets); + } + + /* Among the linked sockets, find Image Texture shader node. */ + const bNode *tex_node{get_node_of_type(linked_sockets, SH_NODE_TEX_IMAGE)}; + if (!tex_node) { + continue; + } + const char *tex_image_filepath = get_image_filepath(tex_node); + if (!tex_image_filepath) { + continue; + } + + /* Find "Mapping" node if connected to texture node. */ + linked_sockets_to_dest_id(tex_node, *node_tree, "Vector", linked_sockets); + const bNode *mapping = get_node_of_type(linked_sockets, SH_NODE_MAPPING); + + if (normal_map_node) { + copy_property_from_node( + SOCK_FLOAT, normal_map_node, "Strength", {&r_mtl_mat.map_Bump_strength, 1}); + } + /* Texture transform options. Only translation (origin offset, "-o") and scale + * ("-o") are supported. */ + copy_property_from_node(SOCK_VECTOR, mapping, "Location", {texture_map.value.translation, 3}); + copy_property_from_node(SOCK_VECTOR, mapping, "Scale", {texture_map.value.scale, 3}); + + texture_map.value.image_path = tex_image_filepath; + } +} + +MTLMaterial mtlmaterial_for_material(const Material *material) +{ + BLI_assert(material != nullptr); + MTLMaterial mtlmat; + mtlmat.name = std::string(material->id.name + 2); + std::replace(mtlmat.name.begin(), mtlmat.name.end(), ' ', '_'); + const nodes::NodeTreeRef *nodetree = nullptr; + if (material->nodetree) { + nodetree = new nodes::NodeTreeRef(material->nodetree); + } + const nodes::NodeRef *bsdf_node = find_bsdf_node(nodetree); + store_bsdf_properties(bsdf_node, material, mtlmat); + store_image_textures(bsdf_node, nodetree, material, mtlmat); + if (nodetree) { + delete nodetree; + } + return mtlmat; +} + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh new file mode 100644 index 00000000000..2f62d189bd1 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_mtl.hh @@ -0,0 +1,104 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include "BLI_float3.hh" +#include "BLI_map.hh" +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +#include "DNA_node_types.h" +#include "obj_export_io.hh" + +namespace blender { +template<> struct DefaultHash<io::obj::eMTLSyntaxElement> { + uint64_t operator()(const io::obj::eMTLSyntaxElement value) const + { + return static_cast<uint64_t>(value); + } +}; + +} // namespace blender + +namespace blender::io::obj { +class OBJMesh; + +/** + * Generic container for texture node properties. + */ +struct tex_map_XX { + tex_map_XX(StringRef to_socket_id) : dest_socket_id(to_socket_id){}; + + /** Target socket which this texture node connects to. */ + const std::string dest_socket_id; + float3 translation{0.0f}; + float3 scale{1.0f}; + /* Only Flat and Smooth projections are supported. */ + int projection_type = SHD_PROJ_FLAT; + std::string image_path; + std::string mtl_dir_path; +}; + +/** + * Container suited for storing Material data for/from a .MTL file. + */ +struct MTLMaterial { + MTLMaterial() + { + texture_maps.add(eMTLSyntaxElement::map_Kd, tex_map_XX("Base Color")); + texture_maps.add(eMTLSyntaxElement::map_Ks, tex_map_XX("Specular")); + texture_maps.add(eMTLSyntaxElement::map_Ns, tex_map_XX("Roughness")); + texture_maps.add(eMTLSyntaxElement::map_d, tex_map_XX("Alpha")); + texture_maps.add(eMTLSyntaxElement::map_refl, tex_map_XX("Metallic")); + texture_maps.add(eMTLSyntaxElement::map_Ke, tex_map_XX("Emission")); + texture_maps.add(eMTLSyntaxElement::map_Bump, tex_map_XX("Normal")); + } + + /** + * Caller must ensure that the given lookup key exists in the Map. + * \return Texture map corresponding to the given ID. + */ + tex_map_XX &tex_map_of_type(const eMTLSyntaxElement key) + { + { + BLI_assert(texture_maps.contains_as(key)); + return texture_maps.lookup_as(key); + } + } + + std::string name; + /* Always check for negative values while importing or exporting. Use defaults if + * any value is negative. */ + float Ns{-1.0f}; + float3 Ka{-1.0f}; + float3 Kd{-1.0f}; + float3 Ks{-1.0f}; + float3 Ke{-1.0f}; + float Ni{-1.0f}; + float d{-1.0f}; + int illum{-1}; + Map<const eMTLSyntaxElement, tex_map_XX> texture_maps; + /** Only used for Normal Map node: "map_Bump". */ + float map_Bump_strength{-1.0f}; +}; + +MTLMaterial mtlmaterial_for_material(const Material *material); +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc new file mode 100644 index 00000000000..4138ad2f697 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.cc @@ -0,0 +1,122 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include "BLI_float3.hh" +#include "BLI_listbase.h" +#include "BLI_math.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "IO_wavefront_obj.h" +#include "obj_export_nurbs.hh" + +namespace blender::io::obj { +OBJCurve::OBJCurve(const Depsgraph *depsgraph, + const OBJExportParams &export_params, + Object *curve_object) + : export_object_eval_(curve_object) +{ + export_object_eval_ = DEG_get_evaluated_object(depsgraph, curve_object); + export_curve_ = static_cast<Curve *>(export_object_eval_->data); + set_world_axes_transform(export_params.forward_axis, export_params.up_axis); +} + +/** + * Set the final transform after applying axes settings and an Object's world transform. + */ +void OBJCurve::set_world_axes_transform(const eTransformAxisForward forward, + const eTransformAxisUp up) +{ + float axes_transform[3][3]; + unit_m3(axes_transform); + /* +Y-forward and +Z-up are the Blender's default axis settings. */ + mat3_from_axis_conversion(OBJ_AXIS_Y_FORWARD, OBJ_AXIS_Z_UP, forward, up, axes_transform); + /* mat3_from_axis_conversion returns a transposed matrix! */ + transpose_m3(axes_transform); + mul_m4_m3m4(world_axes_transform_, axes_transform, export_object_eval_->obmat); + /* #mul_m4_m3m4 does not transform last row of #Object.obmat, i.e. location data. */ + mul_v3_m3v3(world_axes_transform_[3], axes_transform, export_object_eval_->obmat[3]); + world_axes_transform_[3][3] = export_object_eval_->obmat[3][3]; +} + +const char *OBJCurve::get_curve_name() const +{ + return export_object_eval_->id.name + 2; +} + +int OBJCurve::total_splines() const +{ + return BLI_listbase_count(&export_curve_->nurb); +} + +/** + * \param spline_index: Zero-based index of spline of interest. + * \return: Total vertices in a spline. + */ +int OBJCurve::total_spline_vertices(const int spline_index) const +{ + const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index)); + return nurb->pntsu * nurb->pntsv; +} + +/** + * Get coordinates of the vertex at the given index on the given spline. + */ +float3 OBJCurve::vertex_coordinates(const int spline_index, + const int vertex_index, + const float scaling_factor) const +{ + const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index)); + float3 r_coord; + const BPoint &bpoint = nurb->bp[vertex_index]; + copy_v3_v3(r_coord, bpoint.vec); + mul_m4_v3(world_axes_transform_, r_coord); + mul_v3_fl(r_coord, scaling_factor); + return r_coord; +} + +/** + * Get total control points of the NURBS spline at the given index. This is different than total + * vertices of a spline. + */ +int OBJCurve::total_spline_control_points(const int spline_index) const +{ + const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index)); + const int r_nurbs_degree = nurb->orderu - 1; + /* Total control points = Number of points in the curve (+ degree of the + * curve if it is cyclic). */ + int r_tot_control_points = nurb->pntsv * nurb->pntsu; + if (nurb->flagu & CU_NURB_CYCLIC) { + r_tot_control_points += r_nurbs_degree; + } + return r_tot_control_points; +} + +/** + * Get the degree of the NURBS spline at the given index. + */ +int OBJCurve::get_nurbs_degree(const int spline_index) const +{ + const Nurb *const nurb = static_cast<Nurb *>(BLI_findlink(&export_curve_->nurb, spline_index)); + return nurb->orderu - 1; +} + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh new file mode 100644 index 00000000000..463e41befb5 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_export_nurbs.hh @@ -0,0 +1,57 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include "BLI_utility_mixins.hh" + +#include "DNA_curve_types.h" + +namespace blender::io::obj { + +/** + * Provides access to the a Curve Object's properties. + * Only #CU_NURBS type is supported. + * + * \note Used for Curves to be exported in parameter form, and not converted to meshes. + */ +class OBJCurve : NonCopyable { + private: + const Object *export_object_eval_; + const Curve *export_curve_; + float world_axes_transform_[4][4]; + + public: + OBJCurve(const Depsgraph *depsgraph, const OBJExportParams &export_params, Object *curve_object); + + const char *get_curve_name() const; + int total_splines() const; + int total_spline_vertices(const int spline_index) const; + float3 vertex_coordinates(const int spline_index, + const int vertex_index, + const float scaling_factor) const; + int total_spline_control_points(const int spline_index) const; + int get_nurbs_degree(const int spline_index) const; + + private: + void set_world_axes_transform(const eTransformAxisForward forward, const eTransformAxisUp up); +}; + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.cc b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc new file mode 100644 index 00000000000..d15d053adc9 --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.cc @@ -0,0 +1,302 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#include <cstdio> +#include <exception> +#include <memory> + +#include "BKE_scene.h" + +#include "BLI_path_util.h" +#include "BLI_vector.hh" + +#include "DEG_depsgraph_query.h" + +#include "DNA_scene_types.h" + +#include "ED_object.h" + +#include "obj_export_mesh.hh" +#include "obj_export_nurbs.hh" +#include "obj_exporter.hh" + +#include "obj_export_file_writer.hh" + +namespace blender::io::obj { + +OBJDepsgraph::OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode) +{ + Scene *scene = CTX_data_scene(C); + Main *bmain = CTX_data_main(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + if (eval_mode == DAG_EVAL_RENDER) { + depsgraph_ = DEG_graph_new(bmain, scene, view_layer, DAG_EVAL_RENDER); + needs_free_ = true; + DEG_graph_build_for_all_objects(depsgraph_); + BKE_scene_graph_evaluated_ensure(depsgraph_, bmain); + } + else { + depsgraph_ = CTX_data_ensure_evaluated_depsgraph(C); + needs_free_ = false; + } +} + +OBJDepsgraph::~OBJDepsgraph() +{ + if (needs_free_) { + DEG_graph_free(depsgraph_); + } +} + +Depsgraph *OBJDepsgraph::get() +{ + return depsgraph_; +} + +void OBJDepsgraph::update_for_newframe() +{ + BKE_scene_graph_update_for_newframe(depsgraph_); +} + +static void print_exception_error(const std::system_error &ex) +{ + std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message() + << std::endl; +} + +/** + * Filter supported objects from the Scene. + * + * \note Curves are also stored with Meshes if export settings specify so. + */ +std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>> +filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params) +{ + Vector<std::unique_ptr<OBJMesh>> r_exportable_meshes; + Vector<std::unique_ptr<OBJCurve>> r_exportable_nurbs; + const ViewLayer *view_layer = DEG_get_input_view_layer(depsgraph); + LISTBASE_FOREACH (const Base *, base, &view_layer->object_bases) { + Object *object_in_layer = base->object; + if (export_params.export_selected_objects && !(object_in_layer->base_flag & BASE_SELECTED)) { + continue; + } + switch (object_in_layer->type) { + case OB_SURF: + /* Export in mesh form: vertices and polygons. */ + ATTR_FALLTHROUGH; + case OB_MESH: + r_exportable_meshes.append( + std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + break; + case OB_CURVE: { + Curve *curve = static_cast<Curve *>(object_in_layer->data); + Nurb *nurb{static_cast<Nurb *>(curve->nurb.first)}; + if (!nurb) { + /* An empty curve. Not yet supported to export these as meshes. */ + if (export_params.export_curves_as_nurbs) { + r_exportable_nurbs.append( + std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer)); + } + break; + } + switch (nurb->type) { + case CU_NURBS: + if (export_params.export_curves_as_nurbs) { + /* Export in parameter form: control points. */ + r_exportable_nurbs.append( + std::make_unique<OBJCurve>(depsgraph, export_params, object_in_layer)); + } + else { + /* Export in mesh form: edges and vertices. */ + r_exportable_meshes.append( + std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + } + break; + case CU_BEZIER: + /* Always export in mesh form: edges and vertices. */ + r_exportable_meshes.append( + std::make_unique<OBJMesh>(depsgraph, export_params, object_in_layer)); + break; + default: + /* Other curve types are not supported. */ + break; + } + break; + } + default: + /* Other object types are not supported. */ + break; + } + } + return {std::move(r_exportable_meshes), std::move(r_exportable_nurbs)}; +} + +static void write_mesh_objects(Vector<std::unique_ptr<OBJMesh>> exportable_as_mesh, + OBJWriter &obj_writer, + MTLWriter *mtl_writer, + const OBJExportParams &export_params) +{ + if (mtl_writer) { + obj_writer.write_mtllib_name(mtl_writer->mtl_file_path()); + } + + /* Smooth groups and UV vertex indices may make huge memory allocations, so they should be freed + * right after they're written, instead of waiting for #blender::Vector to clean them up after + * all the objects are exported. */ + for (auto &obj_mesh : exportable_as_mesh) { + obj_writer.write_object_name(*obj_mesh); + obj_writer.write_vertex_coords(*obj_mesh); + Vector<int> obj_mtlindices; + + if (obj_mesh->tot_polygons() > 0) { + if (export_params.export_smooth_groups) { + obj_mesh->calc_smooth_groups(export_params.smooth_groups_bitflags); + } + if (export_params.export_normals) { + obj_writer.write_poly_normals(*obj_mesh); + } + if (export_params.export_uv) { + obj_writer.write_uv_coords(*obj_mesh); + } + if (mtl_writer) { + obj_mtlindices = mtl_writer->add_materials(*obj_mesh); + } + /* This function takes a 0-indexed slot index for the obj_mesh object and + * returns the material name that we are using in the .obj file for it. */ + std::function<const char *(int)> matname_fn = [&](int s) -> const char * { + if (!mtl_writer || s < 0 || s >= obj_mtlindices.size()) { + return nullptr; + } + return mtl_writer->mtlmaterial_name(obj_mtlindices[s]); + }; + obj_writer.write_poly_elements(*obj_mesh, matname_fn); + } + obj_writer.write_edges_indices(*obj_mesh); + + obj_writer.update_index_offsets(*obj_mesh); + } +} + +/** + * Export NURBS Curves in parameter form, not as vertices and edges. + */ +static void write_nurbs_curve_objects(const Vector<std::unique_ptr<OBJCurve>> &exportable_as_nurbs, + const OBJWriter &obj_writer) +{ + /* #OBJCurve doesn't have any dynamically allocated memory, so it's fine + * to wait for #blender::Vector to clean the objects up. */ + for (const std::unique_ptr<OBJCurve> &obj_curve : exportable_as_nurbs) { + obj_writer.write_nurbs_curve(*obj_curve); + } +} + +/** + * Export a single frame to a .OBJ file. + * + * Conditionally write a .MTL file also. + */ +void export_frame(Depsgraph *depsgraph, const OBJExportParams &export_params, const char *filepath) +{ + std::unique_ptr<OBJWriter> frame_writer = nullptr; + try { + frame_writer = std::make_unique<OBJWriter>(filepath, export_params); + } + catch (const std::system_error &ex) { + print_exception_error(ex); + return; + } + if (!frame_writer) { + BLI_assert(!"File should be writable by now."); + return; + } + std::unique_ptr<MTLWriter> mtl_writer = nullptr; + if (export_params.export_materials) { + try { + mtl_writer = std::make_unique<MTLWriter>(export_params.filepath); + } + catch (const std::system_error &ex) { + print_exception_error(ex); + } + } + + frame_writer->write_header(); + + auto [exportable_as_mesh, exportable_as_nurbs] = filter_supported_objects(depsgraph, + export_params); + + write_mesh_objects( + std::move(exportable_as_mesh), *frame_writer, mtl_writer.get(), export_params); + if (mtl_writer) { + mtl_writer->write_header(export_params.blen_filepath); + mtl_writer->write_materials(); + } + write_nurbs_curve_objects(std::move(exportable_as_nurbs), *frame_writer); +} + +/** + * Append the current frame number in the .OBJ file name. + * + * \return Whether the filepath is in #FILE_MAX limits. + */ +bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames) +{ + BLI_strncpy(r_filepath_with_frames, filepath, FILE_MAX); + BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, ""); + const int digits = frame == 0 ? 1 : integer_digits_i(abs(frame)); + BLI_path_frame(r_filepath_with_frames, frame, digits); + return BLI_path_extension_replace(r_filepath_with_frames, FILE_MAX, ".obj"); +} + +/** + * Central internal function to call Scene update & writer functions. + */ +void exporter_main(bContext *C, const OBJExportParams &export_params) +{ + ED_object_mode_set(C, OB_MODE_OBJECT); + OBJDepsgraph obj_depsgraph(C, export_params.export_eval_mode); + Scene *scene = DEG_get_input_scene(obj_depsgraph.get()); + const char *filepath = export_params.filepath; + + /* Single frame export, i.e. no animation. */ + if (!export_params.export_animation) { + fprintf(stderr, "Writing to %s\n", filepath); + export_frame(obj_depsgraph.get(), export_params, filepath); + return; + } + + char filepath_with_frames[FILE_MAX]; + /* Used to reset the Scene to its original state. */ + const int original_frame = CFRA; + + for (int frame = export_params.start_frame; frame <= export_params.end_frame; frame++) { + const bool filepath_ok = append_frame_to_filename(filepath, frame, filepath_with_frames); + if (!filepath_ok) { + fprintf(stderr, "Error: File Path too long.\n%s\n", filepath_with_frames); + return; + } + + CFRA = frame; + obj_depsgraph.update_for_newframe(); + fprintf(stderr, "Writing to %s\n", filepath_with_frames); + export_frame(obj_depsgraph.get(), export_params, filepath_with_frames); + } + CFRA = original_frame; +} +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/exporter/obj_exporter.hh b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh new file mode 100644 index 00000000000..e02a240b51a --- /dev/null +++ b/source/blender/io/wavefront_obj/exporter/obj_exporter.hh @@ -0,0 +1,88 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup obj + */ + +#pragma once + +#include "BLI_utility_mixins.hh" + +#include "BLI_vector.hh" + +#include "IO_wavefront_obj.h" + +namespace blender::io::obj { + +/** + * Behaves like `std::unique_ptr<Depsgraph, custom_deleter>`. + * Needed to free a new Depsgraph created for #DAG_EVAL_RENDER. + */ +class OBJDepsgraph : NonMovable, NonCopyable { + private: + Depsgraph *depsgraph_ = nullptr; + bool needs_free_ = false; + + public: + OBJDepsgraph(const bContext *C, const eEvaluationMode eval_mode); + ~OBJDepsgraph(); + + Depsgraph *get(); + void update_for_newframe(); +}; + +/** + * The main function for exporting a .obj file according to the given `export_parameters`. + * It uses the context `C` to get the dependency graph, and from that, the `Scene`. + * Depending on whether or not `export_params.export_animation` is set, it writes + * either one file per animation frame, or just one file. + */ +void exporter_main(bContext *C, const OBJExportParams &export_params); + +class OBJMesh; +class OBJCurve; + +/** + * Export a single frame of a .obj file, according to the given `export_parameters`. + * The frame state is given in `depsgraph`. + * The output file name is given by `filepath`. + * This function is normally called from `exporter_main`, but is exposed here for testing purposes. + */ +void export_frame(Depsgraph *depsgraph, + const OBJExportParams &export_params, + const char *filepath); + +/** + * Find the objects to be exported in the `view_layer` of the dependency graph`depsgraph`, + * and return them in vectors `unique_ptr`s of `OBJMesh` and `OBJCurve`. + * If `export_params.export_selected_objects` is set, then only selected objects are to be + * exported, else all objects are to be exported. But only objects of type `OB_MESH`, `OB_CURVE`, + * and `OB_SURF` are supported; the rest will be ignored. If `export_params.export_curves_as_nurbs` + * is set, then curves of type `CU_NURBS` are exported in curve form in the .obj file, otherwise + * they are converted to mesh and returned in the `OBJMesh` vector. All other exportable types are + * always converted to mesh and returned in the `OBJMesh` vector. + */ +std::pair<Vector<std::unique_ptr<OBJMesh>>, Vector<std::unique_ptr<OBJCurve>>> +filter_supported_objects(Depsgraph *depsgraph, const OBJExportParams &export_params); + +/** + * Makes `r_filepath_with_frames` (which should point at a character array of size `FILE_MAX`) + * be `filepath` with its "#" characters replaced by the number representing `frame`, and with + * a .obj extension. + */ +bool append_frame_to_filename(const char *filepath, const int frame, char *r_filepath_with_frames); +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc new file mode 100644 index 00000000000..f12bfd0cea5 --- /dev/null +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.cc @@ -0,0 +1,417 @@ +/* Apache License, Version 2.0 */ + +#include <fstream> +#include <gtest/gtest.h> +#include <ios> +#include <memory> +#include <sstream> +#include <string> +#include <system_error> + +#include "testing/testing.h" +#include "tests/blendfile_loading_base_test.h" + +#include "BKE_appdir.h" +#include "BKE_blender_version.h" + +#include "BLI_fileops.h" +#include "BLI_index_range.hh" +#include "BLI_string_utf8.h" +#include "BLI_vector.hh" + +#include "DEG_depsgraph.h" + +#include "obj_export_file_writer.hh" +#include "obj_export_mesh.hh" +#include "obj_export_nurbs.hh" +#include "obj_exporter.hh" + +#include "obj_exporter_tests.hh" + +namespace blender::io::obj { + +/* This is also the test name. */ +class obj_exporter_test : public BlendfileLoadingBaseTest { + public: + /** + * \param filepath: relative to "tests" directory. + */ + bool load_file_and_depsgraph(const std::string &filepath, + const eEvaluationMode eval_mode = DAG_EVAL_VIEWPORT) + { + if (!blendfile_load(filepath.c_str())) { + return false; + } + depsgraph_create(eval_mode); + return true; + } +}; + +const std::string all_objects_file = "io_tests/blend_scene/all_objects.blend"; +const std::string all_curve_objects_file = "io_tests/blend_scene/all_curves.blend"; + +TEST_F(obj_exporter_test, filter_objects_curves_as_mesh) +{ + OBJExportParamsDefault _export; + if (!load_file_and_depsgraph(all_objects_file)) { + ADD_FAILURE(); + return; + } + auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; + EXPECT_EQ(objmeshes.size(), 17); + EXPECT_EQ(objcurves.size(), 0); +} + +TEST_F(obj_exporter_test, filter_objects_curves_as_nurbs) +{ + OBJExportParamsDefault _export; + if (!load_file_and_depsgraph(all_objects_file)) { + ADD_FAILURE(); + return; + } + _export.params.export_curves_as_nurbs = true; + auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; + EXPECT_EQ(objmeshes.size(), 16); + EXPECT_EQ(objcurves.size(), 2); +} + +TEST_F(obj_exporter_test, filter_objects_selected) +{ + OBJExportParamsDefault _export; + if (!load_file_and_depsgraph(all_objects_file)) { + ADD_FAILURE(); + return; + } + _export.params.export_selected_objects = true; + _export.params.export_curves_as_nurbs = true; + auto [objmeshes, objcurves]{filter_supported_objects(depsgraph, _export.params)}; + EXPECT_EQ(objmeshes.size(), 1); + EXPECT_EQ(objcurves.size(), 0); +} + +TEST(obj_exporter_utils, append_negative_frame_to_filename) +{ + const char path_original[FILE_MAX] = "/my_file.obj"; + const char path_truth[FILE_MAX] = "/my_file-123.obj"; + const int frame = -123; + char path_with_frame[FILE_MAX] = {0}; + const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); + EXPECT_TRUE(ok); + EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); +} + +TEST(obj_exporter_utils, append_positive_frame_to_filename) +{ + const char path_original[FILE_MAX] = "/my_file.obj"; + const char path_truth[FILE_MAX] = "/my_file123.obj"; + const int frame = 123; + char path_with_frame[FILE_MAX] = {0}; + const bool ok = append_frame_to_filename(path_original, frame, path_with_frame); + EXPECT_TRUE(ok); + EXPECT_EQ_ARRAY(path_with_frame, path_truth, BLI_strlen_utf8(path_truth)); +} + +TEST_F(obj_exporter_test, curve_nurbs_points) +{ + if (!load_file_and_depsgraph(all_curve_objects_file)) { + ADD_FAILURE(); + return; + } + + OBJExportParamsDefault _export; + _export.params.export_curves_as_nurbs = true; + auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)}; + + for (auto &objcurve : objcurves) { + if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) { + ADD_FAILURE(); + return; + } + const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get(); + EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines()); + for (int spline_index : IndexRange(objcurve->total_splines())) { + EXPECT_EQ(objcurve->total_spline_vertices(spline_index), + nurbs_truth->total_spline_vertices(spline_index)); + EXPECT_EQ(objcurve->get_nurbs_degree(spline_index), + nurbs_truth->get_nurbs_degree(spline_index)); + EXPECT_EQ(objcurve->total_spline_control_points(spline_index), + nurbs_truth->total_spline_control_points(spline_index)); + } + } +} + +TEST_F(obj_exporter_test, curve_coordinates) +{ + if (!load_file_and_depsgraph(all_curve_objects_file)) { + ADD_FAILURE(); + return; + } + + OBJExportParamsDefault _export; + _export.params.export_curves_as_nurbs = true; + auto [objmeshes_unused, objcurves]{filter_supported_objects(depsgraph, _export.params)}; + + for (auto &objcurve : objcurves) { + if (all_nurbs_truth.count(objcurve->get_curve_name()) != 1) { + ADD_FAILURE(); + return; + } + const NurbsObject *const nurbs_truth = all_nurbs_truth.at(objcurve->get_curve_name()).get(); + EXPECT_EQ(objcurve->total_splines(), nurbs_truth->total_splines()); + for (int spline_index : IndexRange(objcurve->total_splines())) { + for (int vertex_index : IndexRange(objcurve->total_spline_vertices(spline_index))) { + EXPECT_V3_NEAR(objcurve->vertex_coordinates( + spline_index, vertex_index, _export.params.scaling_factor), + nurbs_truth->vertex_coordinates(spline_index, vertex_index), + 0.000001f); + } + } + } +} + +static std::unique_ptr<OBJWriter> init_writer(const OBJExportParams ¶ms, + const std::string out_filepath) +{ + try { + auto writer = std::make_unique<OBJWriter>(out_filepath.c_str(), params); + return writer; + } + catch (const std::system_error &ex) { + std::cerr << ex.code().category().name() << ": " << ex.what() << ": " << ex.code().message() + << std::endl; + return nullptr; + } +} + +/* The following is relative to BKE_tempdir_base. */ +const char *const temp_file_path = "output.OBJ"; + +static std::string read_temp_file_in_string(const std::string &file_path) +{ + std::ifstream temp_stream(file_path); + std::ostringstream input_ss; + input_ss << temp_stream.rdbuf(); + return input_ss.str(); +} + +TEST(obj_exporter_writer, header) +{ + /* Because testing doesn't fully initialize Blender, we need the following. */ + BKE_tempdir_init(NULL); + std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path; + { + OBJExportParamsDefault _export; + std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path); + if (!writer) { + ADD_FAILURE(); + return; + } + writer->write_header(); + } + const std::string result = read_temp_file_in_string(out_file_path); + using namespace std::string_literals; + ASSERT_EQ(result, "# Blender "s + BKE_blender_version_string() + "\n" + "# www.blender.org\n"); + BLI_delete(out_file_path.c_str(), false, false); +} + +TEST(obj_exporter_writer, mtllib) +{ + std::string out_file_path = blender::tests::flags_test_release_dir() + "/" + temp_file_path; + { + OBJExportParamsDefault _export; + std::unique_ptr<OBJWriter> writer = init_writer(_export.params, out_file_path); + if (!writer) { + ADD_FAILURE(); + return; + } + writer->write_mtllib_name("/Users/blah.mtl"); + writer->write_mtllib_name("\\C:\\blah.mtl"); + } + const std::string result = read_temp_file_in_string(out_file_path); + ASSERT_EQ(result, "mtllib blah.mtl\nmtllib blah.mtl\n"); +} + +/* Return true if string #a and string #b are equal after their first newline. */ +static bool strings_equal_after_first_lines(const std::string &a, const std::string &b) +{ + /* If `dbg_level > 0` then a failing test will print context around the first mismatch. */ + const bool dbg_level = 0; + const size_t a_len = a.size(); + const size_t b_len = b.size(); + const size_t a_next = a.find_first_of('\n'); + const size_t b_next = b.find_first_of('\n'); + if (a_next == std::string::npos || b_next == std::string::npos) { + if (dbg_level > 0) { + std::cout << "Couldn't find newline in one of args\n"; + } + return false; + } + if (dbg_level > 0) { + if (a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) != 0) { + for (int i = 0; i < a_len - a_next && i < b_len - b_next; ++i) { + if (a[a_next + i] != b[b_next + i]) { + std::cout << "Difference found at pos " << a_next + i << " of a\n"; + std::cout << "a: " << a.substr(a_next + i, 100) << " ...\n"; + std::cout << "b: " << b.substr(b_next + i, 100) << " ... \n"; + return false; + } + } + } + else { + return true; + } + } + return a.compare(a_next, a_len - a_next, b, b_next, b_len - b_next) == 0; +} + +/* From here on, tests are whole file tests, testing for golden output. */ +class obj_exporter_regression_test : public obj_exporter_test { + public: + /** + * Export the given blend file with the given parameters and + * test to see if it matches a golden file (ignoring any difference in Blender version number). + * \param blendfile: input, relative to "tests" directory. + * \param golden_obj: expected output, relative to "tests" directory. + * \param params: the parameters to be used for export. + */ + void compare_obj_export_to_golden(const std::string &blendfile, + const std::string &golden_obj, + const std::string &golden_mtl, + OBJExportParams ¶ms) + { + if (!load_file_and_depsgraph(blendfile)) { + return; + } + /* Because testing doesn't fully initialize Blender, we need the following. */ + BKE_tempdir_init(NULL); + std::string tempdir = std::string(BKE_tempdir_base()); + std::string out_file_path = tempdir + BLI_path_basename(golden_obj.c_str()); + strncpy(params.filepath, out_file_path.c_str(), FILE_MAX); + params.blen_filepath = blendfile.c_str(); + export_frame(depsgraph, params, out_file_path.c_str()); + std::string output_str = read_temp_file_in_string(out_file_path); + + std::string golden_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_obj; + std::string golden_str = read_temp_file_in_string(golden_file_path); + ASSERT_TRUE(strings_equal_after_first_lines(output_str, golden_str)); + BLI_delete(out_file_path.c_str(), false, false); + if (!golden_mtl.empty()) { + std::string out_mtl_file_path = tempdir + BLI_path_basename(golden_mtl.c_str()); + std::string output_mtl_str = read_temp_file_in_string(out_mtl_file_path); + std::string golden_mtl_file_path = blender::tests::flags_test_asset_dir() + "/" + golden_mtl; + std::string golden_mtl_str = read_temp_file_in_string(golden_mtl_file_path); + ASSERT_TRUE(strings_equal_after_first_lines(output_mtl_str, golden_mtl_str)); + BLI_delete(out_mtl_file_path.c_str(), false, false); + } + } +}; + +TEST_F(obj_exporter_regression_test, all_tris) +{ + OBJExportParamsDefault _export; + compare_obj_export_to_golden("io_tests/blend_geometry/all_tris.blend", + "io_tests/obj/all_tris.obj", + "io_tests/obj/all_tris.mtl", + _export.params); +} + +TEST_F(obj_exporter_regression_test, all_quads) +{ + OBJExportParamsDefault _export; + _export.params.scaling_factor = 2.0f; + _export.params.export_materials = false; + compare_obj_export_to_golden( + "io_tests/blend_geometry/all_quads.blend", "io_tests/obj/all_quads.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, fgons) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + compare_obj_export_to_golden( + "io_tests/blend_geometry/fgons.blend", "io_tests/obj/fgons.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, edges) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + compare_obj_export_to_golden( + "io_tests/blend_geometry/edges.blend", "io_tests/obj/edges.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, vertices) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + compare_obj_export_to_golden( + "io_tests/blend_geometry/vertices.blend", "io_tests/obj/vertices.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, nurbs_as_nurbs) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + _export.params.export_curves_as_nurbs = true; + compare_obj_export_to_golden( + "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, nurbs_as_mesh) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + _export.params.export_curves_as_nurbs = false; + compare_obj_export_to_golden( + "io_tests/blend_geometry/nurbs.blend", "io_tests/obj/nurbs_mesh.obj", "", _export.params); +} + +TEST_F(obj_exporter_regression_test, cube_all_data_triangulated) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + _export.params.export_triangulated_mesh = true; + compare_obj_export_to_golden("io_tests/blend_geometry/cube_all_data.blend", + "io_tests/obj/cube_all_data_triangulated.obj", + "", + _export.params); +} + +TEST_F(obj_exporter_regression_test, suzanne_all_data) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_materials = false; + _export.params.export_smooth_groups = true; + compare_obj_export_to_golden("io_tests/blend_geometry/suzanne_all_data.blend", + "io_tests/obj/suzanne_all_data.obj", + "", + _export.params); +} + +TEST_F(obj_exporter_regression_test, all_objects) +{ + OBJExportParamsDefault _export; + _export.params.forward_axis = OBJ_AXIS_Y_FORWARD; + _export.params.up_axis = OBJ_AXIS_Z_UP; + _export.params.export_smooth_groups = true; + compare_obj_export_to_golden("io_tests/blend_scene/all_objects.blend", + "io_tests/obj/all_objects.obj", + "io_tests/obj/all_objects.mtl", + _export.params); +} + +} // namespace blender::io::obj diff --git a/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh new file mode 100644 index 00000000000..def70eff0ee --- /dev/null +++ b/source/blender/io/wavefront_obj/tests/obj_exporter_tests.hh @@ -0,0 +1,149 @@ +/* Apache License, Version 2.0 */ + +/** + * This file contains default values for several items like + * vertex coordinates, export parameters, MTL values etc. + */ + +#pragma once + +#include <array> +#include <gtest/gtest.h> +#include <string> +#include <vector> + +#include "IO_wavefront_obj.h" + +namespace blender::io::obj { + +using array_float_3 = std::array<float, 3>; + +/** + * This matches #OBJCurve's member functions, except that all the numbers and names are known + * constants. Used to store expected values of NURBS Curve sobjects. + */ +class NurbsObject { + private: + std::string nurbs_name_; + /* The indices in these vectors are spline indices. */ + std::vector<std::vector<array_float_3>> coordinates_; + std::vector<int> degrees_; + std::vector<int> control_points_; + + public: + NurbsObject(const std::string nurbs_name, + const std::vector<std::vector<array_float_3>> coordinates, + const std::vector<int> degrees, + const std::vector<int> control_points) + : nurbs_name_(nurbs_name), + coordinates_(coordinates), + degrees_(degrees), + control_points_(control_points) + { + } + + int total_splines() const + { + return coordinates_.size(); + } + + int total_spline_vertices(const int spline_index) const + { + if (spline_index >= coordinates_.size()) { + ADD_FAILURE(); + return 0; + } + return coordinates_[spline_index].size(); + } + + const float *vertex_coordinates(const int spline_index, const int vertex_index) const + { + return coordinates_[spline_index][vertex_index].data(); + } + + int get_nurbs_degree(const int spline_index) const + { + return degrees_[spline_index]; + } + + int total_spline_control_points(const int spline_index) const + { + return control_points_[spline_index]; + } +}; + +struct OBJExportParamsDefault { + OBJExportParams params; + OBJExportParamsDefault() + { + params.filepath[0] = '\0'; + params.blen_filepath = ""; + params.export_animation = false; + params.start_frame = 0; + params.end_frame = 1; + + params.forward_axis = OBJ_AXIS_NEGATIVE_Z_FORWARD; + params.up_axis = OBJ_AXIS_Y_UP; + params.scaling_factor = 1.f; + + params.export_eval_mode = DAG_EVAL_VIEWPORT; + params.export_selected_objects = false; + params.export_uv = true; + params.export_normals = true; + params.export_materials = true; + params.export_triangulated_mesh = false; + params.export_curves_as_nurbs = false; + + params.export_object_groups = false; + params.export_material_groups = false; + params.export_vertex_groups = false; + params.export_smooth_groups = true; + params.smooth_groups_bitflags = false; + } +}; + +const std::vector<std::vector<array_float_3>> coordinates_NurbsCurve{ + {{6.94742, 0.000000, 0.000000}, + {7.44742, 0.000000, -1.000000}, + {9.44742, 0.000000, -1.000000}, + {9.94742, 0.000000, 0.000000}}}; +const std::vector<std::vector<array_float_3>> coordinates_NurbsCircle{ + {{11.463165, 0.000000, 1.000000}, + {10.463165, 0.000000, 1.000000}, + {10.463165, 0.000000, 0.000000}, + {10.463165, 0.000000, -1.000000}, + {11.463165, 0.000000, -1.000000}, + {12.463165, 0.000000, -1.000000}, + {12.463165, 0.000000, 0.000000}, + {12.463165, 0.000000, 1.000000}}}; +const std::vector<std::vector<array_float_3>> coordinates_NurbsPathCurve{ + {{13.690557, 0.000000, 0.000000}, + {14.690557, 0.000000, 0.000000}, + {15.690557, 0.000000, 0.000000}, + {16.690557, 0.000000, 0.000000}, + {17.690557, 0.000000, 0.000000}}, + {{14.192808, 0.000000, 0.000000}, + {14.692808, 0.000000, -1.000000}, + {16.692808, 0.000000, -1.000000}, + {17.192808, 0.000000, 0.000000}}}; + +const std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs_truth = []() { + std::map<std::string, std::unique_ptr<NurbsObject>> all_nurbs; + all_nurbs.emplace( + "NurbsCurve", + /* Name, coordinates, degrees of splines, control points of splines. */ + std::make_unique<NurbsObject>( + "NurbsCurve", coordinates_NurbsCurve, std::vector<int>{3}, std::vector<int>{4})); + all_nurbs.emplace( + "NurbsCircle", + std::make_unique<NurbsObject>( + "NurbsCircle", coordinates_NurbsCircle, std::vector<int>{3}, std::vector<int>{11})); + /* This is actually an Object containing a NurbsPath and a NurbsCurve spline. */ + all_nurbs.emplace("NurbsPathCurve", + std::make_unique<NurbsObject>("NurbsPathCurve", + coordinates_NurbsPathCurve, + std::vector<int>{3, 3}, + std::vector<int>{5, 4})); + return all_nurbs; +}(); +} // namespace blender::io::obj diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 6a478f9abb5..17b3fb302e6 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -802,6 +802,9 @@ typedef enum IDRecalcFlag { */ ID_RECALC_TAG_FOR_UNDO = (1 << 24), + /* The node tree has changed in a way that affects its output nodes. */ + ID_RECALC_NTREE_OUTPUT = (1 << 25), + /*************************************************************************** * Pseudonyms, to have more semantic meaning in the actual code without * using too much low-level and implementation specific tags. */ diff --git a/source/blender/makesdna/DNA_customdata_types.h b/source/blender/makesdna/DNA_customdata_types.h index 36bdd4915ff..787dbc23515 100644 --- a/source/blender/makesdna/DNA_customdata_types.h +++ b/source/blender/makesdna/DNA_customdata_types.h @@ -134,7 +134,6 @@ typedef enum CustomDataType { CD_CLOTH_ORCO = 23, /* CD_RECAST = 24, */ /* UNUSED */ - /* BMESH ONLY START */ CD_MPOLY = 25, CD_MLOOP = 26, CD_SHAPE_KEYINDEX = 27, @@ -144,7 +143,6 @@ typedef enum CustomDataType { CD_ORIGSPACE_MLOOP = 31, CD_PREVIEW_MLOOPCOL = 32, CD_BM_ELEM_PYPTR = 33, - /* BMESH ONLY END */ CD_PAINT_MASK = 34, CD_GRID_PAINT_MASK = 35, @@ -164,7 +162,6 @@ typedef enum CustomDataType { CD_PROP_COLOR = 47, CD_PROP_FLOAT3 = 48, CD_PROP_FLOAT2 = 49, - CD_PROP_BOOL = 50, CD_HAIRLENGTH = 51, @@ -197,7 +194,6 @@ typedef enum CustomDataType { #define CD_MASK_CLOTH_ORCO (1 << CD_CLOTH_ORCO) // #define CD_MASK_RECAST (1 << CD_RECAST) /* DEPRECATED */ -/* BMESH ONLY START */ #define CD_MASK_MPOLY (1 << CD_MPOLY) #define CD_MASK_MLOOP (1 << CD_MLOOP) #define CD_MASK_SHAPE_KEYINDEX (1 << CD_SHAPE_KEYINDEX) @@ -207,7 +203,6 @@ typedef enum CustomDataType { #define CD_MASK_ORIGSPACE_MLOOP (1LL << CD_ORIGSPACE_MLOOP) #define CD_MASK_PREVIEW_MLOOPCOL (1LL << CD_PREVIEW_MLOOPCOL) #define CD_MASK_BM_ELEM_PYPTR (1LL << CD_BM_ELEM_PYPTR) -/* BMESH ONLY END */ #define CD_MASK_PAINT_MASK (1LL << CD_PAINT_MASK) #define CD_MASK_GRID_PAINT_MASK (1LL << CD_GRID_PAINT_MASK) diff --git a/source/blender/makesdna/DNA_mesh_types.h b/source/blender/makesdna/DNA_mesh_types.h index 77cb553c7c7..94e88bdaca6 100644 --- a/source/blender/makesdna/DNA_mesh_types.h +++ b/source/blender/makesdna/DNA_mesh_types.h @@ -74,7 +74,7 @@ struct MLoopTri_Store { int len_alloc; }; -/* Runtime data, not saved in files. */ +/** Runtime data, not saved in files. */ typedef struct Mesh_Runtime { /* Evaluated mesh for objects which do not have effective modifiers. * This mesh is used as a result of modifier stack evaluation. @@ -138,6 +138,15 @@ typedef struct Mesh_Runtime { int64_t cd_dirty_loop; int64_t cd_dirty_poly; + /** + * Settings for lazily evaluating the subdivision on the CPU if needed. These are + * set in the modifier when GPU subdivision can be performed. + */ + char subsurf_apply_render; + char subsurf_use_optimal_display; + char _pad[2]; + int subsurf_resolution; + } Mesh_Runtime; typedef struct Mesh { @@ -356,16 +365,17 @@ typedef enum eMeshWrapperType { ME_WRAPPER_TYPE_MDATA = 0, /** Use edit-mesh data (#Mesh.edit_mesh, #Mesh_Runtime.edit_data). */ ME_WRAPPER_TYPE_BMESH = 1, - /* ME_WRAPPER_TYPE_SUBD = 2, */ /* TODO */ + /** Use subdivision mesh data (#Mesh_Runtime.mesh_eval). */ + ME_WRAPPER_TYPE_SUBD = 2, } eMeshWrapperType; -/* texflag */ +/** #Mesh.texflag */ enum { ME_AUTOSPACE = 1, ME_AUTOSPACE_EVALUATED = 2, }; -/* me->editflag */ +/** #Mesh.editflag */ enum { ME_EDIT_MIRROR_VERTEX_GROUPS = 1 << 0, ME_EDIT_MIRROR_Y = 1 << 1, /* unused so far */ @@ -387,7 +397,7 @@ enum { ((_me)->editflag & ME_EDIT_PAINT_VERT_SEL) ? SCE_SELECT_VERTEX : \ 0) -/* me->flag */ +/** #Mesh.flag */ enum { ME_FLAG_UNUSED_0 = 1 << 0, /* cleared */ ME_FLAG_UNUSED_1 = 1 << 1, /* cleared */ @@ -407,26 +417,26 @@ enum { ME_REMESH_REPROJECT_SCULPT_FACE_SETS = 1 << 15, }; -/* me->cd_flag */ +/** #Mesh.cd_flag */ enum { ME_CDFLAG_VERT_BWEIGHT = 1 << 0, ME_CDFLAG_EDGE_BWEIGHT = 1 << 1, ME_CDFLAG_EDGE_CREASE = 1 << 2, }; -/* me->remesh_mode */ +/** #Mesh.remesh_mode */ enum { REMESH_VOXEL = 0, REMESH_QUAD = 1, }; -/* Subsurf Type */ +/** #SubsurfModifierData.subdivType */ enum { ME_CC_SUBSURF = 0, ME_SIMPLE_SUBSURF = 1, }; -/* me->symmetry */ +/** #Mesh.symmetry */ typedef enum eMeshSymmetryType { ME_SYMMETRY_X = 1 << 0, ME_SYMMETRY_Y = 1 << 1, diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index f7a468264c3..fc041e257b0 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -121,28 +121,28 @@ typedef struct ModifierData { int type, mode; char _pad0[4]; short flag; - /* An "expand" bit for each of the modifier's (sub)panels (uiPanelDataExpansion). */ + /** An "expand" bit for each of the modifier's (sub)panels (#uiPanelDataExpansion). */ short ui_expand_flag; /** MAX_NAME. */ char name[64]; char *error; - /* Pointer to a ModifierData in the original domain. */ + /** Pointer to a #ModifierData in the original domain. */ struct ModifierData *orig_modifier_data; - /* Runtime field which contains unique identifier of the modifier. */ + /** Runtime field which contains unique identifier of the modifier. */ SessionUUID session_uuid; - /* Runtime field which contains runtime data which is specific to a modifier type. */ + /** Runtime field which contains runtime data which is specific to a modifier type. */ void *runtime; void *_pad1; } ModifierData; typedef enum { - /* This modifier has been inserted in local override, and hence can be fully edited. */ + /** This modifier has been inserted in local override, and hence can be fully edited. */ eModifierFlag_OverrideLibrary_Local = (1 << 0), - /* This modifier does not own its caches, but instead shares them with another modifier. */ + /** This modifier does not own its caches, but instead shares them with another modifier. */ eModifierFlag_SharedCaches = (1 << 1), /** * This modifier is the object's active modifier. Used for context in the node editor. @@ -151,7 +151,9 @@ typedef enum { eModifierFlag_Active = (1 << 2), } ModifierFlag; -/* not a real modifier */ +/** + * \note Not a real modifier. + */ typedef struct MappingInfoModifierData { ModifierData modifier; @@ -194,6 +196,13 @@ typedef enum { SUBSURF_BOUNDARY_SMOOTH_PRESERVE_CORNERS = 1, } eSubsurfBoundarySmooth; +typedef struct SubsurfRuntimeData { + /* Cached subdivision surface descriptor, with topology and settings. */ + struct Subdiv *subdiv; + char set_by_draw_code; + char _pad[7]; +} SubsurfRuntimeData; + typedef struct SubsurfModifierData { ModifierData modifier; @@ -219,7 +228,7 @@ typedef struct LatticeModifierData { void *_pad1; } LatticeModifierData; -/* Lattice modifier flags. */ +/** #LatticeModifierData.flag */ enum { MOD_LATTICE_INVERT_VGROUP = (1 << 0), }; @@ -237,12 +246,12 @@ typedef struct CurveModifierData { void *_pad1; } CurveModifierData; -/* Curve modifier flags */ +/** #CurveModifierData.flag */ enum { MOD_CURVE_INVERT_VGROUP = (1 << 0), }; -/* CurveModifierData->defaxis */ +/** #CurveModifierData.defaxis */ enum { MOD_CURVE_POSX = 1, MOD_CURVE_POSY = 2, @@ -264,7 +273,7 @@ typedef struct BuildModifierData { int seed; } BuildModifierData; -/* Build Modifier -> flag */ +/** #BuildModifierData.flag */ enum { /** order of vertices is randomized */ MOD_BUILD_FLAG_RANDOMIZE = (1 << 0), @@ -272,7 +281,7 @@ enum { MOD_BUILD_FLAG_REVERSE = (1 << 1), }; -/* Mask Modifier */ +/** Mask Modifier. */ typedef struct MaskModifierData { ModifierData modifier; @@ -289,13 +298,13 @@ typedef struct MaskModifierData { void *_pad1; } MaskModifierData; -/* Mask Modifier -> mode */ +/** #MaskModifierData.mode */ enum { MOD_MASK_MODE_VGROUP = 0, MOD_MASK_MODE_ARM = 1, }; -/* Mask Modifier -> flag */ +/** #MaskModifierData.flag */ enum { MOD_MASK_INV = (1 << 0), MOD_MASK_SMOOTH = (1 << 1), @@ -304,63 +313,68 @@ enum { typedef struct ArrayModifierData { ModifierData modifier; - /* the object with which to cap the start of the array. */ + /** The object with which to cap the start of the array. */ struct Object *start_cap; - /* the object with which to cap the end of the array. */ + /** The object with which to cap the end of the array. */ struct Object *end_cap; - /* the curve object to use for MOD_ARR_FITCURVE. */ + /** The curve object to use for #MOD_ARR_FITCURVE. */ struct Object *curve_ob; - /* the object to use for object offset. */ + /** The object to use for object offset. */ struct Object *offset_ob; - /* a constant duplicate offset; - * 1 means the duplicates are 1 unit apart + /** + * A constant duplicate offset; + * 1 means the duplicates are 1 unit apart. */ float offset[3]; - /* a scaled factor for duplicate offsets; - * 1 means the duplicates are 1 object-width apart + /** + * A scaled factor for duplicate offsets; + * 1 means the duplicates are 1 object-width apart. */ float scale[3]; - /* the length over which to distribute the duplicates */ + /** The length over which to distribute the duplicates. */ float length; - /* the limit below which to merge vertices in adjacent duplicates */ + /** The limit below which to merge vertices in adjacent duplicates. */ float merge_dist; - /* determines how duplicate count is calculated; one of: - * - MOD_ARR_FIXEDCOUNT -> fixed - * - MOD_ARR_FITLENGTH -> calculated to fit a set length - * - MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object + /** + * Determines how duplicate count is calculated; one of: + * - #MOD_ARR_FIXEDCOUNT -> fixed. + * - #MOD_ARR_FITLENGTH -> calculated to fit a set length. + * - #MOD_ARR_FITCURVE -> calculated to fit the length of a Curve object. */ int fit_type; - /* flags specifying how total offset is calculated; binary OR of: - * - MOD_ARR_OFF_CONST -> total offset += offset - * - MOD_ARR_OFF_RELATIVE -> total offset += relative * object width - * - MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix - * total offset is the sum of the individual enabled offsets + /** + * Flags specifying how total offset is calculated; binary OR of: + * - #MOD_ARR_OFF_CONST -> total offset += offset. + * - #MOD_ARR_OFF_RELATIVE -> total offset += relative * object width. + * - #MOD_ARR_OFF_OBJ -> total offset += offset_ob's matrix. + * Total offset is the sum of the individual enabled offsets. */ int offset_type; - /* general flags: - * MOD_ARR_MERGE -> merge vertices in adjacent duplicates + /** + * General flags: + * #MOD_ARR_MERGE -> merge vertices in adjacent duplicates. */ int flags; - /* the number of duplicates to generate for MOD_ARR_FIXEDCOUNT */ + /** The number of duplicates to generate for #MOD_ARR_FIXEDCOUNT. */ int count; float uv_offset[2]; } ArrayModifierData; -/* ArrayModifierData->fit_type */ +/** #ArrayModifierData.fit_type */ enum { MOD_ARR_FIXEDCOUNT = 0, MOD_ARR_FITLENGTH = 1, MOD_ARR_FITCURVE = 2, }; -/* ArrayModifierData->offset_type */ +/** #ArrayModifierData.offset_type */ enum { MOD_ARR_OFF_CONST = (1 << 0), MOD_ARR_OFF_RELATIVE = (1 << 1), MOD_ARR_OFF_OBJ = (1 << 2), }; -/* ArrayModifierData->flags */ +/** #ArrayModifierData.flags */ enum { MOD_ARR_MERGE = (1 << 0), MOD_ARR_MERGEFINAL = (1 << 1), @@ -389,7 +403,7 @@ typedef struct MirrorModifierData { void *_pad1; } MirrorModifierData; -/* MirrorModifierData->flag */ +/** #MirrorModifierData.flag */ enum { MOD_MIR_CLIPPING = (1 << 0), MOD_MIR_MIRROR_U = (1 << 1), @@ -416,7 +430,7 @@ typedef struct EdgeSplitModifierData { int flags; } EdgeSplitModifierData; -/* EdgeSplitModifierData->flags */ +/** #EdgeSplitModifierData.flags */ enum { MOD_EDGESPLIT_FROMANGLE = (1 << 1), MOD_EDGESPLIT_FROMFLAG = (1 << 2), @@ -468,7 +482,7 @@ typedef struct BevelModifierData { void *_pad2; } BevelModifierData; -/* BevelModifierData->flags and BevelModifierData->lim_flags */ +/** #BevelModifierData.flags and BevelModifierData.lim_flags */ enum { #ifdef DNA_DEPRECATED_ALLOW MOD_BEVEL_VERT_DEPRECATED = (1 << 1), @@ -491,7 +505,7 @@ enum { MOD_BEVEL_HARDEN_NORMALS = (1 << 15), }; -/* BevelModifierData->val_flags (not used as flags any more) */ +/** #BevelModifierData.val_flags (not used as flags any more) */ enum { MOD_BEVEL_AMT_OFFSET = 0, MOD_BEVEL_AMT_WIDTH = 1, @@ -500,19 +514,19 @@ enum { MOD_BEVEL_AMT_ABSOLUTE = 4, }; -/* BevelModifierData->profile_type */ +/** #BevelModifierData.profile_type */ enum { MOD_BEVEL_PROFILE_SUPERELLIPSE = 0, MOD_BEVEL_PROFILE_CUSTOM = 1, }; -/* BevelModifierData->edge_flags */ +/** #BevelModifierData.edge_flags */ enum { MOD_BEVEL_MARK_SEAM = (1 << 0), MOD_BEVEL_MARK_SHARP = (1 << 1), }; -/* BevelModifierData->face_str_mode */ +/** #BevelModifierData.face_str_mode */ enum { MOD_BEVEL_FACE_STRENGTH_NONE = 0, MOD_BEVEL_FACE_STRENGTH_NEW = 1, @@ -520,20 +534,20 @@ enum { MOD_BEVEL_FACE_STRENGTH_ALL = 3, }; -/* BevelModifier->miter_inner and ->miter_outer */ +/** #BevelModifier.miter_inner & #BevelModifier.miter_outer */ enum { MOD_BEVEL_MITER_SHARP = 0, MOD_BEVEL_MITER_PATCH = 1, MOD_BEVEL_MITER_ARC = 2, }; -/* BevelModifier->vmesh_method */ +/** #BevelModifier.vmesh_method */ enum { MOD_BEVEL_VMESH_ADJ = 0, MOD_BEVEL_VMESH_CUTOFF = 1, }; -/* BevelModifier->affect_type */ +/** #BevelModifier.affect_type */ enum { MOD_BEVEL_AFFECT_VERTICES = 0, MOD_BEVEL_AFFECT_EDGES = 1, @@ -553,7 +567,7 @@ typedef struct FluidModifierData { void *_pad1; } FluidModifierData; -/* Fluid modifier flags */ +/** #FluidModifierData.type */ enum { MOD_FLUID_TYPE_DOMAIN = (1 << 0), MOD_FLUID_TYPE_FLOW = (1 << 1), @@ -563,7 +577,8 @@ enum { typedef struct DisplaceModifierData { ModifierData modifier; - /* keep in sync with MappingInfoModifierData */ + /* Keep in sync with #MappingInfoModifierData. */ + struct Tex *texture; struct Object *map_object; char map_bone[64]; @@ -583,12 +598,12 @@ typedef struct DisplaceModifierData { char _pad[6]; } DisplaceModifierData; -/* DisplaceModifierData->flag */ +/** #DisplaceModifierData.flag */ enum { MOD_DISP_INVERT_VGROUP = (1 << 0), }; -/* DisplaceModifierData->direction */ +/** #DisplaceModifierData.direction */ enum { MOD_DISP_DIR_X = 0, MOD_DISP_DIR_Y = 1, @@ -598,7 +613,7 @@ enum { MOD_DISP_DIR_CLNOR = 5, }; -/* DisplaceModifierData->texmapping */ +/** #DisplaceModifierData.texmapping */ enum { MOD_DISP_MAP_LOCAL = 0, MOD_DISP_MAP_GLOBAL = 1, @@ -606,7 +621,7 @@ enum { MOD_DISP_MAP_UV = 3, }; -/* DisplaceModifierData->space */ +/** #DisplaceModifierData.space */ enum { MOD_DISP_SPACE_LOCAL = 0, MOD_DISP_SPACE_GLOBAL = 1, @@ -614,9 +629,10 @@ enum { typedef struct UVProjectModifierData { ModifierData modifier; - - /* the objects which do the projecting */ - /** MOD_UVPROJECT_MAXPROJECTORS. */ + /** + * The objects which do the projecting. + * \note 10=MOD_UVPROJECT_MAXPROJECTORS. + */ struct Object *projectors[10]; char _pad2[4]; int num_projectors; @@ -649,7 +665,7 @@ typedef struct DecimateModifierData { float defgrp_factor; short flag, mode; - /* runtime only */ + /** runtime only. */ int face_count; } DecimateModifierData; @@ -678,7 +694,7 @@ typedef struct SmoothModifierData { } SmoothModifierData; -/* Smooth modifier flags */ +/** #SmoothModifierData.flag */ enum { MOD_SMOOTH_INVERT_VGROUP = (1 << 0), MOD_SMOOTH_X = (1 << 1), @@ -695,11 +711,13 @@ typedef struct CastModifierData { float size; /** MAX_VGROUP_NAME. */ char defgrp_name[64]; - short flag, type; + short flag; + /** Cast modifier projection type. */ + short type; void *_pad1; } CastModifierData; -/* Cast modifier flags */ +/** #CastModifierData.flag */ enum { /* And what bout (1 << 0) flag? ;) */ MOD_CAST_INVERT_VGROUP = (1 << 0), @@ -710,7 +728,7 @@ enum { MOD_CAST_SIZE_FROM_RADIUS = (1 << 5), }; -/* Cast modifier projection types */ +/** #CastModifierData.type */ enum { MOD_CAST_TYPE_SPHERE = 0, MOD_CAST_TYPE_CYLINDER = 1, @@ -720,7 +738,8 @@ enum { typedef struct WaveModifierData { ModifierData modifier; - /* keep in sync with MappingInfoModifierData */ + /* Keep in sync with #MappingInfoModifierData. */ + struct Tex *texture; struct Object *map_object; char map_bone[64]; @@ -728,7 +747,7 @@ typedef struct WaveModifierData { char uvlayer_name[64]; int uvlayer_tmp; int texmapping; - /* end MappingInfoModifierData */ + /* End MappingInfoModifierData. */ struct Object *objectcenter; /** MAX_VGROUP_NAME. */ @@ -745,7 +764,7 @@ typedef struct WaveModifierData { void *_pad2; } WaveModifierData; -/* WaveModifierData.flag */ +/** #WaveModifierData.flag */ enum { MOD_WAVE_INVERT_VGROUP = (1 << 0), MOD_WAVE_X = (1 << 1), @@ -775,7 +794,7 @@ enum { MOD_HOOK_INVERT_VGROUP = (1 << 1), }; -/* same as WarpModifierFalloff */ +/** \note same as #WarpModifierFalloff */ typedef enum { eHook_Falloff_None = 0, eHook_Falloff_Curve = 1, @@ -832,15 +851,17 @@ typedef struct ClothModifierData { /** Definition is in DNA_cloth_types.h. */ struct ClothCollSettings *coll_parms; - /* PointCache can be shared with other instances of ClothModifierData. - * Inspect (modifier.flag & eModifierFlag_SharedCaches) to find out. */ + /** + * PointCache can be shared with other instances of #ClothModifierData. + * Inspect `modifier.flag & eModifierFlag_SharedCaches` to find out. + */ /** Definition is in DNA_object_force_types.h. */ struct PointCache *point_cache; struct ListBase ptcaches; - /* XXX nasty hack, remove once hair can be separated from cloth modifier data */ + /** XXX: nasty hack, remove once hair can be separated from cloth modifier data. */ struct ClothHairData *hairdata; - /* grid geometry values of hair continuum */ + /** Grid geometry values of hair continuum. */ float hair_grid_min[3]; float hair_grid_max[3]; int hair_grid_res[3]; @@ -907,20 +928,20 @@ typedef struct BooleanModifierData { char bm_flag; } BooleanModifierData; -/* BooleanModifierData->operation */ +/** #BooleanModifierData.operation */ typedef enum { eBooleanModifierOp_Intersect = 0, eBooleanModifierOp_Union = 1, eBooleanModifierOp_Difference = 2, } BooleanModifierOp; -/* BooleanModifierData->solver */ +/** #BooleanModifierData.solver */ typedef enum { eBooleanModifierSolver_Fast = 0, eBooleanModifierSolver_Exact = 1, } BooleanModifierSolver; -/* BooleanModifierData->flag */ +/** #BooleanModifierData.flag */ enum { eBooleanModifierFlag_Self = (1 << 0), eBooleanModifierFlag_Object = (1 << 1), @@ -928,7 +949,7 @@ enum { eBooleanModifierFlag_HoleTolerant = (1 << 3), }; -/* bm_flag only used when G_DEBUG. */ +/** #BooleanModifierData.bm_flag (only used when #G_DEBUG is set). */ enum { eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 0), eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 1), @@ -1102,7 +1123,7 @@ typedef enum { eMultiresModifierFlag_UseSculptBaseMesh = (1 << 4), } MultiresModifierFlag; -/* DEPRECATED, only used for versioning. */ +/** DEPRECATED: only used for versioning. */ typedef struct FluidsimModifierData { ModifierData modifier; @@ -1111,7 +1132,7 @@ typedef struct FluidsimModifierData { void *_pad1; } FluidsimModifierData; -/* DEPRECATED, only used for versioning. */ +/** DEPRECATED: only used for versioning. */ typedef struct SmokeModifierData { ModifierData modifier; @@ -1150,7 +1171,7 @@ typedef struct ShrinkwrapModifierData { char _pad[2]; } ShrinkwrapModifierData; -/* Shrinkwrap->shrinkType */ +/** #ShrinkwrapModifierData.shrinkType */ enum { MOD_SHRINKWRAP_NEAREST_SURFACE = 0, MOD_SHRINKWRAP_PROJECT = 1, @@ -1158,7 +1179,7 @@ enum { MOD_SHRINKWRAP_TARGET_PROJECT = 3, }; -/* Shrinkwrap->shrinkMode */ +/** #ShrinkwrapModifierData.shrinkMode */ enum { /** Move vertex to the surface of the target object (keepDist towards original position) */ MOD_SHRINKWRAP_ON_SURFACE = 0, @@ -1172,7 +1193,7 @@ enum { MOD_SHRINKWRAP_ABOVE_SURFACE = 4, }; -/* Shrinkwrap->shrinkOpts */ +/** #ShrinkwrapModifierData.shrinkOpts */ enum { /** allow shrinkwrap to move the vertex in the positive direction of axis */ MOD_SHRINKWRAP_PROJECT_ALLOW_POS_DIR = (1 << 0), @@ -1196,7 +1217,7 @@ enum { #define MOD_SHRINKWRAP_CULL_TARGET_MASK \ (MOD_SHRINKWRAP_CULL_TARGET_FRONTFACE | MOD_SHRINKWRAP_CULL_TARGET_BACKFACE) -/* Shrinkwrap->projAxis */ +/** #ShrinkwrapModifierData.projAxis */ enum { /** projection over normal is used if no axis is selected */ MOD_SHRINKWRAP_PROJECT_OVER_NORMAL = 0, @@ -1228,7 +1249,7 @@ typedef struct SimpleDeformModifierData { void *_pad1; } SimpleDeformModifierData; -/* SimpleDeform->flag */ +/** #SimpleDeformModifierData.flag */ enum { MOD_SIMPLEDEFORM_FLAG_INVERT_VGROUP = (1 << 0), }; @@ -1434,7 +1455,9 @@ enum { typedef struct WarpModifierData { ModifierData modifier; - /* keep in sync with MappingInfoModifierData */ + + /* Keep in sync with #MappingInfoModifierData. */ + struct Tex *texture; struct Object *map_object; char map_bone[64]; @@ -1442,7 +1465,7 @@ typedef struct WarpModifierData { char uvlayer_name[64]; int uvlayer_tmp; int texmapping; - /* end MappingInfoModifierData */ + /* End #MappingInfoModifierData. */ struct Object *object_from; struct Object *object_to; @@ -1462,12 +1485,13 @@ typedef struct WarpModifierData { void *_pad1; } WarpModifierData; -/* WarpModifierData->flag */ +/** #WarpModifierData.flag */ enum { MOD_WARP_VOLUME_PRESERVE = (1 << 0), MOD_WARP_INVERT_VGROUP = (1 << 1), }; +/** \note same as #HookModifierFalloff. */ typedef enum { eWarp_Falloff_None = 0, eWarp_Falloff_Curve = 1, @@ -1508,7 +1532,7 @@ typedef struct WeightVGEditModifierData { char mask_defgrp_name[64]; /* Texture masking. */ - /** Which channel to use as weightf. */ + /** Which channel to use as weight/mask. */ int mask_tex_use_channel; /** The texture. */ struct Tex *mask_texture; @@ -1526,7 +1550,7 @@ typedef struct WeightVGEditModifierData { void *_pad1; } WeightVGEditModifierData; -/* WeightVGEdit flags. */ +/** #WeightVGEdit.edit_flags */ enum { MOD_WVG_EDIT_WEIGHTS_NORMALIZE = (1 << 0), MOD_WVG_INVERT_FALLOFF = (1 << 1), @@ -1581,7 +1605,7 @@ typedef struct WeightVGMixModifierData { char _pad1[3]; } WeightVGMixModifierData; -/* How second vgroup's weights affect first ones. */ +/** #WeightVGMixModifierData.mix_mode (how second vgroup's weights affect first ones). */ enum { /** Second weights replace weights. */ MOD_WVG_MIX_SET = 1, @@ -1599,7 +1623,7 @@ enum { MOD_WVG_MIX_AVG = 7, }; -/* What vertices to affect. */ +/** #WeightVGMixModifierData.mix_set (what vertices to affect). */ enum { /** Affect all vertices. */ MOD_WVG_SET_ALL = 1, @@ -1613,7 +1637,7 @@ enum { MOD_WVG_SET_AND = 5, }; -/* WeightVGMix->flag */ +/** #WeightVGMixModifierData.flag */ enum { MOD_WVG_MIX_INVERT_VGROUP_MASK = (1 << 0), MOD_WVG_MIX_WEIGHTS_NORMALIZE = (1 << 1), @@ -1631,8 +1655,9 @@ typedef struct WeightVGProximityModifierData { /** The custom mapping curve. */ struct CurveMapping *cmap_curve; - /* Proximity modes. */ + /** Modes of proximity weighting. */ int proximity_mode; + /** Options for proximity weighting. */ int proximity_flags; /* Target object from which to calculate vertices distances. */ @@ -1662,20 +1687,21 @@ typedef struct WeightVGProximityModifierData { float min_dist, max_dist; /* Put here to avoid breaking existing struct... */ - /** Using MOD_WVG_MAPPING_* enums. */ + /** + * Mapping modes (using MOD_WVG_MAPPING_* enums). */ short falloff_type; /* Padding... */ char _pad0[2]; } WeightVGProximityModifierData; -/* Modes of proximity weighting. */ +/** #WeightVGProximityModifierData.proximity_mode */ enum { MOD_WVG_PROXIMITY_OBJECT = 1, /* source vertex to other location */ MOD_WVG_PROXIMITY_GEOMETRY = 2, /* source vertex to other geometry */ }; -/* Flags options for proximity weighting. */ +/** #WeightVGProximityModifierData.proximity_flags */ enum { /* Use nearest vertices of target obj, in MOD_WVG_PROXIMITY_GEOMETRY mode. */ MOD_WVG_PROXIMITY_GEOM_VERTS = (1 << 0), @@ -1689,7 +1715,8 @@ enum { }; /* Defines common to all WeightVG modifiers. */ -/* Mapping modes. */ + +/** #WeightVGProximityModifierData.falloff_type */ enum { MOD_WVG_MAPPING_NONE = 0, MOD_WVG_MAPPING_CURVE = 1, @@ -1703,7 +1730,7 @@ enum { MOD_WVG_MAPPING_STEP = 9, /* Median Step. */ }; -/* Tex channel to be used as mask. */ +/** #WeightVGProximityModifierData.mask_tex_use_channel */ enum { MOD_WVG_MASK_TEX_USE_INT = 1, MOD_WVG_MASK_TEX_USE_RED = 2, @@ -1725,13 +1752,13 @@ typedef struct DynamicPaintModifierData { char _pad[4]; } DynamicPaintModifierData; -/* Dynamic paint modifier flags */ +/** #DynamicPaintModifierData.type */ enum { MOD_DYNAMICPAINT_TYPE_CANVAS = (1 << 0), MOD_DYNAMICPAINT_TYPE_BRUSH = (1 << 1), }; -/* Remesh modifier */ +/** Remesh modifier. */ typedef enum eRemeshModifierFlags { MOD_REMESH_FLOOD_FILL = (1 << 0), MOD_REMESH_SMOOTH_SHADING = (1 << 1), @@ -1770,7 +1797,7 @@ typedef struct RemeshModifierData { float adaptivity; } RemeshModifierData; -/* Skin modifier */ +/** Skin modifier. */ typedef struct SkinModifierData { ModifierData modifier; @@ -1783,19 +1810,19 @@ typedef struct SkinModifierData { char _pad[2]; } SkinModifierData; -/* SkinModifierData.symmetry_axes */ +/** #SkinModifierData.symmetry_axes */ enum { MOD_SKIN_SYMM_X = (1 << 0), MOD_SKIN_SYMM_Y = (1 << 1), MOD_SKIN_SYMM_Z = (1 << 2), }; -/* SkinModifierData.flag */ +/** #SkinModifierData.flag */ enum { MOD_SKIN_SMOOTH_SHADING = 1, }; -/* Triangulate modifier */ +/** Triangulate modifier. */ typedef struct TriangulateModifierData { ModifierData modifier; @@ -1805,7 +1832,7 @@ typedef struct TriangulateModifierData { int min_vertices; } TriangulateModifierData; -/* TriangulateModifierData.flag */ +/** #TriangulateModifierData.flag */ enum { #ifdef DNA_DEPRECATED_ALLOW MOD_TRIANGULATE_BEAUTY = (1 << 0), /* deprecated */ @@ -1813,13 +1840,13 @@ enum { MOD_TRIANGULATE_KEEP_CUSTOMLOOP_NORMALS = 1 << 1, }; -/* Triangulate methods - NGons */ +/** #TriangulateModifierData.ngon_method triangulate method (N-gons). */ enum { MOD_TRIANGULATE_NGON_BEAUTY = 0, MOD_TRIANGULATE_NGON_EARCLIP = 1, }; -/* Triangulate methods - Quads */ +/** #TriangulateModifierData.quad_method triangulate method (quads). */ enum { MOD_TRIANGULATE_QUAD_BEAUTY = 0, MOD_TRIANGULATE_QUAD_FIXED = 1, @@ -1837,7 +1864,7 @@ typedef struct LaplacianSmoothModifierData { short flag, repeat; } LaplacianSmoothModifierData; -/* Smooth modifier flags */ +/** #LaplacianSmoothModifierData.flag */ enum { MOD_LAPLACIANSMOOTH_X = (1 << 1), MOD_LAPLACIANSMOOTH_Y = (1 << 2), @@ -1892,7 +1919,7 @@ enum { MOD_CORRECTIVESMOOTH_RESTSOURCE_BIND = 1, }; -/* Corrective Smooth modifier flags */ +/** #CorrectiveSmoothModifierData.flag */ enum { MOD_CORRECTIVESMOOTH_INVERT_VGROUP = (1 << 0), MOD_CORRECTIVESMOOTH_ONLY_SMOOTH = (1 << 1), @@ -1926,12 +1953,12 @@ typedef struct UVWarpModifierData { char uvlayer_name[64]; } UVWarpModifierData; -/* UVWarp modifier flags */ +/** #UVWarpModifierData.flag */ enum { MOD_UVWARP_INVERT_VGROUP = 1 << 0, }; -/* cache modifier */ +/** Mesh cache modifier. */ typedef struct MeshCacheModifierData { ModifierData modifier; @@ -1967,7 +1994,7 @@ typedef struct MeshCacheModifierData { char filepath[1024]; } MeshCacheModifierData; -/* MeshCache modifier flags. */ +/** #MeshCacheModifierData.flag */ enum { MOD_MESHCACHE_INVERT_VERTEX_GROUP = 1 << 0, }; @@ -2012,13 +2039,15 @@ typedef struct LaplacianDeformModifierData { } LaplacianDeformModifierData; -/* Laplacian Deform modifier flags */ +/** #LaplacianDeformModifierData.flag */ enum { MOD_LAPLACIANDEFORM_BIND = 1 << 0, MOD_LAPLACIANDEFORM_INVERT_VGROUP = 1 << 1, }; -/* many of these options match 'solidify' */ +/** + * \note many of these options match 'solidify'. + */ typedef struct WireframeModifierData { ModifierData modifier; /** MAX_VGROUP_NAME. */ @@ -2053,13 +2082,13 @@ typedef struct WeldModifierData { char _pad[2]; } WeldModifierData; -/* WeldModifierData->flag */ +/** #WeldModifierData.flag */ enum { MOD_WELD_INVERT_VGROUP = (1 << 0), MOD_WELD_LOOSE_EDGES = (1 << 1), }; -/* #WeldModifierData.mode */ +/** #WeldModifierData.mode */ enum { MOD_WELD_MODE_ALL = 0, MOD_WELD_MODE_CONNECTED = 1, @@ -2100,7 +2129,7 @@ typedef struct DataTransferModifierData { void *_pad2; } DataTransferModifierData; -/* DataTransferModifierData.flags */ +/** #DataTransferModifierData.flags */ enum { MOD_DATATRANSFER_OBSRC_TRANSFORM = 1 << 0, MOD_DATATRANSFER_MAP_MAXDIST = 1 << 1, @@ -2113,7 +2142,7 @@ enum { MOD_DATATRANSFER_USE_POLY = 1u << 31, }; -/* Set Split Normals modifier */ +/** Set Split Normals modifier. */ typedef struct NormalEditModifierData { ModifierData modifier; /** MAX_VGROUP_NAME. */ @@ -2131,20 +2160,20 @@ typedef struct NormalEditModifierData { void *_pad1; } NormalEditModifierData; -/* NormalEditModifierData.mode */ +/** #NormalEditModifierData.mode */ enum { MOD_NORMALEDIT_MODE_RADIAL = 0, MOD_NORMALEDIT_MODE_DIRECTIONAL = 1, }; -/* NormalEditModifierData.flags */ +/** #NormalEditModifierData.flags */ enum { MOD_NORMALEDIT_INVERT_VGROUP = (1 << 0), MOD_NORMALEDIT_USE_DIRECTION_PARALLEL = (1 << 1), MOD_NORMALEDIT_NO_POLYNORS_FIX = (1 << 2), }; -/* NormalEditModifierData.mix_mode */ +/** #NormalEditModifierData.mix_mode */ enum { MOD_NORMALEDIT_MIX_COPY = 0, MOD_NORMALEDIT_MIX_ADD = 1, @@ -2169,7 +2198,7 @@ typedef struct MeshSeqCacheModifierData { char reader_object_path[1024]; } MeshSeqCacheModifierData; -/* MeshSeqCacheModifierData.read_flag */ +/** #MeshSeqCacheModifierData.read_flag */ enum { MOD_MESHSEQ_READ_VERT = (1 << 0), MOD_MESHSEQ_READ_POLY = (1 << 1), @@ -2214,7 +2243,7 @@ typedef struct SurfaceDeformModifierData { void *_pad1; } SurfaceDeformModifierData; -/* Surface Deform modifier flags */ +/** Surface Deform modifier flags. */ enum { /* This indicates "do bind on next modifier evaluation" as well as "is bound". */ MOD_SDEF_BIND = (1 << 0), @@ -2223,7 +2252,7 @@ enum { MOD_SDEF_SPARSE_BIND = (1 << 2), }; -/* Surface Deform vertex bind modes */ +/** Surface Deform vertex bind modes. */ enum { MOD_SDEF_MODE_LOOPTRI = 0, MOD_SDEF_MODE_NGON = 1, @@ -2243,14 +2272,14 @@ typedef struct WeightedNormalModifierData { /* Name/id of the generic PROP_INT cdlayer storing face weights. */ #define MOD_WEIGHTEDNORMALS_FACEWEIGHT_CDLAYER_ID "__mod_weightednormals_faceweight" -/* WeightedNormalModifierData.mode */ +/** #WeightedNormalModifierData.mode */ enum { MOD_WEIGHTEDNORMAL_MODE_FACE = 0, MOD_WEIGHTEDNORMAL_MODE_ANGLE = 1, MOD_WEIGHTEDNORMAL_MODE_FACE_ANGLE = 2, }; -/* WeightedNormalModifierData.flag */ +/** #WeightedNormalModifierData.flag */ enum { MOD_WEIGHTEDNORMAL_KEEP_SHARP = (1 << 0), MOD_WEIGHTEDNORMAL_INVERT_VGROUP = (1 << 1), @@ -2270,8 +2299,10 @@ typedef struct NodesModifierData { struct bNodeTree *node_group; struct NodesModifierSettings settings; - /* Contains logged information from the last evaluation. This can be used to help the user to - * debug a node tree. */ + /** + * Contains logged information from the last evaluation. + * This can be used to help the user to debug a node tree. + */ void *runtime_eval_log; void *_pad1; } NodesModifierData; @@ -2304,7 +2335,7 @@ typedef struct MeshToVolumeModifierData { void *_pad3; } MeshToVolumeModifierData; -/* MeshToVolumeModifierData->resolution_mode */ +/** #MeshToVolumeModifierData.resolution_mode */ typedef enum MeshToVolumeModifierResolutionMode { MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_AMOUNT = 0, MESH_TO_VOLUME_RESOLUTION_MODE_VOXEL_SIZE = 1, @@ -2322,7 +2353,7 @@ typedef struct VolumeDisplaceModifierData { float texture_sample_radius; } VolumeDisplaceModifierData; -/* VolumeDisplaceModifierData->texture_map_mode */ +/** #VolumeDisplaceModifierData.texture_map_mode */ enum { MOD_VOLUME_DISPLACE_MAP_LOCAL = 0, MOD_VOLUME_DISPLACE_MAP_GLOBAL = 1, diff --git a/source/blender/makesdna/DNA_movieclip_types.h b/source/blender/makesdna/DNA_movieclip_types.h index 8e01a9e1f1f..08064e6242b 100644 --- a/source/blender/makesdna/DNA_movieclip_types.h +++ b/source/blender/makesdna/DNA_movieclip_types.h @@ -160,7 +160,7 @@ typedef struct MovieClipScopes { float slide_scale[2]; } MovieClipScopes; -/* MovieClipProxy->build_size_flag */ +/** #MovieClipProxy.build_size_flag */ enum { MCLIP_PROXY_SIZE_25 = (1 << 0), MCLIP_PROXY_SIZE_50 = (1 << 1), @@ -172,13 +172,13 @@ enum { MCLIP_PROXY_UNDISTORTED_SIZE_100 = (1 << 7), }; -/* MovieClip->source */ +/** #MovieClip.source */ enum { MCLIP_SRC_SEQUENCE = 1, MCLIP_SRC_MOVIE = 2, }; -/* MovieClip->flag */ +/** #MovieClip.flag */ enum { MCLIP_USE_PROXY = (1 << 0), MCLIP_USE_PROXY_CUSTOM_DIR = (1 << 1), @@ -188,7 +188,7 @@ enum { MCLIP_TIMECODE_FLAGS = (MCLIP_USE_PROXY | MCLIP_USE_PROXY_CUSTOM_DIR), }; -/* MovieClip->render_size */ +/** #MovieClip.render_size */ enum { MCLIP_PROXY_RENDER_SIZE_FULL = 0, MCLIP_PROXY_RENDER_SIZE_25 = 1, @@ -197,7 +197,7 @@ enum { MCLIP_PROXY_RENDER_SIZE_100 = 4, }; -/* MovieClip->render_flag */ +/** #MovieClip.render_flag */ enum { MCLIP_PROXY_RENDER_UNDISTORT = 1, /** Use original, if proxy is not found. */ diff --git a/source/blender/makesdna/DNA_nla_types.h b/source/blender/makesdna/DNA_nla_types.h index 7808dd68384..82edc0e1816 100644 --- a/source/blender/makesdna/DNA_nla_types.h +++ b/source/blender/makesdna/DNA_nla_types.h @@ -33,7 +33,7 @@ struct Ipo; struct Object; struct bAction; -/* simple uniform modifier structure, assumed it can hold all type info */ +/** Simple uniform modifier structure, assumed it can hold all type info. */ typedef struct bActionModifier { struct bActionModifier *next, *prev; short type, flag; @@ -95,7 +95,7 @@ typedef struct bActionStrip { #define ACTSTRIPMODE_BLEND 0 #define ACTSTRIPMODE_ADD 1 -/* strip->flag */ +/** #bActionStrip.flag */ typedef enum eActStrip_Flag { ACTSTRIP_SELECT = (1 << 0), ACTSTRIP_USESTRIDE = (1 << 1), diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index dc5acb9d5b2..e349dfd8704 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -95,7 +95,7 @@ typedef struct SocketDeclarationHandle SocketDeclarationHandle; #endif typedef struct bNodeSocket { - struct bNodeSocket *next, *prev, *new_sock; + struct bNodeSocket *next, *prev; /** User-defined properties. */ IDProperty *prop; @@ -159,7 +159,7 @@ typedef struct bNodeSocket { * restores pointer from matching own_index. */ struct bNodeSocket *groupsock DNA_DEPRECATED; - /** A link pointer, set in ntreeUpdateTree. */ + /** A link pointer, set in #BKE_ntree_update_main. */ struct bNodeLink *link; /* XXX deprecated, socket input values are stored in default_value now. @@ -172,9 +172,13 @@ typedef struct bNodeSocket { * data. It has to be updated when the node declaration changes. */ const SocketDeclarationHandle *declaration; + + /** #eNodeTreeChangedFlag. */ + uint32_t changed_flag; + char _pad[4]; } bNodeSocket; -/* sock->type */ +/** #bNodeSocket.type & #bNodeSocketType.type */ typedef enum eNodeSocketDatatype { SOCK_CUSTOM = -1, /* socket has no integer type */ SOCK_FLOAT = 0, @@ -193,7 +197,7 @@ typedef enum eNodeSocketDatatype { SOCK_MATERIAL = 13, } eNodeSocketDatatype; -/* Socket shape. */ +/** Socket shape. */ typedef enum eNodeSocketDisplayShape { SOCK_DISPLAY_SHAPE_CIRCLE = 0, SOCK_DISPLAY_SHAPE_SQUARE = 1, @@ -203,13 +207,13 @@ typedef enum eNodeSocketDisplayShape { SOCK_DISPLAY_SHAPE_DIAMOND_DOT = 5, } eNodeSocketDisplayShape; -/* Socket side (input/output). */ +/** Socket side (input/output). */ typedef enum eNodeSocketInOut { SOCK_IN = 1 << 0, SOCK_OUT = 1 << 1, } eNodeSocketInOut; -/* #bNodeSocket.flag, first bit is selection. */ +/** #bNodeSocket.flag, first bit is selection. */ typedef enum eNodeSocketFlag { /** Hidden is user defined, to hide unused sockets. */ SOCK_HIDDEN = (1 << 1), @@ -239,9 +243,9 @@ typedef enum eNodeSocketFlag { SOCK_HIDE_LABEL = (1 << 12), } eNodeSocketFlag; -/* TODO: Limit data in bNode to what we want to see saved. */ +/** TODO: Limit data in #bNode to what we want to see saved. */ typedef struct bNode { - struct bNode *next, *prev, *new_node; + struct bNode *next, *prev; /** User-defined properties. */ IDProperty *prop; @@ -260,8 +264,9 @@ typedef struct bNode { /** Used as a boolean for execution. */ uint8_t need_exec; - - char _pad[1]; + char _pad2[5]; + /** #eNodeTreeChangedFlag. */ + uint32_t changed_flag; /** Custom user-defined color. */ float color[3]; @@ -400,10 +405,6 @@ typedef struct bNode { #define __NODE_ACTIVE_PREVIEW (1 << 18) /* deprecated */ /* node->update */ -/* XXX NODE_UPDATE is a generic update flag. More fine-grained updates - * might be used in the future, but currently all work the same way. - */ -#define NODE_UPDATE 0xFFFF /* generic update flag (includes all others) */ #define NODE_UPDATE_ID 1 /* associated id data block has changed */ #define NODE_UPDATE_OPERATOR 2 /* node update triggered from update operator */ @@ -511,8 +512,12 @@ typedef struct bNodeTree { */ int cur_index; int flag; - /** Update flags. */ - int update; + /** + * Keeps track of what changed in the node tree until the next update. + * Should not be changed directly, instead use the functions in `BKE_node_tree_update.h`. + * #eNodeTreeChangedFlag. + */ + uint32_t changed_flag; /** Flag to prevent re-entrant update calls. */ short is_updating; /** Generic temporary flag for recursion check (DFS/BFS). */ @@ -546,7 +551,11 @@ typedef struct bNodeTree { * in case multiple different editors are used and make context ambiguous. */ bNodeInstanceKey active_viewer_key; - char _pad[4]; + /** + * A hash of the topology of the node tree leading up to the outputs. This is used to determine + * of the node tree changed in a way that requires updating geometry nodes or shaders. + */ + uint32_t output_topology_hash; /** Execution data. * @@ -571,7 +580,7 @@ typedef struct bNodeTree { struct PreviewImage *preview; } bNodeTree; -/* ntree->type, index */ +/** #NodeTree.type, index */ #define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */ #define NTREE_CUSTOM -1 /* for dynamically registered custom types */ @@ -580,10 +589,10 @@ typedef struct bNodeTree { #define NTREE_TEXTURE 2 #define NTREE_GEOMETRY 3 -/* ntree->init, flag */ +/** #NodeTree.init, flag */ #define NTREE_TYPE_INIT 1 -/* ntree->flag */ +/** #NodeTree.flag */ #define NTREE_DS_EXPAND (1 << 0) /* for animation editors */ #define NTREE_COM_OPENCL (1 << 1) /* use opencl */ #define NTREE_TWO_PASS (1 << 2) /* two pass */ @@ -594,20 +603,6 @@ typedef struct bNodeTree { /* tree is localized copy, free when deleting node groups */ /* #define NTREE_IS_LOCALIZED (1 << 5) */ -/* ntree->update */ -typedef enum eNodeTreeUpdate { - NTREE_UPDATE = 0xFFFF, /* generic update flag (includes all others) */ - NTREE_UPDATE_LINKS = (1 << 0), /* links have been added or removed */ - NTREE_UPDATE_NODES = (1 << 1), /* nodes or sockets have been added or removed */ - NTREE_UPDATE_GROUP_IN = (1 << 4), /* group inputs have changed */ - NTREE_UPDATE_GROUP_OUT = (1 << 5), /* group outputs have changed */ - /* The field interface has changed. So e.g. an output that was always a field before is not - * anymore. This implies that the field type inferencing has to be done again. */ - NTREE_UPDATE_FIELD_INFERENCING = (1 << 6), - /* group has changed (generic flag including all other group flags) */ - NTREE_UPDATE_GROUP = (NTREE_UPDATE_GROUP_IN | NTREE_UPDATE_GROUP_OUT), -} eNodeTreeUpdate; - /* tree->execution_mode */ typedef enum eNodeTreeExecutionMode { NTREE_EXECUTION_MODE_TILED = 0, @@ -674,7 +669,8 @@ typedef struct bNodeSocketValueMaterial { struct Material *value; } bNodeSocketValueMaterial; -/* Data structs, for node->storage. */ +/* Data structs, for `node->storage`. */ + enum { CMP_NODE_MASKTYPE_ADD = 0, CMP_NODE_MASKTYPE_SUBTRACT = 1, @@ -713,7 +709,7 @@ typedef struct NodeFrame { short label_size; } NodeFrame; -/* This one has been replaced with ImageUser, keep it for do_versions(). */ +/** \note This one has been replaced with #ImageUser, keep it for do_versions(). */ typedef struct NodeImageAnim { int frames DNA_DEPRECATED; int sfra DNA_DEPRECATED; @@ -767,7 +763,7 @@ typedef struct NodeEllipseMask { char _pad[4]; } NodeEllipseMask; -/* Layer info for image node outputs. */ +/** Layer info for image node outputs. */ typedef struct NodeImageLayer { /* index in the Image->layers->passes lists */ int pass_index DNA_DEPRECATED; @@ -805,7 +801,7 @@ typedef struct NodeAntiAliasingData { float corner_rounding; } NodeAntiAliasingData; -/* NOTE: Only for do-version code. */ +/** \note Only for do-version code. */ typedef struct NodeHueSat { float hue, sat, val; } NodeHueSat; @@ -817,7 +813,9 @@ typedef struct NodeImageFile { int sfra, efra; } NodeImageFile; -/* XXX first struct fields should match NodeImageFile to ensure forward compatibility */ +/** + * XXX: first struct fields should match #NodeImageFile to ensure forward compatibility. + */ typedef struct NodeImageMultiFile { /** 1024 = FILE_MAX. */ char base_path[1024]; @@ -1066,7 +1064,7 @@ typedef struct NodeShaderPrincipled { char _pad[3]; } NodeShaderPrincipled; -/* TEX_output */ +/** TEX_output. */ typedef struct TexNodeOutput { char name[64]; } TexNodeOutput; @@ -1266,6 +1264,13 @@ typedef struct NodeRandomValue { uint8_t data_type; } NodeRandomValue; +typedef struct NodeAccumulateField { + /* CustomDataType. */ + uint8_t data_type; + /* AttributeDomain. */ + uint8_t domain; +} NodeAccumulateField; + typedef struct NodeAttributeRandomize { /* CustomDataType. */ uint8_t data_type; @@ -1632,14 +1637,17 @@ typedef struct NodeFunctionCompare { #define NODE_IES_INTERNAL 0 #define NODE_IES_EXTERNAL 1 -/* frame node flags */ +/* Frame node flags. */ + #define NODE_FRAME_SHRINK 1 /* keep the bounding box minimal */ #define NODE_FRAME_RESIZEABLE 2 /* test flag, if frame can be resized by user */ -/* proxy node flags */ +/* Proxy node flags. */ + #define NODE_PROXY_AUTOTYPE 1 /* automatically change output type based on link */ -/* comp channel matte */ +/* Comp channel matte. */ + #define CMP_NODE_CHANNEL_MATTE_CS_RGB 1 #define CMP_NODE_CHANNEL_MATTE_CS_HSV 2 #define CMP_NODE_CHANNEL_MATTE_CS_YUV 3 @@ -1661,7 +1669,7 @@ typedef struct NodeFunctionCompare { #define SHD_VECT_TRANSFORM_SPACE_OBJECT 1 #define SHD_VECT_TRANSFORM_SPACE_CAMERA 2 -/* attribute */ +/** #NodeShaderAttribute.type */ enum { SHD_ATTRIBUTE_GEOMETRY = 0, SHD_ATTRIBUTE_OBJECT = 1, @@ -1795,7 +1803,7 @@ enum { #define SHD_AO_INSIDE 1 #define SHD_AO_LOCAL 2 -/* Mapping node vector types. */ +/** Mapping node vector types. */ enum { NODE_MAPPING_TYPE_POINT = 0, NODE_MAPPING_TYPE_TEXTURE = 1, @@ -1803,7 +1811,7 @@ enum { NODE_MAPPING_TYPE_NORMAL = 3, }; -/* Rotation node vector types. */ +/** Rotation node vector types. */ enum { NODE_VECTOR_ROTATE_TYPE_AXIS = 0, NODE_VECTOR_ROTATE_TYPE_AXIS_X = 1, @@ -1815,7 +1823,7 @@ enum { /* math node clamp */ #define SHD_MATH_CLAMP 1 -/* Math node operations. */ +/** Math node operations. */ typedef enum NodeMathOperation { NODE_MATH_ADD = 0, NODE_MATH_SUBTRACT = 1, @@ -1859,7 +1867,7 @@ typedef enum NodeMathOperation { NODE_MATH_SMOOTH_MAX = 39, } NodeMathOperation; -/* Vector Math node operations. */ +/** Vector Math node operations. */ typedef enum NodeVectorMathOperation { NODE_VECTOR_MATH_ADD = 0, NODE_VECTOR_MATH_SUBTRACT = 1, @@ -1893,14 +1901,14 @@ typedef enum NodeVectorMathOperation { NODE_VECTOR_MATH_MULTIPLY_ADD = 26, } NodeVectorMathOperation; -/* Boolean math node operations. */ +/** Boolean math node operations. */ enum { NODE_BOOLEAN_MATH_AND = 0, NODE_BOOLEAN_MATH_OR = 1, NODE_BOOLEAN_MATH_NOT = 2, }; -/* Float compare node operations. */ +/** Float compare node operations. */ typedef enum NodeCompareMode { NODE_COMPARE_MODE_ELEMENT = 0, NODE_COMPARE_MODE_LENGTH = 1, @@ -1921,7 +1929,7 @@ typedef enum NodeCompareOperation { } NodeCompareOperation; -/* Float to Int node operations. */ +/** Float to Int node operations. */ typedef enum FloatToIntRoundingMode { FN_NODE_FLOAT_TO_INT_ROUND = 0, FN_NODE_FLOAT_TO_INT_FLOOR = 1, @@ -1929,13 +1937,13 @@ typedef enum FloatToIntRoundingMode { FN_NODE_FLOAT_TO_INT_TRUNCATE = 3, } FloatToIntRoundingMode; -/* Clamp node types. */ +/** Clamp node types. */ enum { NODE_CLAMP_MINMAX = 0, NODE_CLAMP_RANGE = 1, }; -/* Map range node types. */ +/** Map range node types. */ enum { NODE_MAP_RANGE_LINEAR = 0, NODE_MAP_RANGE_STEPPED = 1, @@ -1947,7 +1955,8 @@ enum { #define SHD_MIXRGB_USE_ALPHA 1 #define SHD_MIXRGB_CLAMP 2 -/* subsurface */ +/* Subsurface. */ + enum { #ifdef DNA_DEPRECATED_ALLOW SHD_SUBSURFACE_COMPATIBLE = 0, /* Deprecated */ @@ -1978,25 +1987,29 @@ enum { /* viewer and composite output. */ #define CMP_NODE_OUTPUT_IGNORE_ALPHA 1 -/* Plane track deform node */ +/* Plane track deform node. */ + enum { CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR = 1, }; -/* Stabilization node */ +/* Stabilization node. */ + enum { CMP_NODEFLAG_STABILIZE_INVERSE = 1, }; /* Set Alpha Node. */ -/* `NodeSetAlpha.mode` */ + +/** #NodeSetAlpha.mode */ typedef enum CMPNodeSetAlphaMode { CMP_NODE_SETALPHA_MODE_APPLY = 0, CMP_NODE_SETALPHA_MODE_REPLACE_ALPHA = 1, } CMPNodeSetAlphaMode; /* Denoise Node. */ -/* `NodeDenoise.prefilter` */ + +/** #NodeDenoise.prefilter */ typedef enum CMPNodeDenoisePrefilter { CMP_NODE_DENOISE_PREFILTER_FAST = 0, CMP_NODE_DENOISE_PREFILTER_NONE = 1, diff --git a/source/blender/makesdna/DNA_object_force_types.h b/source/blender/makesdna/DNA_object_force_types.h index 0aa4a171511..7d0d4c0d460 100644 --- a/source/blender/makesdna/DNA_object_force_types.h +++ b/source/blender/makesdna/DNA_object_force_types.h @@ -32,7 +32,7 @@ extern "C" { struct BodySpring; -/* pd->forcefield: Effector Fields types */ +/** #PartDeflect.forcefield: Effector Fields types. */ typedef enum ePFieldType { /** (this is used for general effector weight). */ PFIELD_NULL = 0, diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index 57c8ef200ae..13a368e4263 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -57,7 +57,7 @@ struct SculptSession; struct SoftBody; struct bGPdata; -/* Vertex Groups - Name Info */ +/** Vertex Groups - Name Info */ typedef struct bDeformGroup { struct bDeformGroup *next, *prev; /** MAX_VGROUP_NAME. */ @@ -66,7 +66,7 @@ typedef struct bDeformGroup { char flag, _pad0[7]; } bDeformGroup; -/* Face Maps. */ +/** Face Maps. */ typedef struct bFaceMap { struct bFaceMap *next, *prev; /** MAX_VGROUP_NAME. */ @@ -107,7 +107,7 @@ typedef struct BoundBox { char _pad0[4]; } BoundBox; -/* boundbox flag */ +/** #BoundBox.flag */ enum { BOUNDBOX_DISABLED = (1 << 0), BOUNDBOX_DIRTY = (1 << 1), @@ -115,7 +115,7 @@ enum { struct CustomData_MeshMasks; -/* Not saved in file! */ +/** Not saved in file! */ typedef struct Object_Runtime { /** * The custom data layer mask that was last used @@ -126,7 +126,12 @@ typedef struct Object_Runtime { /** Did last modifier stack generation need mapping support? */ char last_need_mapping; - char _pad0[3]; + /** Opaque data reserved for management of objects in collection context. + * E.g. used currently to check for potential duplicates of objects in a collection, after + * remapping process. */ + char collection_management; + + char _pad0[2]; /** Only used for drawing the parent/child help-line. */ float parent_display_origin[3]; @@ -246,7 +251,7 @@ typedef struct Object { /** String describing subobject info, MAX_ID_NAME-2. */ char parsubstr[64]; struct Object *parent, *track; - /* if ob->proxy (or proxy_group), this object is proxy for object ob->proxy */ + /* If `ob->proxy` (or proxy_group), this object is proxy for object `ob->proxy`. */ /* proxy_from is set in target back to the proxy. */ struct Object *proxy, *proxy_group, *proxy_from; /** Old animation system, deprecated for 2.5. */ @@ -322,8 +327,7 @@ typedef struct Object { * Inverse matrix of 'obmat' for any other use than rendering! * * \note this isn't assured to be valid as with 'obmat', - * before using this value you should do... - * invert_m4_m4(ob->imat, ob->obmat); + * before using this value you should do: `invert_m4_m4(ob->imat, ob->obmat)` */ float imat[4][4]; @@ -436,7 +440,7 @@ typedef struct Object { Object_Runtime runtime; } Object; -/* Warning, this is not used anymore because hooks are now modifiers */ +/** DEPRECATED: this is not used anymore because hooks are now modifiers. */ typedef struct ObHook { struct ObHook *next, *prev; @@ -466,7 +470,7 @@ typedef struct ObHook { /* used many places, should be specialized. */ #define SELECT 1 -/* type */ +/** #Object.type */ enum { OB_EMPTY = 0, OB_MESH = 1, @@ -544,7 +548,7 @@ enum { case ID_PT: \ case ID_VO -/* partype: first 4 bits: type */ +/** #Object.partype: first 4 bits: type. */ enum { PARTYPE = (1 << 4) - 1, PAROBJECT = 0, @@ -555,7 +559,7 @@ enum { }; -/* (short) transflag */ +/** #Object.transflag (short) */ enum { OB_TRANSFORM_ADJUST_ROOT_PARENT_FOR_VIEW_LOCK = 1 << 0, OB_TRANSFLAG_UNUSED_1 = 1 << 1, /* cleared */ @@ -577,7 +581,7 @@ enum { OB_DUPLI = OB_DUPLIVERTS | OB_DUPLICOLLECTION | OB_DUPLIFACES | OB_DUPLIPARTS, }; -/* (short) trackflag / upflag */ +/** #Object.trackflag / #Object.upflag (short) */ enum { OB_POSX = 0, OB_POSY = 1, @@ -587,7 +591,7 @@ enum { OB_NEGZ = 5, }; -/* dtx: flags (short) */ +/** #Object.dtx draw type extra flags (short) */ enum { OB_DRAWBOUNDOX = 1 << 0, OB_AXIS = 1 << 1, @@ -606,7 +610,7 @@ enum { OB_USE_GPENCIL_LIGHTS = 1 << 10, }; -/* empty_drawtype: no flags */ +/** #Object.empty_drawtype: no flags */ enum { OB_ARROWS = 1, OB_PLAINAXES = 2, @@ -618,7 +622,10 @@ enum { OB_EMPTY_IMAGE = 8, }; -/* gpencil add types */ +/** + * Grease-pencil add types. + * TODO: doesn't need to be DNA, local to `OBJECT_OT_gpencil_add`. + */ enum { GP_EMPTY = 0, GP_STROKE = 1, @@ -628,7 +635,7 @@ enum { GP_LRT_COLLECTION = 5, }; -/* boundtype */ +/** #Object.boundtype */ enum { OB_BOUND_BOX = 0, OB_BOUND_SPHERE = 1, @@ -642,7 +649,7 @@ enum { /* **************** BASE ********************* */ -/* base->flag_legacy */ +/** #Base.flag_legacy */ enum { BA_WAS_SEL = (1 << 1), /* NOTE: BA_HAS_RECALC_DATA can be re-used later if freed in readfile.c. */ @@ -671,7 +678,7 @@ enum { # define OB_FLAG_UNUSED_12 (1 << 12) /* cleared */ #endif -/* ob->visibility_flag */ +/** #Object.visibility_flag */ enum { OB_HIDE_VIEWPORT = 1 << 0, OB_HIDE_SELECT = 1 << 1, @@ -686,7 +693,7 @@ enum { OB_SHADOW_CATCHER = 1 << 10 }; -/* ob->shapeflag */ +/** #Object.shapeflag */ enum { OB_SHAPE_LOCK = 1 << 0, #ifdef DNA_DEPRECATED_ALLOW @@ -695,7 +702,7 @@ enum { OB_SHAPE_EDIT_MODE = 1 << 2, }; -/* ob->nlaflag */ +/** #Object.nlaflag */ enum { OB_ADS_UNUSED_1 = 1 << 0, /* cleared */ OB_ADS_UNUSED_2 = 1 << 1, /* cleared */ @@ -711,7 +718,7 @@ enum { /* OB_ADS_SHOWPARTS = 1 << 14, */ /* UNUSED */ }; -/* ob->protectflag */ +/** #Object.protectflag */ enum { OB_LOCK_LOCX = 1 << 0, OB_LOCK_LOCY = 1 << 1, @@ -729,13 +736,13 @@ enum { OB_LOCK_ROT4D = 1 << 10, }; -/* ob->duplicator_visibility_flag */ +/** #Object.duplicator_visibility_flag */ enum { OB_DUPLI_FLAG_VIEWPORT = 1 << 0, OB_DUPLI_FLAG_RENDER = 1 << 1, }; -/* ob->empty_image_depth */ +/** #Object.empty_image_depth */ #define OB_EMPTY_IMAGE_DEPTH_DEFAULT 0 #define OB_EMPTY_IMAGE_DEPTH_FRONT 1 #define OB_EMPTY_IMAGE_DEPTH_BACK 2 diff --git a/source/blender/makesdna/DNA_particle_types.h b/source/blender/makesdna/DNA_particle_types.h index a51c532dfb3..5add664f624 100644 --- a/source/blender/makesdna/DNA_particle_types.h +++ b/source/blender/makesdna/DNA_particle_types.h @@ -72,7 +72,7 @@ typedef struct ParticleSpring { unsigned int particle_index[2], delete_flag; } ParticleSpring; -/* Child particles are created around or between parent particles */ +/** Child particles are created around or between parent particles. */ typedef struct ChildParticle { /** Face index on the final derived mesh. */ int num; @@ -364,8 +364,7 @@ typedef struct ParticleSystem { int flag, totpart, totunexist, totchild, totcached, totchildcache; /* NOTE: Recalc is one of ID_RECALC_PSYS_ALL flags. * - * TODO(sergey): Use part->id.recalc instead of this duplicated flag - * somehow. */ + * TODO(sergey): Use #ParticleSettings.id.recalc instead of this duplicated flag somehow. */ int recalc; short target_psys, totkeyed, bakespace; char _pad1[6]; @@ -438,9 +437,11 @@ typedef enum eParticleDrawFlag { PART_DRAW_HAIR_GRID = (1 << 18), } eParticleDrawFlag; -/* part->type +/** + * #ParticleSettings.type * Hair is always baked static in object/geometry space. - * Other types (normal particles) are in global space and not static baked. */ + * Other types (normal particles) are in global space and not static baked. + */ enum { PART_EMITTER = 0, /* REACTOR type currently unused */ @@ -458,7 +459,7 @@ enum { PART_FLUID_SPRAYFOAMBUBBLE = 12, }; -/* Mirroring Mantaflow particle types from particle.h (Mantaflow header). */ +/** Mirroring Mantaflow particle types from particle.h (Mantaflow header). */ enum { /* PARTICLE_TYPE_NONE = (0 << 0), */ /* UNUSED */ /* PARTICLE_TYPE_NEW = (1 << 0), */ /* UNUSED */ @@ -470,7 +471,7 @@ enum { /* PARTICLE_TYPE_INVALID = (1 << 30), */ /* UNUSED */ }; -/* part->flag */ +/** #ParticleSettings.flag */ #define PART_REACT_STA_END 1 #define PART_REACT_MULTIPLE 2 @@ -514,26 +515,26 @@ enum { #define PART_SELF_EFFECT (1 << 22) -/* part->from */ +/** #ParticleSettings.from */ #define PART_FROM_VERT 0 #define PART_FROM_FACE 1 #define PART_FROM_VOLUME 2 /* #define PART_FROM_PARTICLE 3 deprecated! */ #define PART_FROM_CHILD 4 -/* part->distr */ +/** #ParticleSettings.distr */ #define PART_DISTR_JIT 0 #define PART_DISTR_RAND 1 #define PART_DISTR_GRID 2 -/* part->phystype */ +/** #ParticleSettings.phystype */ #define PART_PHYS_NO 0 #define PART_PHYS_NEWTON 1 #define PART_PHYS_KEYED 2 #define PART_PHYS_BOIDS 3 #define PART_PHYS_FLUID 4 -/* part->kink */ +/** #ParticleSettings.kink */ typedef enum eParticleKink { PART_KINK_NO = 0, PART_KINK_CURL = 1, @@ -543,7 +544,7 @@ typedef enum eParticleKink { PART_KINK_SPIRAL = 5, } eParticleKink; -/* part->child_flag */ +/** #ParticleSettings.child_flag */ typedef enum eParticleChildFlag { PART_CHILD_USE_CLUMP_NOISE = (1 << 0), PART_CHILD_USE_CLUMP_CURVE = (1 << 1), @@ -551,22 +552,22 @@ typedef enum eParticleChildFlag { PART_CHILD_USE_TWIST_CURVE = (1 << 3), } eParticleChildFlag; -/* part->shape_flag */ +/** #ParticleSettings.shape_flag */ typedef enum eParticleShapeFlag { PART_SHAPE_CLOSE_TIP = (1 << 0), } eParticleShapeFlag; -/* part->draw_col */ +/* #ParticleSettings.draw_col */ #define PART_DRAW_COL_NONE 0 #define PART_DRAW_COL_MAT 1 #define PART_DRAW_COL_VEL 2 #define PART_DRAW_COL_ACC 3 -/* part->time_flag */ +/* #ParticleSettings.time_flag */ #define PART_TIME_AUTOSF 1 /* Automatic subframes */ -/* part->draw_as */ -/* part->ren_as */ +/* #ParticleSettings.draw_as */ +/* #ParticleSettings.ren_as */ #define PART_DRAW_NOT 0 #define PART_DRAW_DOT 1 #define PART_DRAW_HALO 1 @@ -580,13 +581,13 @@ typedef enum eParticleShapeFlag { #define PART_DRAW_BB 9 /* deprecated */ #define PART_DRAW_REND 10 -/* part->integrator */ +/* #ParticleSettings.integrator */ #define PART_INT_EULER 0 #define PART_INT_MIDPOINT 1 #define PART_INT_RK4 2 #define PART_INT_VERLET 3 -/* part->rotmode */ +/* #ParticleSettings.rotmode */ #define PART_ROT_NOR 1 #define PART_ROT_VEL 2 #define PART_ROT_GLOB_X 3 @@ -597,7 +598,7 @@ typedef enum eParticleShapeFlag { #define PART_ROT_OB_Z 8 #define PART_ROT_NOR_TAN 9 -/* part->avemode */ +/* #ParticleSettings.avemode */ #define PART_AVE_VELOCITY 1 #define PART_AVE_RAND 2 #define PART_AVE_HORIZONTAL 3 @@ -606,12 +607,12 @@ typedef enum eParticleShapeFlag { #define PART_AVE_GLOBAL_Y 6 #define PART_AVE_GLOBAL_Z 7 -/* part->reactevent */ +/* #ParticleSettings.reactevent */ #define PART_EVENT_DEATH 0 #define PART_EVENT_COLLIDE 1 #define PART_EVENT_NEAR 2 -/* part->childtype */ +/* #ParticleSettings.childtype */ #define PART_CHILD_PARTICLES 1 #define PART_CHILD_FACES 2 @@ -675,7 +676,7 @@ typedef enum eParticleShapeFlag { #define PTARGET_MODE_FRIEND 1 #define PTARGET_MODE_ENEMY 2 -/* mapto */ +/** #MTex.mapto */ typedef enum eParticleTextureInfluence { /* init */ PAMAP_TIME = (1 << 0), /* emission time */ diff --git a/source/blender/makesdna/DNA_pointcloud_types.h b/source/blender/makesdna/DNA_pointcloud_types.h index 26f1db3324b..53fda29a33a 100644 --- a/source/blender/makesdna/DNA_pointcloud_types.h +++ b/source/blender/makesdna/DNA_pointcloud_types.h @@ -54,7 +54,7 @@ typedef struct PointCloud { void *batch_cache; } PointCloud; -/* PointCloud.flag */ +/** #PointCloud.flag */ enum { PT_DS_EXPAND = (1 << 0), }; diff --git a/source/blender/makesdna/DNA_rigidbody_types.h b/source/blender/makesdna/DNA_rigidbody_types.h index aa11e74e89d..f653905e169 100644 --- a/source/blender/makesdna/DNA_rigidbody_types.h +++ b/source/blender/makesdna/DNA_rigidbody_types.h @@ -38,7 +38,7 @@ struct EffectorWeights; /* ******************************** */ /* RigidBody World */ -/* Container for data shared by original and evaluated copies of RigidBodyWorld */ +/** Container for data shared by original and evaluated copies of #RigidBodyWorld. */ typedef struct RigidBodyWorld_Shared { /* cache */ struct PointCache *pointcache; @@ -90,7 +90,7 @@ typedef struct RigidBodyWorld { float time_scale; } RigidBodyWorld; -/* Flags for RigidBodyWorld */ +/** RigidBodyWorld.flag */ typedef enum eRigidBodyWorld_Flag { /* should sim world be skipped when evaluating (user setting) */ RBW_FLAG_MUTED = (1 << 0), @@ -170,7 +170,7 @@ typedef struct RigidBodyOb { struct RigidBodyOb_Shared *shared; } RigidBodyOb; -/* Participation types for RigidBodyOb */ +/** #RigidBodyOb.type */ typedef enum eRigidBodyOb_Type { /* active geometry participant in simulation. is directly controlled by sim */ RBO_TYPE_ACTIVE = 0, @@ -178,7 +178,7 @@ typedef enum eRigidBodyOb_Type { RBO_TYPE_PASSIVE = 1, } eRigidBodyOb_Type; -/* Flags for RigidBodyOb */ +/** #RigidBodyOb.flag */ typedef enum eRigidBodyOb_Flag { /* rigidbody is kinematic (controlled by the animation system) */ RBO_FLAG_KINEMATIC = (1 << 0), @@ -198,7 +198,7 @@ typedef enum eRigidBodyOb_Flag { RBO_FLAG_USE_DEFORM = (1 << 7), } eRigidBodyOb_Flag; -/* RigidBody Collision Shape */ +/** Rigid Body Collision Shape. */ typedef enum eRigidBody_Shape { /** Simple box (i.e. bounding box). */ RB_SHAPE_BOX = 0, @@ -304,7 +304,7 @@ typedef struct RigidBodyCon { void *physics_constraint; } RigidBodyCon; -/* Participation types for RigidBodyOb */ +/** Participation types for #RigidBodyOb.type */ typedef enum eRigidBodyCon_Type { /** lets bodies rotate around a specified point */ RBC_TYPE_POINT = 0, @@ -333,13 +333,13 @@ typedef enum eRigidBodyCon_Type { RBC_TYPE_MOTOR = 11, } eRigidBodyCon_Type; -/* Spring implementation type for RigidBodyOb */ +/** Spring implementation type for RigidBodyOb. */ typedef enum eRigidBodyCon_SpringType { RBC_SPRING_TYPE1 = 0, /* btGeneric6DofSpringConstraint */ RBC_SPRING_TYPE2 = 1, /* btGeneric6DofSpring2Constraint */ } eRigidBodyCon_SpringType; -/* Flags for RigidBodyCon */ +/** #RigidBodyCon.flag */ typedef enum eRigidBodyCon_Flag { /* constraint influences rigid body motion */ RBC_FLAG_ENABLED = (1 << 0), diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index c66ac3a6211..4607a47a9a8 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -195,7 +195,7 @@ typedef struct AudioData { /* *************************************************************** */ /* Render Layers */ -/* Render Layer */ +/** Render Layer. */ typedef struct SceneRenderLayer { struct SceneRenderLayer *next, *prev; @@ -323,7 +323,7 @@ typedef enum eScenePassType { #define RE_PASSNAME_BLOOM "BloomCol" #define RE_PASSNAME_VOLUME_LIGHT "VolumeDir" -/* View - MultiView */ +/** View - MultiView. */ typedef struct SceneRenderView { struct SceneRenderView *next, *prev; @@ -785,12 +785,12 @@ typedef struct RenderData { struct CurveMapping mblur_shutter_curve; } RenderData; -/* RenderData.quality_flag */ +/** #RenderData.quality_flag */ typedef enum eQualityOption { SCE_PERF_HQ_NORMALS = (1 << 0), } eQualityOption; -/* RenderData.hair_type */ +/** #RenderData.hair_type */ typedef enum eHairType { SCE_HAIR_SHAPE_STRAND = 0, SCE_HAIR_SHAPE_STRIP = 1, @@ -799,7 +799,7 @@ typedef enum eHairType { /* *************************************************************** */ /* Render Conversion/Simplification Settings */ -/* control render convert and shading engine */ +/** Control render convert and shading engine. */ typedef struct RenderProfile { struct RenderProfile *next, *prev; char name[32]; @@ -829,7 +829,7 @@ typedef struct RenderProfile { #define STEREO_RIGHT_SUFFIX "_R" #define STEREO_LEFT_SUFFIX "_L" -/* View3D.stereo3d_camera / View3D.multiview_eye / ImageUser.multiview_eye */ +/** #View3D.stereo3d_camera / #View3D.multiview_eye / #ImageUser.multiview_eye */ typedef enum eStereoViews { STEREO_LEFT_ID = 0, STEREO_RIGHT_ID = 1, @@ -861,12 +861,12 @@ typedef struct Paint_Runtime { char _pad[2]; } Paint_Runtime; -/* We might want to store other things here. */ +/** We might want to store other things here. */ typedef struct PaintToolSlot { struct Brush *brush; } PaintToolSlot; -/* Paint Tool Base */ +/** Paint Tool Base. */ typedef struct Paint { struct Brush *brush; @@ -903,7 +903,7 @@ typedef struct Paint { /* ------------------------------------------- */ /* Image Paint */ -/* Texture/Image Editor */ +/** Texture/Image Editor. */ typedef struct ImagePaintSettings { Paint paint; @@ -934,7 +934,7 @@ typedef struct ImagePaintSettings { /* ------------------------------------------- */ /* Particle Edit */ -/* Settings for a Particle Editing Brush */ +/** Settings for a Particle Editing Brush. */ typedef struct ParticleBrushData { /** Common setting. */ short size; @@ -944,7 +944,7 @@ typedef struct ParticleBrushData { float strength; } ParticleBrushData; -/* Particle Edit Mode Settings */ +/** Particle Edit Mode Settings. */ typedef struct ParticleEditSettings { short flag; short totrekey; @@ -971,7 +971,7 @@ typedef struct ParticleEditSettings { /* ------------------------------------------- */ /* Sculpt */ -/* Sculpt */ +/** Sculpt. */ typedef struct Sculpt { Paint paint; @@ -1006,7 +1006,7 @@ typedef struct UvSculpt { Paint paint; } UvSculpt; -/* grease pencil drawing brushes */ +/** Grease pencil drawing brushes. */ typedef struct GpPaint { Paint paint; int flag; @@ -1020,21 +1020,21 @@ enum { GPPAINT_FLAG_USE_VERTEXCOLOR = 1, }; -/* Grease pencil vertex paint. */ +/** Grease pencil vertex paint. */ typedef struct GpVertexPaint { Paint paint; int flag; char _pad[4]; } GpVertexPaint; -/* Grease pencil sculpt paint. */ +/** Grease pencil sculpt paint. */ typedef struct GpSculptPaint { Paint paint; int flag; char _pad[4]; } GpSculptPaint; -/* Grease pencil weight paint. */ +/** Grease pencil weight paint. */ typedef struct GpWeightPaint { Paint paint; int flag; @@ -1044,7 +1044,7 @@ typedef struct GpWeightPaint { /* ------------------------------------------- */ /* Vertex Paint */ -/* Vertex Paint */ +/** Vertex Paint. */ typedef struct VPaint { Paint paint; char flag; @@ -1062,7 +1062,7 @@ enum { /* ------------------------------------------- */ /* GPencil Stroke Sculpting */ -/* GP_Sculpt_Settings.lock_axis */ +/** #GP_Sculpt_Settings.lock_axis */ typedef enum eGP_Lockaxis_Types { GP_LOCKAXIS_VIEW = 0, GP_LOCKAXIS_X = 1, @@ -1071,7 +1071,7 @@ typedef enum eGP_Lockaxis_Types { GP_LOCKAXIS_CURSOR = 4, } eGP_Lockaxis_Types; -/* Settings for a GPencil Speed Guide */ +/** Settings for a GPencil Speed Guide. */ typedef struct GP_Sculpt_Guide { char use_guide; char use_snapping; @@ -1085,7 +1085,7 @@ typedef struct GP_Sculpt_Guide { struct Object *reference_object; } GP_Sculpt_Guide; -/* GPencil Stroke Sculpting Settings */ +/** GPencil Stroke Sculpting Settings. */ typedef struct GP_Sculpt_Settings { /** Runtime. */ void *paintcursor; @@ -1134,7 +1134,7 @@ typedef enum eGP_vertex_SelectMaskFlag { GP_VERTEX_MASK_SELECTMODE_SEGMENT = (1 << 2), } eGP_Vertex_SelectMaskFlag; -/* Settings for GP Interpolation Operators */ +/** Settings for GP Interpolation Operators. */ typedef struct GP_Interpolate_Settings { /** Custom interpolation curve (for use with GP_IPO_CURVEMAP). */ struct CurveMapping *custom_ipo; @@ -1255,7 +1255,7 @@ typedef struct UnifiedPaintSettings { struct ColorSpace *colorspace; } UnifiedPaintSettings; -/* UnifiedPaintSettings.flag */ +/** #UnifiedPaintSettings.flag */ typedef enum { UNIFIED_PAINT_SIZE = (1 << 0), UNIFIED_PAINT_ALPHA = (1 << 1), @@ -1313,7 +1313,7 @@ enum { /* *************************************************************** */ /* Stats */ -/* Stats for Meshes */ +/** Stats for Meshes. */ typedef struct MeshStatVis { char type; char _pad1[2]; @@ -1570,8 +1570,8 @@ typedef struct PhysicsSettings { char _pad0[4]; } PhysicsSettings; -/* ------------------------------------------- */ -/* Safe Area options used in Camera View & Sequencer +/** + * Safe Area options used in Camera View & Sequencer. */ typedef struct DisplaySafeAreas { /* each value represents the (x,y) margins as a multiplier. @@ -1587,8 +1587,9 @@ typedef struct DisplaySafeAreas { float action_center[2]; } DisplaySafeAreas; -/* ------------------------------------------- */ -/* Scene Display - used for store scene specific display settings for the 3d view */ +/** + * Scene Display - used for store scene specific display settings for the 3d view. + */ typedef struct SceneDisplay { /** Light direction for shadows/highlight. */ float light_direction[3]; diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index a4c254d6e5a..1a1d7cba7af 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -244,7 +244,7 @@ typedef struct PanelCategoryDyn { rcti rect; } PanelCategoryDyn; -/* region stack of active tabs */ +/** Region stack of active tabs. */ typedef struct PanelCategoryStack { struct PanelCategoryStack *next, *prev; char idname[64]; @@ -654,8 +654,10 @@ enum { #define UILST_FLT_SORT_MASK (((unsigned int)(UILST_FLT_SORT_REVERSE | UILST_FLT_SORT_LOCK)) - 1) -/* regiontype, first two are the default set */ -/* Do NOT change order, append on end. Types are hardcoded needed */ +/** + * regiontype, first two are the default set. + * \warning Do NOT change order, append on end. Types are hard-coded needed. + */ typedef enum eRegion_Type { RGN_TYPE_WINDOW = 0, RGN_TYPE_HEADER = 1, diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index e1bba60396a..5fe67a34dae 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -47,6 +47,10 @@ struct SequenceLookup; struct VFont; struct bSound; +/* -------------------------------------------------------------------- */ +/** \name Sequence & Editing Structs + * \{ */ + /* strlens; 256= FILE_MAXFILE, 768= FILE_MAXDIR */ typedef struct StripAnim { @@ -311,7 +315,12 @@ typedef struct Editing { void *_pad1; } Editing; -/* ************* Effect Variable Structs ********* */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Effect Variable Structs + * \{ */ + typedef struct WipeVars { float edgeWidth, angle; short forward, wipetype; @@ -360,7 +369,7 @@ typedef struct SpeedControlVars { float speed_fader_frame_number; } SpeedControlVars; -/* SpeedControlVars.speed_control_type */ +/** #SpeedControlVars.speed_control_type */ enum { SEQ_SPEED_STRETCH = 0, SEQ_SPEED_MULTIPLY = 1, @@ -387,7 +396,7 @@ typedef struct TextVars { char _pad[5]; } TextVars; -/* TextVars.flag */ +/** #TextVars.flag */ enum { SEQ_TEXT_SHADOW = (1 << 0), SEQ_TEXT_BOX = (1 << 1), @@ -395,14 +404,14 @@ enum { SEQ_TEXT_ITALIC = (1 << 3), }; -/* TextVars.align */ +/** #TextVars.align */ enum { SEQ_TEXT_ALIGN_X_LEFT = 0, SEQ_TEXT_ALIGN_X_CENTER = 1, SEQ_TEXT_ALIGN_X_RIGHT = 2, }; -/* TextVars.align_y */ +/** #TextVars.align_y */ enum { SEQ_TEXT_ALIGN_Y_TOP = 0, SEQ_TEXT_ALIGN_Y_CENTER = 1, @@ -418,7 +427,11 @@ typedef struct ColorMixVars { float factor; } ColorMixVars; -/* ***************** Sequence modifiers ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sequence Modifiers + * \{ */ typedef struct SequenceModifierData { struct SequenceModifierData *next, *prev; @@ -489,7 +502,11 @@ enum { SEQ_TONEMAP_RD_PHOTORECEPTOR = 1, }; -/* ***************** Scopes ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Scopes + * \{ */ typedef struct SequencerScopes { struct ImBuf *reference_ibuf; @@ -522,10 +539,15 @@ typedef struct SequencerScopes { #define SEQ_SPEED_UNUSED_3 (1 << 2) /* cleared */ #define SEQ_SPEED_USE_INTERPOLATION (1 << 3) -/* ***************** SEQUENCE ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Flags & Types + * \{ */ + #define SEQ_NAME_MAXSTR 64 -/* seq->flag */ +/** #Sequence.flag */ enum { /* SELECT */ SEQ_LEFTSEL = (1 << 1), @@ -568,7 +590,7 @@ enum { SEQ_INVALID_EFFECT = (1u << 31), }; -/* StripProxy->storage */ +/** #StripProxy.storage */ enum { SEQ_STORAGE_PROXY_CUSTOM_FILE = (1 << 1), /* store proxy in custom directory */ SEQ_STORAGE_PROXY_CUSTOM_DIR = (1 << 2), /* store proxy in custom file */ @@ -601,18 +623,22 @@ enum { #define SEQ_PROXY_TC_RECORD_RUN_NO_GAPS 8 #define SEQ_PROXY_TC_ALL 15 -/* SeqProxy->build_flags */ +/** SeqProxy.build_flags */ enum { SEQ_PROXY_SKIP_EXISTING = 1, }; -/* seq->alpha_mode */ +/** #Sequence.alpha_mode */ enum { SEQ_ALPHA_STRAIGHT = 0, SEQ_ALPHA_PREMUL = 1, }; -/* seq->type WATCH IT: SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip!!! */ +/** + * #Sequence.type + * + * \warning #SEQ_TYPE_EFFECT BIT is used to determine if this is an effect strip! + */ enum { SEQ_TYPE_IMAGE = 0, SEQ_TYPE_META = 1, @@ -681,7 +707,7 @@ enum { /* modifiers */ -/* SequenceModifierData->type */ +/** #SequenceModifierData.type */ enum { seqModifierType_ColorBalance = 1, seqModifierType_Curves = 2, @@ -694,7 +720,7 @@ enum { NUM_SEQUENCE_MODIFIER_TYPES, }; -/* SequenceModifierData->flag */ +/** #SequenceModifierData.flag */ enum { SEQUENCE_MODIFIER_MUTE = (1 << 0), SEQUENCE_MODIFIER_EXPANDED = (1 << 1), @@ -712,13 +738,14 @@ enum { SEQUENCE_MASK_TIME_ABSOLUTE = 1, }; -/* Sequence->cache_flag - * SEQ_CACHE_STORE_RAW - * SEQ_CACHE_STORE_PREPROCESSED - * SEQ_CACHE_STORE_COMPOSITE - * FINAL_OUT is ignored +/** + * #Sequence.cache_flag + * - #SEQ_CACHE_STORE_RAW + * - #SEQ_CACHE_STORE_PREPROCESSED + * - #SEQ_CACHE_STORE_COMPOSITE + * - #FINAL_OUT is ignored * - * Editing->cache_flag + * #Editing.cache_flag * all entries */ enum { @@ -745,7 +772,7 @@ enum { SEQ_CACHE_STORE_THUMBNAIL = (1 << 12), }; -/* Sequence->color_tag. */ +/** #Sequence.color_tag. */ typedef enum SequenceColorTag { SEQUENCE_COLOR_NONE = -1, SEQUENCE_COLOR_01, diff --git a/source/blender/makesdna/DNA_shader_fx_types.h b/source/blender/makesdna/DNA_shader_fx_types.h index 01e3b3a5230..be787c1760f 100644 --- a/source/blender/makesdna/DNA_shader_fx_types.h +++ b/source/blender/makesdna/DNA_shader_fx_types.h @@ -77,7 +77,7 @@ typedef struct ShaderFxData { char *error; } ShaderFxData; -/* Runtime temp data */ +/** Runtime temp data. */ typedef struct ShaderFxData_Runtime { float loc[3]; char _pad[4]; diff --git a/source/blender/makesdna/DNA_simulation_types.h b/source/blender/makesdna/DNA_simulation_types.h index a700c9fe2f8..b14301ed32d 100644 --- a/source/blender/makesdna/DNA_simulation_types.h +++ b/source/blender/makesdna/DNA_simulation_types.h @@ -38,7 +38,7 @@ typedef struct Simulation { char _pad[4]; } Simulation; -/* Simulation.flag */ +/** #Simulation.flag */ enum { SIM_DS_EXPAND = (1 << 0), }; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index a7a19be5b3e..5a98277531c 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -61,16 +61,16 @@ struct bNodeTree; struct wmOperator; struct wmTimer; -/* Defined in `buttons_intern.h`. */ +/** Defined in `buttons_intern.h`. */ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; -/* Defined in `node_intern.hh`. */ +/** Defined in `node_intern.hh`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; -/* Defined in `file_intern.h`. */ +/** Defined in `file_intern.h`. */ typedef struct SpaceFile_Runtime SpaceFile_Runtime; -/* Defined in `spreadsheet_intern.hh`. */ +/** Defined in `spreadsheet_intern.hh`. */ typedef struct SpaceSpreadsheet_Runtime SpaceSpreadsheet_Runtime; /* -------------------------------------------------------------------- */ @@ -91,7 +91,7 @@ typedef struct SpaceLink { char _pad0[6]; } SpaceLink; -/* SpaceLink.link_flag */ +/** #SpaceLink.link_flag */ enum { /** * The space is not a regular one opened through the editor menu (for example) but spawned by an @@ -113,7 +113,7 @@ enum { /** \name Space Info * \{ */ -/* Info Header */ +/** Info Header. */ typedef struct SpaceInfo { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -127,7 +127,7 @@ typedef struct SpaceInfo { char _pad[7]; } SpaceInfo; -/* SpaceInfo.rpt_mask */ +/** #SpaceInfo.rpt_mask */ typedef enum eSpaceInfo_RptMask { INFO_RPT_DEBUG = (1 << 0), INFO_RPT_INFO = (1 << 1), @@ -142,7 +142,7 @@ typedef enum eSpaceInfo_RptMask { /** \name Properties Editor * \{ */ -/* Properties Editor */ +/** Properties Editor. */ typedef struct SpaceProperties { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -210,7 +210,7 @@ typedef struct SpaceProperties { // #define BUTS_EFFECTS 14 #endif /* DNA_DEPRECATED_ALLOW */ -/* SpaceProperties.mainb new */ +/** #SpaceProperties.mainb new */ typedef enum eSpaceButtons_Context { BCONTEXT_RENDER = 0, BCONTEXT_SCENE = 1, @@ -235,7 +235,7 @@ typedef enum eSpaceButtons_Context { BCONTEXT_TOT, } eSpaceButtons_Context; -/* SpaceProperties.flag */ +/** #SpaceProperties.flag */ typedef enum eSpaceButtons_Flag { /* SB_PRV_OSA = (1 << 0), */ /* UNUSED */ SB_PIN_CONTEXT = (1 << 1), @@ -246,7 +246,7 @@ typedef enum eSpaceButtons_Flag { SB_SHADING_CONTEXT = (1 << 4), } eSpaceButtons_Flag; -/* SpaceProperties.outliner_sync */ +/** #SpaceProperties.outliner_sync */ typedef enum eSpaceButtons_OutlinerSync { PROPERTIES_SYNC_AUTO = 0, PROPERTIES_SYNC_NEVER = 1, @@ -259,10 +259,10 @@ typedef enum eSpaceButtons_OutlinerSync { /** \name Outliner * \{ */ -/* Defined in `outliner_intern.h`. */ +/** Defined in `outliner_intern.h`. */ typedef struct SpaceOutliner_Runtime SpaceOutliner_Runtime; -/* Outliner */ +/** Outliner */ typedef struct SpaceOutliner { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -303,7 +303,7 @@ typedef struct SpaceOutliner { SpaceOutliner_Runtime *runtime; } SpaceOutliner; -/* SpaceOutliner.flag */ +/** #SpaceOutliner.flag */ typedef enum eSpaceOutliner_Flag { /* SO_TESTBLOCKS = (1 << 0), */ /* UNUSED */ /* SO_NEWSELECTED = (1 << 1), */ /* UNUSED */ @@ -314,7 +314,7 @@ typedef enum eSpaceOutliner_Flag { SO_MODE_COLUMN = (1 << 6), } eSpaceOutliner_Flag; -/* SpaceOutliner.filter */ +/** #SpaceOutliner.filter */ typedef enum eSpaceOutliner_Filter { SO_FILTER_SEARCH = (1 << 0), /* Run-time flag. */ SO_FILTER_CLEARED_1 = (1 << 1), @@ -356,7 +356,7 @@ typedef enum eSpaceOutliner_Filter { (SO_FILTER_NO_OB_CONTENT | SO_FILTER_NO_CHILDREN | SO_FILTER_OB_TYPE | SO_FILTER_OB_STATE | \ SO_FILTER_NO_COLLECTION | SO_FILTER_NO_VIEW_LAYERS | SO_FILTER_NO_LIB_OVERRIDE) -/* SpaceOutliner.filter_state */ +/** #SpaceOutliner.filter_state */ typedef enum eSpaceOutliner_StateFilter { SO_FILTER_OB_ALL = 0, SO_FILTER_OB_VISIBLE = 1, @@ -366,7 +366,7 @@ typedef enum eSpaceOutliner_StateFilter { SO_FILTER_OB_SELECTABLE = 5, } eSpaceOutliner_StateFilter; -/* SpaceOutliner.show_restrict_flags */ +/** #SpaceOutliner.show_restrict_flags */ typedef enum eSpaceOutliner_ShowRestrictFlag { SO_RESTRICT_ENABLE = (1 << 0), SO_RESTRICT_SELECT = (1 << 1), @@ -377,7 +377,7 @@ typedef enum eSpaceOutliner_ShowRestrictFlag { SO_RESTRICT_INDIRECT_ONLY = (1 << 6), } eSpaceOutliner_Restrict; -/* SpaceOutliner.outlinevis */ +/** #SpaceOutliner.outlinevis */ typedef enum eSpaceOutliner_Mode { SO_SCENES = 0, /* SO_CUR_SCENE = 1, */ /* deprecated! */ @@ -398,7 +398,7 @@ typedef enum eSpaceOutliner_Mode { SO_OVERRIDES_LIBRARY = 16, } eSpaceOutliner_Mode; -/* SpaceOutliner.storeflag */ +/** #SpaceOutliner.storeflag */ typedef enum eSpaceOutliner_StoreFlag { /* cleanup tree */ SO_TREESTORE_CLEANUP = (1 << 0), @@ -408,7 +408,7 @@ typedef enum eSpaceOutliner_StoreFlag { SO_TREESTORE_REBUILD = (1 << 2), } eSpaceOutliner_StoreFlag; -/* outliner search flags (SpaceOutliner.search_flags) */ +/** Outliner search flags (#SpaceOutliner.search_flags) */ typedef enum eSpaceOutliner_Search_Flags { SO_FIND_CASE_SENSITIVE = (1 << 0), SO_FIND_COMPLETE = (1 << 1), @@ -429,7 +429,7 @@ typedef struct SpaceGraph_Runtime { ListBase ghost_curves; } SpaceGraph_Runtime; -/* 'Graph' Editor (formerly known as the IPO Editor) */ +/** 'Graph' Editor (formerly known as the IPO Editor). */ typedef struct SpaceGraph { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -467,7 +467,7 @@ typedef struct SpaceGraph { SpaceGraph_Runtime runtime; } SpaceGraph; -/* SpaceGraph.flag (Graph Editor Settings) */ +/** #SpaceGraph.flag (Graph Editor Settings) */ typedef enum eGraphEdit_Flag { /* OLD DEPRECATED SETTING */ /* SIPO_LOCK_VIEW = (1 << 0), */ @@ -504,7 +504,7 @@ typedef enum eGraphEdit_Flag { SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17), } eGraphEdit_Flag; -/* SpaceGraph.mode (Graph Editor Mode) */ +/** #SpaceGraph.mode (Graph Editor Mode) */ typedef enum eGraphEdit_Mode { /* all animation curves (from all over Blender) */ SIPO_MODE_ANIMATION = 0, @@ -532,7 +532,7 @@ typedef enum eGraphEdit_Runtime_Flag { /** \name NLA Editor * \{ */ -/* NLA Editor */ +/** NLA Editor */ typedef struct SpaceNla { struct SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -552,7 +552,7 @@ typedef struct SpaceNla { View2D v2d DNA_DEPRECATED; } SpaceNla; -/* SpaceNla.flag */ +/** #SpaceNla.flag */ typedef enum eSpaceNla_Flag { SNLA_FLAG_UNUSED_0 = (1 << 0), SNLA_FLAG_UNUSED_1 = (1 << 1), @@ -581,7 +581,7 @@ typedef struct SequencerPreviewOverlay { char _pad0[4]; } SequencerPreviewOverlay; -/* SequencerPreviewOverlay.flag */ +/** #SequencerPreviewOverlay.flag */ typedef enum eSpaceSeq_SequencerPreviewOverlay_Flag { SEQ_PREVIEW_SHOW_2D_CURSOR = (1 << 1), SEQ_PREVIEW_SHOW_OUTLINE_SELECTED = (1 << 2), @@ -596,7 +596,7 @@ typedef struct SequencerTimelineOverlay { char _pad0[4]; } SequencerTimelineOverlay; -/* SequencerTimelineOverlay.flag */ +/** #SequencerTimelineOverlay.flag */ typedef enum eSpaceSeq_SequencerTimelineOverlay_Flag { SEQ_TIMELINE_SHOW_STRIP_OFFSETS = (1 << 1), SEQ_TIMELINE_SHOW_THUMBNAILS = (1 << 2), @@ -617,7 +617,7 @@ typedef struct SpaceSeqRuntime { struct GHash *last_displayed_thumbnails; } SpaceSeqRuntime; -/* Sequencer */ +/** Sequencer. */ typedef struct SpaceSeq { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -667,7 +667,7 @@ typedef struct SpaceSeq { SpaceSeqRuntime runtime; } SpaceSeq; -/* SpaceSeq.mainb */ +/** #SpaceSeq.mainb */ typedef enum eSpaceSeq_RegionType { SEQ_DRAW_IMG_IMBUF = 1, SEQ_DRAW_IMG_WAVEFORM = 2, @@ -675,14 +675,14 @@ typedef enum eSpaceSeq_RegionType { SEQ_DRAW_IMG_HISTOGRAM = 4, } eSpaceSeq_RegionType; -/* SpaceSeq.draw_flag */ +/** #SpaceSeq.draw_flag */ typedef enum eSpaceSeq_DrawFlag { SEQ_DRAW_BACKDROP = (1 << 0), SEQ_DRAW_UNUSED_1 = (1 << 1), SEQ_DRAW_TRANSFORM_PREVIEW = (1 << 2), } eSpaceSeq_DrawFlag; -/* SpaceSeq.flag */ +/** #SpaceSeq.flag */ typedef enum eSpaceSeq_Flag { SEQ_DRAWFRAMES = (1 << 0), SEQ_MARKER_TRANS = (1 << 1), @@ -703,14 +703,14 @@ typedef enum eSpaceSeq_Flag { SEQ_SHOW_GRID = (1 << 18), } eSpaceSeq_Flag; -/* SpaceSeq.view */ +/** #SpaceSeq.view */ typedef enum eSpaceSeq_Displays { SEQ_VIEW_SEQUENCE = 1, SEQ_VIEW_PREVIEW = 2, SEQ_VIEW_SEQUENCE_PREVIEW = 3, } eSpaceSeq_Dispays; -/* SpaceSeq.render_size */ +/** #SpaceSeq.render_size */ typedef enum eSpaceSeq_Proxy_RenderSize { SEQ_RENDER_SIZE_NONE = -1, SEQ_RENDER_SIZE_SCENE = 0, @@ -740,7 +740,7 @@ enum { SEQ_GIZMO_HIDE_TOOL = (1 << 3), }; -/* SpaceSeq.mainb */ +/** #SpaceSeq.mainb */ typedef enum eSpaceSeq_OverlayFrameType { SEQ_OVERLAY_FRAME_TYPE_RECT = 0, SEQ_OVERLAY_FRAME_TYPE_REFERENCE = 1, @@ -753,7 +753,7 @@ typedef enum eSpaceSeq_OverlayFrameType { /** \name File Selector * \{ */ -/* Config and Input for File Selector */ +/** Config and Input for File Selector. */ typedef struct FileSelectParams { /** Title, also used for the text of the execute button. */ char title[96]; @@ -857,7 +857,7 @@ typedef struct FileFolderHistory { ListBase folders_next; } FileFolderHistory; -/* File Browser */ +/** File Browser. */ typedef struct SpaceFile { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -921,7 +921,7 @@ typedef struct SpaceFile { SpaceFile_Runtime *runtime; } SpaceFile; -/* SpaceFile.browse_mode (File Space Browsing Mode) */ +/** #SpaceFile.browse_mode (File Space Browsing Mode). */ typedef enum eFileBrowse_Mode { /* Regular Blender File Browser */ FILE_BROWSE_MODE_FILES = 0, @@ -929,7 +929,7 @@ typedef enum eFileBrowse_Mode { FILE_BROWSE_MODE_ASSETS = 1, } eFileBrowse_Mode; -/* FileSelectParams.display */ +/** #FileSelectParams.display */ enum eFileDisplayType { /** Internal (not exposed to users): Keep whatever display type was used during the last File * Browser use, or the default if no such record is found. Use this unless there's a good reason @@ -943,7 +943,7 @@ enum eFileDisplayType { FILE_IMGDISPLAY = 3, }; -/* FileSelectParams.sort */ +/** #FileSelectParams.sort */ enum eFileSortType { /** Internal (not exposed to users): Sort by whatever was sorted by during the last File Browser * use, or the default if no such record is found. Use this unless there's a good reason to set a @@ -958,14 +958,14 @@ enum eFileSortType { FILE_SORT_SIZE = 4, }; -/* SpaceFile.tags */ +/** #SpaceFile.tags */ enum eFileTags { /** Tag the space as having to update files representing or containing main data. Must be set * after file read and undo/redo. */ FILE_TAG_REBUILD_MAIN_FILES = (1 << 0), }; -/* FileSelectParams.details_flags */ +/** #FileSelectParams.details_flags */ enum eFileDetails { FILE_DETAILS_SIZE = (1 << 0), FILE_DETAILS_DATETIME = (1 << 1), @@ -986,7 +986,7 @@ enum eFileDetails { */ #define FILE_SELECT_MAX_RECURSIONS (FILE_MAX_LIBEXTRA / 2) -/* filesel types */ +/** Filesel types. */ typedef enum eFileSelectType { FILE_LOADLIB = 1, FILE_MAIN = 2, @@ -1000,14 +1000,14 @@ typedef enum eFileSelectType { FILE_SPECIAL = 9, } eFileSelectType; -/* filesel op property -> action */ +/** filesel op property -> action. */ typedef enum eFileSel_Action { FILE_OPENFILE = 0, FILE_SAVE = 1, } eFileSel_Action; -/* sfile->params->flag */ /** + * #FileSelectParams.flag / `sfile->params->flag`. * \note short flag, also used as 16 lower bits of flags in link/append code * (WM and BLO code area, see #eBLOLibLinkFlags in BLO_readfile.h). */ @@ -1022,7 +1022,7 @@ typedef enum eFileSel_Params_Flag { FILE_DIRSEL_ONLY = (1 << 7), FILE_FILTER = (1 << 8), FILE_PARAMS_FLAG_UNUSED_3 = (1 << 9), - FILE_PARAMS_FLAG_UNUSED_4 = (1 << 10), + FILE_PATH_TOKENS_ALLOW = (1 << 10), FILE_SORT_INVERT = (1 << 11), FILE_HIDE_TOOL_PROPS = (1 << 12), FILE_CHECK_EXISTING = (1 << 13), @@ -1037,8 +1037,10 @@ typedef enum eFileSel_Params_AssetCatalogVisibility { FILE_SHOW_ASSETS_WITHOUT_CATALOG, } eFileSel_Params_AssetCatalogVisibility; -/* sfile->params->rename_flag */ -/* NOTE: short flag. Defined as bitflags, but currently only used as exclusive status markers... */ +/** + * #FileSelectParams.rename_flag / `sfile->params->rename_flag`. + * \note short flag. Defined as bit-flags, but currently only used as exclusive status markers. + */ typedef enum eFileSel_Params_RenameFlag { /** Used when we only have the name of the entry we want to rename, * but not yet access to its matching file entry. */ @@ -1084,7 +1086,7 @@ typedef enum eFileSel_File_Types { FILE_TYPE_BLENDERLIB = (1u << 31), } eFileSel_File_Types; -/* Selection Flags in filesel: struct direntry, unsigned char selflag */ +/** Selection Flags in filesel: struct direntry, unsigned char selflag. */ typedef enum eDirEntry_SelectFlag { /* FILE_SEL_ACTIVE = (1 << 1), */ /* UNUSED */ FILE_SEL_HIGHLIGHTED = (1 << 2), @@ -1156,7 +1158,7 @@ typedef struct FileDirEntryArr { char root[1024]; } FileDirEntryArr; -/* FileDirEntry.flags */ +/** #FileDirEntry.flags */ enum { /* The preview for this entry could not be generated. */ FILE_ENTRY_INVALID_PREVIEW = 1 << 0, @@ -1243,7 +1245,7 @@ typedef struct SpaceImage { SpaceImageOverlay overlay; } SpaceImage; -/* SpaceImage.dt_uv */ +/** #SpaceImage.dt_uv */ typedef enum eSpaceImage_UVDT { SI_UVDT_OUTLINE = 0, SI_UVDT_DASH = 1, @@ -1251,20 +1253,20 @@ typedef enum eSpaceImage_UVDT { SI_UVDT_WHITE = 3, } eSpaceImage_UVDT; -/* SpaceImage.dt_uvstretch */ +/** #SpaceImage.dt_uvstretch */ typedef enum eSpaceImage_UVDT_Stretch { SI_UVDT_STRETCH_ANGLE = 0, SI_UVDT_STRETCH_AREA = 1, } eSpaceImage_UVDT_Stretch; -/* SpaceImage.pixel_snap_mode */ +/** #SpaceImage.pixel_snap_mode */ typedef enum eSpaceImage_PixelSnapMode { SI_PIXEL_SNAP_DISABLED = 0, SI_PIXEL_SNAP_CENTER = 1, SI_PIXEL_SNAP_CORNER = 2, } eSpaceImage_Snap_Mode; -/* SpaceImage.mode */ +/** #SpaceImage.mode */ typedef enum eSpaceImage_Mode { SI_MODE_VIEW = 0, SI_MODE_PAINT = 1, @@ -1281,7 +1283,7 @@ typedef enum eSpaceImage_Sticky { SI_STICKY_VERTEX = 2, } eSpaceImage_Sticky; -/* SpaceImage.flag */ +/** #SpaceImage.flag */ typedef enum eSpaceImage_Flag { SI_FLAG_UNUSED_0 = (1 << 0), /* cleared */ SI_FLAG_UNUSED_1 = (1 << 1), /* cleared */ @@ -1375,7 +1377,7 @@ typedef struct SpaceText_Runtime { } SpaceText_Runtime; -/* Text Editor */ +/** Text Editor. */ typedef struct SpaceText { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1425,7 +1427,7 @@ typedef struct SpaceText { SpaceText_Runtime runtime; } SpaceText; -/* SpaceText flags (moved from DNA_text_types.h) */ +/** SpaceText flags (moved from DNA_text_types.h). */ typedef enum eSpaceText_Flags { /* scrollable */ ST_SCROLL_SELECT = (1 << 0), @@ -1449,7 +1451,7 @@ typedef enum eSpaceText_Flags { /** \name Script View (Obsolete) * \{ */ -/* Script Runtime Data - Obsolete (pre 2.5) */ +/** Script Runtime Data - Obsolete (pre 2.5). */ typedef struct Script { ID id; @@ -1474,7 +1476,7 @@ typedef struct Script { _script->py_globaldict = NULL; \ _script->flags = 0 -/* Script View - Obsolete (pre 2.5) */ +/** Script View - Obsolete (pre 2.5). */ typedef struct SpaceScript { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1584,7 +1586,7 @@ typedef struct SpaceNode { SpaceNode_Runtime *runtime; } SpaceNode; -/* SpaceNode.flag */ +/** #SpaceNode.flag */ typedef enum eSpaceNode_Flag { SNODE_BACKDRAW = (1 << 1), SNODE_SHOW_GPENCIL = (1 << 2), @@ -1602,7 +1604,7 @@ typedef enum eSpaceNode_Flag { SNODE_SKIP_INSOFFSET = (1 << 13), } eSpaceNode_Flag; -/* SpaceNode.texfrom */ +/** #SpaceNode.texfrom */ typedef enum eSpaceNode_TexFrom { /* SNODE_TEX_OBJECT = 0, */ SNODE_TEX_WORLD = 1, @@ -1610,14 +1612,14 @@ typedef enum eSpaceNode_TexFrom { SNODE_TEX_LINESTYLE = 3, } eSpaceNode_TexFrom; -/* SpaceNode.shaderfrom */ +/** #SpaceNode.shaderfrom */ typedef enum eSpaceNode_ShaderFrom { SNODE_SHADER_OBJECT = 0, SNODE_SHADER_WORLD = 1, SNODE_SHADER_LINESTYLE = 2, } eSpaceNode_ShaderFrom; -/* SpaceNode.insert_ofs_dir */ +/** #SpaceNode.insert_ofs_dir */ enum { SNODE_INSERTOFS_DIR_RIGHT = 0, SNODE_INSERTOFS_DIR_LEFT = 1, @@ -1629,7 +1631,7 @@ enum { /** \name Console * \{ */ -/* Console content */ +/** Console content. */ typedef struct ConsoleLine { struct ConsoleLine *next, *prev; @@ -1645,7 +1647,7 @@ typedef struct ConsoleLine { int type; } ConsoleLine; -/* ConsoleLine.type */ +/** #ConsoleLine.type */ typedef enum eConsoleLine_Type { CONSOLE_LINE_OUTPUT = 0, CONSOLE_LINE_INPUT = 1, @@ -1653,7 +1655,7 @@ typedef enum eConsoleLine_Type { CONSOLE_LINE_ERROR = 3, } eConsoleLine_Type; -/* Console View */ +/** Console View. */ typedef struct SpaceConsole { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1707,7 +1709,7 @@ typedef struct SpaceUserPref { /** \name Motion Tracking * \{ */ -/* Clip Editor */ +/** Clip Editor. */ typedef struct SpaceClip { SpaceLink *next, *prev; /** Storage of regions for inactive spaces. */ @@ -1770,7 +1772,7 @@ typedef struct SpaceClip { MaskSpaceInfo mask_info; } SpaceClip; -/* SpaceClip.flag */ +/** #SpaceClip.flag */ typedef enum eSpaceClip_Flag { SC_SHOW_MARKER_PATTERN = (1 << 0), SC_SHOW_MARKER_SEARCH = (1 << 1), @@ -1797,7 +1799,7 @@ typedef enum eSpaceClip_Flag { SC_SHOW_METADATA = (1 << 22), } eSpaceClip_Flag; -/* SpaceClip.mode */ +/** #SpaceClip.mode */ typedef enum eSpaceClip_Mode { SC_MODE_TRACKING = 0, // SC_MODE_RECONSTRUCTION = 1, /* DEPRECATED */ @@ -1805,14 +1807,14 @@ typedef enum eSpaceClip_Mode { SC_MODE_MASKEDIT = 3, } eSpaceClip_Mode; -/* SpaceClip.view */ +/** #SpaceClip.view */ typedef enum eSpaceClip_View { SC_VIEW_CLIP = 0, SC_VIEW_GRAPH = 1, SC_VIEW_DOPESHEET = 2, } eSpaceClip_View; -/* SpaceClip.gpencil_src */ +/** #SpaceClip.gpencil_src */ typedef enum eSpaceClip_GPencil_Source { SC_GPENCIL_SRC_CLIP = 0, SC_GPENCIL_SRC_TRACK = 1, @@ -2030,8 +2032,10 @@ typedef enum eSpreadsheetColumnValueType { /** \name Space Defines (eSpace_Type) * \{ */ -/* space types, moved from DNA_screen_types.h */ -/* Do NOT change order, append on end. types are hardcoded needed */ +/** + * Space types: #SpaceLink.spacetype & #ScrArea.spacetype. + * \note Do NOT change order, append on end. types are hardcoded needed. + */ typedef enum eSpace_Type { SPACE_EMPTY = 0, SPACE_VIEW3D = 1, diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 2c3cd8eab77..cd19825d29f 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -98,8 +98,10 @@ typedef struct CBData { int cur; } CBData; -/* 32 = MAXCOLORBAND */ -/* note that this has to remain a single struct, for UserDef */ +/** + * 32 = #MAXCOLORBAND + * \note that this has to remain a single struct, for UserDef. + */ typedef struct ColorBand { short tot, cur; char ipotype, ipotype_hue; @@ -454,14 +456,14 @@ typedef struct ColorMapping { /* **************** ColorBand ********************* */ -/* colormode */ +/** color-mode. */ enum { COLBAND_BLEND_RGB = 0, COLBAND_BLEND_HSV = 1, COLBAND_BLEND_HSL = 2, }; -/* interpolation */ +/** Interpolation. */ enum { COLBAND_INTERP_LINEAR = 0, COLBAND_INTERP_EASE = 1, @@ -470,7 +472,7 @@ enum { COLBAND_INTERP_CONSTANT = 4, }; -/* color interpolation */ +/** Color interpolation. */ enum { COLBAND_HUE_NEAR = 0, COLBAND_HUE_FAR = 1, @@ -509,7 +511,7 @@ enum { /* #define TEX_PD_NOISE_AGE 2 */ /* Deprecated */ /* #define TEX_PD_NOISE_TIME 3 */ /* Deprecated */ -/* color_source */ +/** color_source. */ enum { TEX_PD_COLOR_CONSTANT = 0, /* color_source: particles */ diff --git a/source/blender/makesdna/DNA_tracking_types.h b/source/blender/makesdna/DNA_tracking_types.h index 0e313183300..815fab59876 100644 --- a/source/blender/makesdna/DNA_tracking_types.h +++ b/source/blender/makesdna/DNA_tracking_types.h @@ -462,7 +462,7 @@ typedef struct MovieTracking { MovieTrackingDopesheet dopesheet; } MovieTracking; -/* MovieTrackingCamera->distortion_model */ +/** #MovieTrackingCamera.distortion_model */ enum { TRACKING_DISTORTION_MODEL_POLYNOMIAL = 0, TRACKING_DISTORTION_MODEL_DIVISION = 1, @@ -470,13 +470,13 @@ enum { TRACKING_DISTORTION_MODEL_BROWN = 3, }; -/* MovieTrackingCamera->units */ +/** #MovieTrackingCamera.units */ enum { CAMERA_UNITS_PX = 0, CAMERA_UNITS_MM = 1, }; -/* MovieTrackingMarker->flag */ +/** #MovieTrackingMarker.flag */ enum { MARKER_DISABLED = (1 << 0), MARKER_TRACKED = (1 << 1), @@ -485,7 +485,7 @@ enum { MARKER_GRAPH_SEL = (MARKER_GRAPH_SEL_X | MARKER_GRAPH_SEL_Y), }; -/* MovieTrackingTrack->flag */ +/** #MovieTrackingTrack.flag */ enum { TRACK_HAS_BUNDLE = (1 << 1), TRACK_DISABLE_RED = (1 << 2), @@ -501,7 +501,7 @@ enum { TRACK_USE_2D_STAB_ROT = (1 << 12), }; -/* MovieTrackingTrack->motion_model */ +/** #MovieTrackingTrack.motion_model */ enum { TRACK_MOTION_MODEL_TRANSLATION = 0, TRACK_MOTION_MODEL_TRANSLATION_ROTATION = 1, @@ -511,27 +511,27 @@ enum { TRACK_MOTION_MODEL_HOMOGRAPHY = 5, }; -/* MovieTrackingTrack->algorithm_flag */ +/** #MovieTrackingTrack.algorithm_flag */ enum { TRACK_ALGORITHM_FLAG_USE_BRUTE = (1 << 0), TRACK_ALGORITHM_FLAG_USE_NORMALIZATION = (1 << 2), TRACK_ALGORITHM_FLAG_USE_MASK = (1 << 3), }; -/* MovieTrackingTrack->pattern_match */ +/** #MovieTrackingTrack.pattern_match */ typedef enum eTrackFrameMatch { TRACK_MATCH_KEYFRAME = 0, TRACK_MATCH_PREVIOS_FRAME = 1, } eTrackFrameMatch; -/* MovieTrackingSettings->motion_flag */ +/** #MovieTrackingSettings.motion_flag */ enum { TRACKING_MOTION_TRIPOD = (1 << 0), TRACKING_MOTION_MODAL = (TRACKING_MOTION_TRIPOD), }; -/* MovieTrackingSettings->speed */ +/** #MovieTrackingSettings.speed */ enum { TRACKING_SPEED_FASTEST = 0, TRACKING_SPEED_REALTIME = 1, @@ -540,13 +540,13 @@ enum { TRACKING_SPEED_DOUBLE = 5, }; -/* MovieTrackingSettings->reconstruction_flag */ +/** #MovieTrackingSettings.reconstruction_flag */ enum { /* TRACKING_USE_FALLBACK_RECONSTRUCTION = (1 << 0), */ /* DEPRECATED */ TRACKING_USE_KEYFRAME_SELECTION = (1 << 1), }; -/* MovieTrackingSettings->refine_camera_intrinsics */ +/** #MovieTrackingSettings.refine_camera_intrinsics */ enum { REFINE_NO_INTRINSICS = (0), @@ -556,7 +556,7 @@ enum { REFINE_TANGENTIAL_DISTORTION = (1 << 3), }; -/* MovieTrackingStabilization->flag */ +/** #MovieTrackingStabilization.flag */ enum { TRACKING_2D_STABILIZATION = (1 << 0), TRACKING_AUTOSCALE = (1 << 1), @@ -565,19 +565,19 @@ enum { TRACKING_SHOW_STAB_TRACKS = (1 << 5), }; -/* MovieTrackingStabilization->filter */ +/** #MovieTrackingStabilization.filter */ enum { TRACKING_FILTER_NEAREST = 0, TRACKING_FILTER_BILINEAR = 1, TRACKING_FILTER_BICUBIC = 2, }; -/* MovieTrackingReconstruction->flag */ +/** #MovieTrackingReconstruction.flag */ enum { TRACKING_RECONSTRUCTED = (1 << 0), }; -/* MovieTrackingObject->flag */ +/** #MovieTrackingObject.flag */ enum { TRACKING_OBJECT_CAMERA = (1 << 0), }; @@ -588,7 +588,7 @@ enum { TRACKING_CLEAN_DELETE_SEGMENT = 2, }; -/* MovieTrackingDopesheet->sort_method */ +/** #MovieTrackingDopesheet.sort_method */ enum { TRACKING_DOPE_SORT_NAME = 0, TRACKING_DOPE_SORT_LONGEST = 1, @@ -598,27 +598,27 @@ enum { TRACKING_DOPE_SORT_END = 5, }; -/* MovieTrackingDopesheet->flag */ +/** #MovieTrackingDopesheet.flag */ enum { TRACKING_DOPE_SORT_INVERSE = (1 << 0), TRACKING_DOPE_SELECTED_ONLY = (1 << 1), TRACKING_DOPE_SHOW_HIDDEN = (1 << 2), }; -/* MovieTrackingDopesheetCoverageSegment->trackness */ +/** #MovieTrackingDopesheetCoverageSegment.trackness */ enum { TRACKING_COVERAGE_BAD = 0, TRACKING_COVERAGE_ACCEPTABLE = 1, TRACKING_COVERAGE_OK = 2, }; -/* MovieTrackingPlaneMarker->flag */ +/** #MovieTrackingPlaneMarker.flag */ enum { PLANE_MARKER_DISABLED = (1 << 0), PLANE_MARKER_TRACKED = (1 << 1), }; -/* MovieTrackingPlaneTrack->flag */ +/** #MovieTrackingPlaneTrack.flag */ enum { PLANE_TRACK_HIDDEN = (1 << 1), PLANE_TRACK_LOCKED = (1 << 2), diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index c8fdac19b61..34415308ef6 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -30,7 +30,8 @@ extern "C" { #endif -/* themes; defines in BIF_resource.h */ +/* Themes; defines in `BIF_resource.h`. */ + struct ColorBand; /* ************************ style definitions ******************** */ @@ -50,8 +51,10 @@ typedef enum eUIFont_ID { /* UIFONT_CUSTOM2 = 3, */ /* UNUSED */ } eUIFont_ID; -/* default fonts to load/initialize */ -/* first font is the default (index 0), others optional */ +/** + * Default fonts to load/initialize. + * First font is the default (index 0), others optional. + */ typedef struct uiFont { struct uiFont *next, *prev; /** 1024 = FILE_MAX. */ @@ -445,7 +448,7 @@ typedef enum eBackgroundGradientTypes { TH_BACKGROUND_GRADIENT_RADIAL = 2, } eBackgroundGradientTypes; -/* set of colors for use as a custom color set for Objects/Bones wire drawing */ +/** Set of colors for use as a custom color set for Objects/Bones wire drawing. */ typedef struct ThemeWireColor { unsigned char solid[4]; unsigned char select[4]; @@ -959,7 +962,7 @@ typedef struct UserDef { UserDef_Runtime runtime; } UserDef; -/* from blenkernel blender.c */ +/** From blenkernel `blender.c`. */ extern UserDef U; /* ***************** USERDEF ****************** */ @@ -1142,6 +1145,7 @@ typedef enum eUserpref_GPU_Flag { USER_GPU_FLAG_NO_DEPT_PICK = (1 << 0), USER_GPU_FLAG_NO_EDIT_MODE_SMOOTH_WIRE = (1 << 1), USER_GPU_FLAG_OVERLAY_SMOOTH_WIRE = (1 << 2), + USER_GPU_FLAG_SUBDIVISION_EVALUATION = (1 << 3), } eUserpref_GPU_Flag; /** #UserDef.tablet_api */ diff --git a/source/blender/makesdna/DNA_view2d_types.h b/source/blender/makesdna/DNA_view2d_types.h index f8166305fd9..6c03422963d 100644 --- a/source/blender/makesdna/DNA_view2d_types.h +++ b/source/blender/makesdna/DNA_view2d_types.h @@ -31,7 +31,7 @@ extern "C" { /* ---------------------------------- */ -/* View 2D data - stored per region */ +/** View 2D data - stored per region. */ typedef struct View2D { /** Tot - area that data can be drawn in; cur - region of tot that is visible in viewport. */ rctf tot, cur; @@ -83,7 +83,7 @@ typedef struct View2D { /* ---------------------------------- */ -/* view zooming restrictions, per axis (v2d->keepzoom) */ +/** View zooming restrictions, per axis (#View2D.keepzoom) */ enum { /* zoom is clamped to lie within limits set by minzoom and maxzoom */ V2D_LIMITZOOM = (1 << 0), @@ -97,7 +97,7 @@ enum { V2D_LOCKZOOM_Y = (1 << 9), }; -/* view panning restrictions, per axis (v2d->keepofs) */ +/** View panning restrictions, per axis (#View2D.keepofs). */ enum { /* panning on x-axis is not allowed */ V2D_LOCKOFS_X = (1 << 1), @@ -109,7 +109,7 @@ enum { V2D_KEEPOFS_Y = (1 << 4), }; -/* view extent restrictions (v2d->keeptot) */ +/** View extent restrictions (#View2D.keeptot). */ enum { /** 'cur' view can be out of extents of 'tot' */ V2D_KEEPTOT_FREE = 0, @@ -120,7 +120,7 @@ enum { V2D_KEEPTOT_STRICT = 2, }; -/* general refresh settings (v2d->flag) */ +/** General refresh settings (#View2D.flag). */ enum { /* global view2d horizontal locking (for showing same time interval) */ /* TODO: this flag may be set in old files but is not accessible currently, @@ -138,7 +138,7 @@ enum { V2D_IS_INIT = (1 << 10), }; -/* scroller flags for View2D (v2d->scroll) */ +/** Scroller flags for View2D (#View2D.scroll). */ enum { /* left scrollbar */ V2D_SCROLL_LEFT = (1 << 0), @@ -162,13 +162,15 @@ enum { V2D_SCROLL_HORIZONTAL_FULLR = (1 << 10), }; -/* scroll_ui, activate flag for drawing */ +/** scroll_ui, activate flag for drawing. */ enum { V2D_SCROLL_H_ACTIVE = (1 << 0), V2D_SCROLL_V_ACTIVE = (1 << 1), }; -/* alignment flags for totrect, flags use 'shading-out' convention (v2d->align) */ +/** + * Alignment flags for `totrect`, flags use 'shading-out' convention (#View2D.align). + */ enum { /* all quadrants free */ V2D_ALIGN_FREE = 0, diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 3fd2f1208dd..5f4353b6f3a 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -245,7 +245,7 @@ typedef struct View3DOverlay { char _pad[4]; } View3DOverlay; -/* View3DOverlay->handle_display */ +/** #View3DOverlay.handle_display */ typedef enum eHandleDisplay { /* Display only selected points. */ CURVE_HANDLE_SELECTED = 0, diff --git a/source/blender/makesdna/DNA_volume_types.h b/source/blender/makesdna/DNA_volume_types.h index 1344f295ea9..df5a122faaf 100644 --- a/source/blender/makesdna/DNA_volume_types.h +++ b/source/blender/makesdna/DNA_volume_types.h @@ -30,13 +30,13 @@ struct PackedFile; struct VolumeGridVector; typedef struct Volume_Runtime { - /* OpenVDB Grids */ + /** OpenVDB Grids. */ struct VolumeGridVector *grids; - /* Current frame in sequence for evaluated volume */ + /** Current frame in sequence for evaluated volume. */ int frame; - /* Default simplify level for volume grids loaded from files. */ + /** Default simplify level for volume grids loaded from files. */ int default_simplify_level; } Volume_Runtime; @@ -96,12 +96,12 @@ typedef struct Volume { Volume_Runtime runtime; } Volume; -/* Volume.flag */ +/** #Volume.flag */ enum { VO_DS_EXPAND = (1 << 0), }; -/* Volume.sequence_mode */ +/** #Volume.sequence_mode */ typedef enum VolumeSequenceMode { VOLUME_SEQUENCE_CLIP = 0, VOLUME_SEQUENCE_EXTEND = 1, @@ -109,7 +109,7 @@ typedef enum VolumeSequenceMode { VOLUME_SEQUENCE_PING_PONG = 3, } VolumeSequenceMode; -/* VolumeDisplay.wireframe_type */ +/** #VolumeDisplay.wireframe_type */ typedef enum VolumeWireframeType { VOLUME_WIREFRAME_NONE = 0, VOLUME_WIREFRAME_BOUNDS = 1, @@ -117,32 +117,32 @@ typedef enum VolumeWireframeType { VOLUME_WIREFRAME_POINTS = 3, } VolumeWireframeType; -/* VolumeDisplay.wireframe_detail */ +/** #VolumeDisplay.wireframe_detail */ typedef enum VolumeWireframeDetail { VOLUME_WIREFRAME_COARSE = 0, VOLUME_WIREFRAME_FINE = 1, } VolumeWireframeDetail; -/* VolumeRender.space */ +/** #VolumeRender.space */ typedef enum VolumeRenderSpace { VOLUME_SPACE_OBJECT = 0, VOLUME_SPACE_WORLD = 1, } VolumeRenderSpace; -/* VolumeDisplay.interpolation_method */ +/** #VolumeDisplay.interpolation_method */ typedef enum VolumeDisplayInterpMethod { VOLUME_DISPLAY_INTERP_LINEAR = 0, VOLUME_DISPLAY_INTERP_CUBIC = 1, VOLUME_DISPLAY_INTERP_CLOSEST = 2, } VolumeDisplayInterpMethod; -/* VolumeDisplay.axis_slice_method */ +/** #VolumeDisplay.axis_slice_method */ typedef enum AxisAlignedSlicingMethod { VOLUME_AXIS_SLICE_FULL = 0, VOLUME_AXIS_SLICE_SINGLE = 1, } AxisAlignedSlicingMethod; -/* VolumeDisplay.slice_axis */ +/** #VolumeDisplay.slice_axis */ typedef enum SliceAxis { VOLUME_SLICE_AXIS_AUTO = 0, VOLUME_SLICE_AXIS_X = 1, diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 841edaf8724..d0e4184d2a5 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -33,7 +33,8 @@ extern "C" { #endif -/* defined here: */ +/* Defined here: */ + struct wmWindow; struct wmWindowManager; @@ -45,7 +46,8 @@ struct wmMsgBus; struct wmOperator; struct wmOperatorType; -/* forwards */ +/* Forward declarations: */ + struct PointerRNA; struct Report; struct ReportList; @@ -58,7 +60,7 @@ struct wmTimer; #define OP_MAX_TYPENAME 64 #define KMAP_MAX_NAME 64 -/* keep in sync with 'rna_enum_wm_report_items' in wm_rna.c */ +/** Keep in sync with 'rna_enum_wm_report_items' in `wm_rna.c`. */ typedef enum eReportType { RPT_DEBUG = (1 << 0), RPT_INFO = (1 << 1), @@ -100,7 +102,9 @@ typedef struct Report { const char *message; } Report; -/* saved in the wm, don't remove */ +/** + * \note Saved in the wm, don't remove. + */ typedef struct ReportList { ListBase list; /** eReportType. */ @@ -133,7 +137,7 @@ typedef struct wmXrData { /* reports need to be before wmWindowManager */ -/* windowmanager is saved, tag WMAN */ +/** Window-manager is saved, tag WMAN. */ typedef struct wmWindowManager { ID id; @@ -204,13 +208,13 @@ typedef struct wmWindowManager { //#endif } wmWindowManager; -/* wmWindowManager.initialized */ +/** #wmWindowManager.initialized */ enum { WM_WINDOW_IS_INIT = (1 << 0), WM_KEYCONFIG_IS_INIT = (1 << 1), }; -/* wmWindowManager.outliner_sync_select_dirty */ +/** #wmWindowManager.outliner_sync_select_dirty */ enum { WM_OUTLINER_SYNC_SELECT_FROM_OBJECT = (1 << 0), WM_OUTLINER_SYNC_SELECT_FROM_EDIT_BONE = (1 << 1), @@ -231,7 +235,9 @@ enum { # endif #endif -/* the saveable part, rest of data is local in ghostwinlay */ +/** + * The saveable part, the rest of the data is local in GHOST. + */ typedef struct wmWindow { struct wmWindow *next, *prev; @@ -352,7 +358,9 @@ typedef struct wmOperatorTypeMacro { struct PointerRNA *ptr; } wmOperatorTypeMacro; -/* Partial copy of the event, for matching by event handler. */ +/** + * Partial copy of the event, for matching by event handler. + */ typedef struct wmKeyMapItem { struct wmKeyMapItem *next, *prev; @@ -436,7 +444,9 @@ enum { KMI_TYPE_NDOF = 5, }; -/* stored in WM, the actively used keymaps */ +/** + * Stored in WM, the actively used key-maps. + */ typedef struct wmKeyMap { struct wmKeyMap *next, *prev; diff --git a/source/blender/makesdna/DNA_workspace_types.h b/source/blender/makesdna/DNA_workspace_types.h index a0856588a58..95530c7b0f7 100644 --- a/source/blender/makesdna/DNA_workspace_types.h +++ b/source/blender/makesdna/DNA_workspace_types.h @@ -60,7 +60,9 @@ typedef struct bToolRef_Runtime { int flag; } bToolRef_Runtime; -/* Stored per mode. */ +/** + * \note Stored per mode. + */ typedef struct bToolRef { struct bToolRef *next, *prev; char idname[64]; diff --git a/source/blender/makesdna/intern/dna_utils.h b/source/blender/makesdna/intern/dna_utils.h index b89c45a7a43..7ba71fb970b 100644 --- a/source/blender/makesdna/intern/dna_utils.h +++ b/source/blender/makesdna/intern/dna_utils.h @@ -60,7 +60,9 @@ char *DNA_elem_id_rename(struct MemArena *mem_arena, const int elem_src_full_len, const uint elem_src_full_offset_len); -/* When requesting version info, support both directions. */ +/** + * When requesting version info, support both directions. + */ enum eDNA_RenameDir { DNA_RENAME_STATIC_FROM_ALIAS = -1, DNA_RENAME_ALIAS_FROM_STATIC = 1, diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index 35af92592e9..19c678a4222 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -1095,8 +1095,8 @@ static void rna_property_override_check_resync(Main *bmain, ID *id_src = rna_property_override_property_real_id_owner(bmain, ptr_item_src, NULL, NULL); ID *id_dst = rna_property_override_property_real_id_owner(bmain, ptr_item_dst, NULL, NULL); - BLI_assert(id_src == NULL || ID_IS_OVERRIDE_LIBRARY_REAL(id_src)); - /* Work around file corruption on writing, see T86853. */ + /* If `id_src` is not a liboverride, we cannot perform any further 'need resync' checks from + * here. */ if (id_src != NULL && !ID_IS_OVERRIDE_LIBRARY_REAL(id_src)) { return; } @@ -1117,8 +1117,8 @@ static void rna_property_override_check_resync(Main *bmain, * override copy generated by `BKE_lib_override_library_update` will already have its * self-references updated to itself, instead of still pointing to its linked source. */ (id_dst->lib == id_src->lib && id_dst != id_owner))) { - ptr_dst->owner_id->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; - CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", ptr_dst->owner_id->name); + id_owner->tag |= LIB_TAG_LIB_OVERRIDE_NEED_RESYNC; + CLOG_INFO(&LOG, 3, "Local override %s detected as needing resync", id_owner->name); } } diff --git a/source/blender/makesrna/intern/rna_cloth.c b/source/blender/makesrna/intern/rna_cloth.c index 2bc00dd5af5..187e232b030 100644 --- a/source/blender/makesrna/intern/rna_cloth.c +++ b/source/blender/makesrna/intern/rna_cloth.c @@ -584,6 +584,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ClothSimSettings"); RNA_def_struct_path_func(srna, "rna_ClothSettings_path"); + RNA_define_lib_overridable(true); + /* goal */ prop = RNA_def_property(srna, "goal_min", PROP_FLOAT, PROP_FACTOR); @@ -659,6 +661,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_mass_vgroup_get", "rna_ClothSettings_mass_vgroup_length", "rna_ClothSettings_mass_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Mass Vertex Group", "Vertex Group for pinning of vertices"); RNA_def_property_update(prop, 0, "rna_cloth_pinning_changed"); @@ -707,6 +710,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_shrink_vgroup_get", "rna_ClothSettings_shrink_vgroup_length", "rna_ClothSettings_shrink_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Shrink Vertex Group", "Vertex Group for shrinking cloth"); RNA_def_property_update(prop, 0, "rna_cloth_update"); @@ -810,6 +814,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_struct_vgroup_get", "rna_ClothSettings_struct_vgroup_length", "rna_ClothSettings_struct_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Structural Stiffness Vertex Group", "Vertex group for fine control over structural stiffness"); @@ -820,6 +825,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_shear_vgroup_get", "rna_ClothSettings_shear_vgroup_length", "rna_ClothSettings_shear_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Shear Stiffness Vertex Group", "Vertex group for fine control over shear stiffness"); RNA_def_property_update(prop, 0, "rna_cloth_update"); @@ -856,6 +862,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_bend_vgroup_get", "rna_ClothSettings_bend_vgroup_length", "rna_ClothSettings_bend_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Bending Stiffness Vertex Group", "Vertex group for fine control over bending stiffness"); @@ -874,6 +881,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_rest_shape_key_set", NULL, NULL); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Rest Shape Key", "Shape key to use the rest spring lengths from"); RNA_def_property_update(prop, 0, "rna_cloth_update"); @@ -976,6 +984,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_internal_vgroup_get", "rna_ClothSettings_internal_vgroup_length", "rna_ClothSettings_internal_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Internal Springs Vertex Group", "Vertex group for fine control over the internal spring stiffness"); @@ -1044,6 +1053,7 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) "rna_ClothSettings_pressure_vgroup_get", "rna_ClothSettings_pressure_vgroup_length", "rna_ClothSettings_pressure_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Pressure Vertex Group", @@ -1082,6 +1092,8 @@ static void rna_def_cloth_sim_settings(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Maximum Spring Extension", "Maximum extension before spring gets cut"); # endif + + RNA_define_lib_overridable(false); } static void rna_def_cloth_collision_settings(BlenderRNA *brna) @@ -1097,6 +1109,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) RNA_def_struct_sdna(srna, "ClothCollSettings"); RNA_def_struct_path_func(srna, "rna_ClothCollisionSettings_path"); + RNA_define_lib_overridable(true); + /* general collision */ prop = RNA_def_property(srna, "use_collision", PROP_BOOLEAN, PROP_NONE); @@ -1169,7 +1183,6 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "collection", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "group"); RNA_def_property_flag(prop, PROP_EDITABLE); - RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Collision Collection", "Limit colliders to this Collection"); RNA_def_property_update(prop, 0, "rna_cloth_dependency_update"); @@ -1178,6 +1191,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) "rna_CollSettings_selfcol_vgroup_get", "rna_CollSettings_selfcol_vgroup_length", "rna_CollSettings_selfcol_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Selfcollision Vertex Group", @@ -1189,6 +1203,7 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) "rna_CollSettings_objcol_vgroup_get", "rna_CollSettings_objcol_vgroup_length", "rna_CollSettings_objcol_vgroup_set"); + RNA_def_property_override_clear_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text( prop, "Collision Vertex Group", @@ -1203,6 +1218,8 @@ static void rna_def_cloth_collision_settings(BlenderRNA *brna) "Impulse Clamping", "Clamp collision impulses to avoid instability (0.0 to disable clamping)"); RNA_def_property_update(prop, 0, "rna_cloth_update"); + + RNA_define_lib_overridable(false); } void RNA_def_cloth(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 5c12fc3a227..091b457cc83 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -321,7 +321,7 @@ static void rna_ColorRamp_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * CMP_NODE_VALTORGB, TEX_NODE_VALTORGB, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP)) { - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); } } break; diff --git a/source/blender/makesrna/intern/rna_dynamicpaint.c b/source/blender/makesrna/intern/rna_dynamicpaint.c index a9d5ef089bb..b693d78a302 100644 --- a/source/blender/makesrna/intern/rna_dynamicpaint.c +++ b/source/blender/makesrna/intern/rna_dynamicpaint.c @@ -589,6 +589,7 @@ static void rna_def_canvas_surface(BlenderRNA *brna) prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Effector Weights", ""); prop = RNA_def_property(srna, "drip_velocity", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index a38bbd3d6d2..d3175c445a9 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -388,6 +388,7 @@ void rna_DriverVariable_name_set(PointerRNA *ptr, const char *value) BLI_strncpy_utf8(data->name, value, 64); driver_variable_name_validate(data); + driver_variable_unique_name(data); } /* ----------- */ diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 90e77406f23..7aa96eb8430 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -1461,6 +1461,7 @@ static void rna_def_fluid_domain_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Effector Weights", ""); /* object collections */ diff --git a/source/blender/makesrna/intern/rna_image.c b/source/blender/makesrna/intern/rna_image.c index 2f42e521b52..0d86572357f 100644 --- a/source/blender/makesrna/intern/rna_image.c +++ b/source/blender/makesrna/intern/rna_image.c @@ -168,7 +168,7 @@ static void rna_ImageUser_update(Main *bmain, Scene *scene, PointerRNA *ptr) if (id) { if (GS(id->name) == ID_NT) { /* Special update for nodetrees to find parent datablock. */ - ED_node_tag_update_nodetree(bmain, (bNodeTree *)id, NULL); + ED_node_tree_propagate_change(NULL, bmain, NULL); } else { /* Update material or texture for render preview. */ diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index df0271d81d5..98de40ead93 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -42,6 +42,7 @@ #include "BKE_geometry_set.h" #include "BKE_image.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_texture.h" #include "RNA_access.h" @@ -1219,7 +1220,7 @@ static void rna_NodeTree_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *p WM_main_add_notifier(NC_NODE | NA_EDITED, NULL); WM_main_add_notifier(NC_SCENE | ND_NODES, &ntree->id); - ED_node_tag_update_nodetree(bmain, ntree, NULL); + ED_node_tree_propagate_change(NULL, bmain, ntree); } static bNode *rna_NodeTree_node_new(bNodeTree *ntree, @@ -1269,14 +1270,9 @@ static bNode *rna_NodeTree_node_new(bNodeTree *ntree, } Main *bmain = CTX_data_main(C); - ntreeUpdateTree(bmain, ntree); - nodeUpdate(ntree, node); + ED_node_tree_propagate_change(C, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); - if (node->type == GEO_NODE_INPUT_SCENE_TIME) { - DEG_relations_tag_update(bmain); - } - return node; } @@ -1300,7 +1296,7 @@ static void rna_NodeTree_node_remove(bNodeTree *ntree, RNA_POINTER_INVALIDATE(node_ptr); - ntreeUpdateTree(bmain, ntree); /* update group node socket links */ + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1320,8 +1316,7 @@ static void rna_NodeTree_node_clear(bNodeTree *ntree, Main *bmain, ReportList *r node = next_node; } - ntreeUpdateTree(bmain, ntree); - + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1400,13 +1395,7 @@ static bNodeLink *rna_NodeTree_link_new(bNodeTree *ntree, fromsock->flag &= ~SOCK_HIDDEN; tosock->flag &= ~SOCK_HIDDEN; - if (tonode) { - nodeUpdate(ntree, tonode); - } - - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, ret->tonode); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } return ret; @@ -1431,7 +1420,7 @@ static void rna_NodeTree_link_remove(bNodeTree *ntree, nodeRemLink(ntree, link); RNA_POINTER_INVALIDATE(link_ptr); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1450,8 +1439,7 @@ static void rna_NodeTree_link_clear(bNodeTree *ntree, Main *bmain, ReportList *r link = next_link; } - ntreeUpdateTree(bmain, ntree); - + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1508,7 +1496,7 @@ static bNodeSocket *rna_NodeTree_inputs_new( bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_IN, type, name); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return sock; @@ -1523,7 +1511,7 @@ static bNodeSocket *rna_NodeTree_outputs_new( bNodeSocket *sock = ntreeAddSocketInterface(ntree, SOCK_OUT, type, name); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return sock; @@ -1544,8 +1532,7 @@ static void rna_NodeTree_socket_remove(bNodeTree *ntree, else { ntreeRemoveSocketInterface(ntree, sock); - ntreeUpdateTree(bmain, ntree); - DEG_id_tag_update(&ntree->id, 0); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } } @@ -1560,7 +1547,7 @@ static void rna_NodeTree_inputs_clear(bNodeTree *ntree, Main *bmain, ReportList ntreeRemoveSocketInterface(ntree, socket); } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1574,7 +1561,7 @@ static void rna_NodeTree_outputs_clear(bNodeTree *ntree, Main *bmain, ReportList ntreeRemoveSocketInterface(ntree, socket); } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1603,9 +1590,9 @@ static void rna_NodeTree_inputs_move(bNodeTree *ntree, Main *bmain, int from_ind } } - ntree->update |= NTREE_UPDATE_GROUP_IN; + BKE_ntree_update_tag_interface(ntree); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1634,9 +1621,9 @@ static void rna_NodeTree_outputs_move(bNodeTree *ntree, Main *bmain, int from_in } } - ntree->update |= NTREE_UPDATE_GROUP_OUT; + BKE_ntree_update_tag_interface(ntree); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -1644,10 +1631,8 @@ static void rna_NodeTree_interface_update(bNodeTree *ntree, bContext *C) { Main *bmain = CTX_data_main(C); - ntree->update |= NTREE_UPDATE_GROUP; - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, NULL); + BKE_ntree_update_tag_interface(ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); } /* ******** NodeLink ******** */ @@ -1968,7 +1953,7 @@ static bNodeType *rna_Node_register_base(Main *bmain, /* setup dummy node & node type to store static properties in */ memset(&dummynt, 0, sizeof(bNodeType)); /* this does some additional initialization of default values */ - node_type_base_custom(&dummynt, identifier, "", 0, 0); + node_type_base_custom(&dummynt, identifier, "", 0); memset(&dummynode, 0, sizeof(bNode)); dummynode.typeinfo = &dummynt; @@ -2210,6 +2195,20 @@ static const EnumPropertyItem *rna_FunctionNodeRandomValue_type_itemf(bContext * return itemf_function_check(rna_enum_attribute_type_items, random_value_type_supported); } +static bool accumulate_field_type_supported(const EnumPropertyItem *item) +{ + return ELEM(item->value, CD_PROP_FLOAT, CD_PROP_FLOAT3, CD_PROP_INT32); +} + +static const EnumPropertyItem *rna_GeoNodeAccumulateField_type_itemf(bContext *UNUSED(C), + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + *r_free = true; + return itemf_function_check(rna_enum_attribute_type_items, accumulate_field_type_supported); +} + static const EnumPropertyItem *rna_GeometryNodeAttributeRandomize_operation_itemf( bContext *UNUSED(C), PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) { @@ -2617,7 +2616,8 @@ static void rna_Node_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr) @@ -2626,9 +2626,10 @@ static void rna_Node_update_relations(Main *bmain, Scene *scene, PointerRNA *ptr DEG_relations_tag_update(bmain); } -static void rna_Node_socket_value_update(ID *id, bNode *node, bContext *C) +static void rna_Node_socket_value_update(ID *id, bNode *UNUSED(node), bContext *C) { - ED_node_tag_update_nodetree(CTX_data_main(C), (bNodeTree *)id, node); + BKE_ntree_update_tag_all((bNodeTree *)id); + ED_node_tree_propagate_change(C, CTX_data_main(C), (bNodeTree *)id); } static void rna_Node_select_set(PointerRNA *ptr, bool value) @@ -2682,7 +2683,7 @@ static bNodeSocket *rna_Node_inputs_new(ID *id, BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2716,7 +2717,7 @@ static bNodeSocket *rna_Node_outputs_new(ID *id, BKE_report(reports, RPT_ERROR, "Unable to create socket"); } else { - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2734,7 +2735,7 @@ static void rna_Node_socket_remove( else { nodeRemoveSocket(ntree, node, sock); - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } } @@ -2749,7 +2750,7 @@ static void rna_Node_inputs_clear(ID *id, bNode *node, Main *bmain) nodeRemoveSocket(ntree, node, sock); } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2763,7 +2764,7 @@ static void rna_Node_outputs_clear(ID *id, bNode *node, Main *bmain) nodeRemoveSocket(ntree, node, sock); } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2795,7 +2796,7 @@ static void rna_Node_inputs_move(ID *id, bNode *node, Main *bmain, int from_inde } } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -2827,7 +2828,7 @@ static void rna_Node_outputs_move(ID *id, bNode *node, Main *bmain, int from_ind } } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); } @@ -3055,10 +3056,9 @@ static void rna_NodeSocket_update(Main *bmain, Scene *UNUSED(scene), PointerRNA { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNodeSocket *sock = (bNodeSocket *)ptr->data; - bNode *node; - if (nodeFindNode(ntree, sock, &node, NULL)) { - ED_node_tag_update_nodetree(bmain, ntree, node); - } + + BKE_ntree_update_tag_socket_property(ntree, sock); + ED_node_tree_propagate_change(NULL, bmain, ntree); } static bool rna_NodeSocket_is_output_get(PointerRNA *ptr) @@ -3351,10 +3351,8 @@ static void rna_NodeSocketInterface_update(Main *bmain, Scene *UNUSED(scene), Po return; } - ntree->update |= NTREE_UPDATE_GROUP; - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, NULL); + BKE_ntree_update_tag_interface(ntree); + ED_node_tree_propagate_change(NULL, bmain, ntree); } /* ******** Standard Node Socket Base Types ******** */ @@ -3452,28 +3450,14 @@ static void rna_NodeSocketStandard_vector_range( /* using a context update function here, to avoid searching the node if possible */ static void rna_NodeSocketStandard_value_update(struct bContext *C, PointerRNA *ptr) { - bNode *node; - /* default update */ rna_NodeSocket_update(CTX_data_main(C), CTX_data_scene(C), ptr); - - /* try to use node from context, faster */ - node = CTX_data_pointer_get(C, "node").data; - if (!node) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNodeSocket *sock = ptr->data; - - /* fall back to searching node in the tree */ - nodeFindNode(ntree, sock, &node, NULL); - } } static void rna_NodeSocketStandard_value_and_relation_update(struct bContext *C, PointerRNA *ptr) { rna_NodeSocketStandard_value_update(C, ptr); - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; Main *bmain = CTX_data_main(C); - ntreeUpdateTree(bmain, ntree); DEG_relations_tag_update(bmain); } @@ -3567,12 +3551,11 @@ static bool rna_NodeInternal_poll_instance(bNode *node, bNodeTree *ntree) } } -static void rna_NodeInternal_update(ID *id, bNode *node) +static void rna_NodeInternal_update(ID *id, bNode *node, Main *bmain) { bNodeTree *ntree = (bNodeTree *)id; - if (node->typeinfo->updatefunc) { - node->typeinfo->updatefunc(ntree, node); - } + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_NodeInternal_draw_buttons(ID *id, @@ -3721,7 +3704,8 @@ static void rna_Node_tex_image_update(Main *bmain, Scene *UNUSED(scene), Pointer bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); WM_main_add_notifier(NC_IMAGE, NULL); } @@ -3730,11 +3714,8 @@ static void rna_NodeGroup_update(Main *bmain, Scene *UNUSED(scene), PointerRNA * bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - if (node->id) { - ntreeUpdateTree(bmain, (bNodeTree *)node->id); - } - - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); DEG_relations_tag_update(bmain); } @@ -4142,13 +4123,12 @@ static const EnumPropertyItem *rna_Node_channel_itemf(bContext *UNUSED(C), return item; } -static void rna_Image_Node_update_id(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_Image_Node_update_id(Main *bmain, Scene *scene, PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; node->update |= NODE_UPDATE_ID; - nodeUpdate(ntree, node); /* to update image node sockets */ + rna_Node_update(bmain, scene, ptr); } static void rna_NodeOutputFile_slots_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) @@ -4395,7 +4375,7 @@ static bNodeSocket *rna_NodeOutputFile_slots_new( sock = ntreeCompositOutputFileAddSocket(ntree, node, name, im_format); - ntreeUpdateTree(CTX_data_main(C), ntree); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_main_add_notifier(NC_NODE | NA_EDITED, ntree); return sock; @@ -4504,42 +4484,27 @@ static void rna_ShaderNodeScript_update(Main *bmain, Scene *scene, PointerRNA *p RE_engine_free(engine); } - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(NULL, bmain, ntree); } static void rna_ShaderNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNode *node = (bNode *)ptr->data; - - nodeUpdate(ntree, node); rna_Node_update(bmain, scene, ptr); } static void rna_Node_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNode *node = (bNode *)ptr->data; - - nodeUpdate(ntree, node); rna_Node_update(bmain, scene, ptr); } static void rna_GeometryNode_socket_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNode *node = (bNode *)ptr->data; - - nodeUpdate(ntree, node); rna_Node_update(bmain, scene, ptr); } static void rna_CompositorNodeScale_update(Main *bmain, Scene *scene, PointerRNA *ptr) { - bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - bNode *node = (bNode *)ptr->data; - - nodeUpdate(ntree, node); rna_Node_update(bmain, scene, ptr); } @@ -9491,6 +9456,28 @@ static void def_geo_subdivision_surface(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_accumulate_field(StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeAccumulateField", "storage"); + + prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "data_type"); + RNA_def_property_enum_items(prop, rna_enum_attribute_type_items); + RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeoNodeAccumulateField_type_itemf"); + RNA_def_property_enum_default(prop, CD_PROP_FLOAT); + RNA_def_property_ui_text(prop, "Data Type", "Type of data stored in attribute"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "domain", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "domain"); + RNA_def_property_enum_items(prop, rna_enum_attribute_domain_items); + RNA_def_property_enum_default(prop, ATTR_DOMAIN_POINT); + RNA_def_property_ui_text(prop, "Domain", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_fn_random_value(StructRNA *srna) { PropertyRNA *prop; @@ -12386,7 +12373,7 @@ static void rna_def_internal_node(BlenderRNA *brna) func = RNA_def_function(srna, "update", "rna_NodeInternal_update"); RNA_def_function_ui_description( func, "Update on node graph topology changes (adding or removing nodes and links)"); - RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_ALLOW_WRITE); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN | FUNC_ALLOW_WRITE); /* draw buttons */ func = RNA_def_function(srna, "draw_buttons", "rna_NodeInternal_draw_buttons"); diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 2fca9f0af7a..d697a48e04b 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1128,6 +1128,8 @@ static void rna_def_collision(BlenderRNA *brna) RNA_def_struct_ui_text( srna, "Collision Settings", "Collision settings for object in physics simulation"); + RNA_define_lib_overridable(true); + prop = RNA_def_property(srna, "use", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "deflect", 1); RNA_def_property_ui_text( @@ -1230,6 +1232,8 @@ static void rna_def_collision(BlenderRNA *brna) "Cloth collision impulses act in the direction of the collider normals " "(more reliable in some cases)"); RNA_def_property_update(prop, 0, "rna_CollisionSettings_update"); + + RNA_define_lib_overridable(false); } static void rna_def_effector_weight(BlenderRNA *brna) @@ -1243,6 +1247,8 @@ static void rna_def_effector_weight(BlenderRNA *brna) RNA_def_struct_ui_text(srna, "Effector Weights", "Effector weights for physics simulation"); RNA_def_struct_ui_icon(srna, ICON_PHYSICS); + RNA_define_lib_overridable(true); + /* Flags */ prop = RNA_def_property(srna, "apply_to_hair_growing", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", EFF_WEIGHT_DO_HAIR); @@ -1362,6 +1368,8 @@ static void rna_def_effector_weight(BlenderRNA *brna) RNA_def_property_ui_range(prop, 0.0f, 1.0f, 0.1, 3); RNA_def_property_ui_text(prop, "Fluid Flow", "Fluid Flow effector weight"); RNA_def_property_update(prop, 0, "rna_EffectorWeight_update"); + + RNA_define_lib_overridable(false); } static void rna_def_field(BlenderRNA *brna) @@ -1471,6 +1479,8 @@ static void rna_def_field(BlenderRNA *brna) srna, "Field Settings", "Field settings for an object in physics simulation"); RNA_def_struct_ui_icon(srna, ICON_PHYSICS); + RNA_define_lib_overridable(true); + /* Enums */ prop = RNA_def_property(srna, "type", PROP_ENUM, PROP_NONE); @@ -1514,34 +1524,34 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "strength", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_strength"); - RNA_def_property_range(prop, -FLT_MAX, FLT_MAX); + RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Strength", "Strength of force field"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); /* different ui range to above */ prop = RNA_def_property(srna, "linear_drag", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_strength"); - RNA_def_property_range(prop, -2.0f, 2.0f); + RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3); RNA_def_property_ui_text(prop, "Linear Drag", "Drag component proportional to velocity"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); prop = RNA_def_property(srna, "harmonic_damping", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_damp"); - RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Harmonic Damping", "Damping of the harmonic force"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); /* different ui range to above */ prop = RNA_def_property(srna, "quadratic_drag", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_damp"); - RNA_def_property_range(prop, -2.0f, 2.0f); + RNA_def_property_ui_range(prop, -2.0f, 2.0f, 10, 3); RNA_def_property_ui_text( prop, "Quadratic Drag", "Drag component proportional to the square of velocity"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); prop = RNA_def_property(srna, "flow", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_flow"); - RNA_def_property_range(prop, 0.0f, 10.0f); + RNA_def_property_ui_range(prop, 0.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Flow", "Convert effector force into air flow velocity"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); @@ -1557,7 +1567,7 @@ static void rna_def_field(BlenderRNA *brna) /* different ui range to above */ prop = RNA_def_property(srna, "inflow", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_flow"); - RNA_def_property_range(prop, -10.0f, 10.0f); + RNA_def_property_ui_range(prop, -10.0f, 10.0f, 10, 3); RNA_def_property_ui_text(prop, "Inflow", "Inwards component of the vortex force"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); @@ -1570,7 +1580,8 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "rest_length", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_size"); - RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_range(prop, 0.0f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3); RNA_def_property_ui_text(prop, "Rest Length", "Rest length of the harmonic force"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); @@ -1728,7 +1739,7 @@ static void rna_def_field(BlenderRNA *brna) prop = RNA_def_property(srna, "guide_minimum", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "f_strength"); - RNA_def_property_range(prop, 0.0f, 1000.0f); + RNA_def_property_ui_range(prop, 0.0f, 1000.0f, 10, 3); RNA_def_property_ui_text( prop, "Minimum Distance", "The distance from which particles are affected fully"); RNA_def_property_update(prop, 0, "rna_FieldSettings_update"); @@ -1799,6 +1810,8 @@ static void rna_def_field(BlenderRNA *brna) /* Variables used for Curve Guide, already wrapped, used for other fields too */ /* falloff_power, use_max_distance, maximum_distance */ + + RNA_define_lib_overridable(false); } static void rna_def_softbody(BlenderRNA *brna) @@ -2134,6 +2147,7 @@ static void rna_def_softbody(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "effector_weights"); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Effector Weights", ""); } diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index f732e14d905..fbc7625d815 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -3498,6 +3498,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Effector Weights", ""); /* animation here? */ @@ -3507,12 +3508,14 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "pd"); RNA_def_property_struct_type(prop, "FieldSettings"); RNA_def_property_pointer_funcs(prop, "rna_Particle_field1_get", NULL, NULL, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Force Field 1", ""); prop = RNA_def_property(srna, "force_field_2", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "pd2"); RNA_def_property_struct_type(prop, "FieldSettings"); RNA_def_property_pointer_funcs(prop, "rna_Particle_field2_get", NULL, NULL, NULL); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Force Field 2", ""); /* twist */ diff --git a/source/blender/makesrna/intern/rna_rigidbody.c b/source/blender/makesrna/intern/rna_rigidbody.c index c0fb904101d..10e28ac3948 100644 --- a/source/blender/makesrna/intern/rna_rigidbody.c +++ b/source/blender/makesrna/intern/rna_rigidbody.c @@ -957,6 +957,7 @@ static void rna_def_rigidbody_world(BlenderRNA *brna) prop = RNA_def_property(srna, "effector_weights", PROP_POINTER, PROP_NONE); RNA_def_property_struct_type(prop, "EffectorWeights"); RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_override_flag(prop, PROPOVERRIDE_OVERRIDABLE_LIBRARY); RNA_def_property_ui_text(prop, "Effector Weights", ""); /* Sweep test */ diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index d05f2a13c4b..c6c7341bcc6 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -86,8 +86,7 @@ const EnumPropertyItem rna_enum_exr_codec_items[] = { {R_IMF_EXR_CODEC_B44, "B44", 0, "B44 (lossy)", ""}, {R_IMF_EXR_CODEC_B44A, "B44A", 0, "B44A (lossy)", ""}, {R_IMF_EXR_CODEC_DWAA, "DWAA", 0, "DWAA (lossy)", ""}, - /* NOTE: Commented out for until new OpenEXR is released, see T50673. */ - /* {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, */ + {R_IMF_EXR_CODEC_DWAB, "DWAB", 0, "DWAB (lossy)", ""}, {0, NULL, 0, NULL, NULL}, }; #endif @@ -3262,6 +3261,7 @@ static void rna_def_tool_settings(BlenderRNA *brna) "Automerge", "Join by distance last drawn stroke with previous strokes in the active layer"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); + RNA_def_property_update(prop, NC_SCENE | ND_TOOLSETTINGS, NULL); prop = RNA_def_property(srna, "gpencil_sculpt", PROP_POINTER, PROP_NONE); RNA_def_property_pointer_sdna(prop, NULL, "gp_sculpt"); @@ -5583,7 +5583,7 @@ static void rna_def_scene_ffmpeg_settings(BlenderRNA *brna) {FFMPEG_MPEG2, "MPEG2", 0, "MPEG-2", ""}, {FFMPEG_MPEG4, "MPEG4", 0, "MPEG-4", ""}, {FFMPEG_AVI, "AVI", 0, "AVI", ""}, - {FFMPEG_MOV, "QUICKTIME", 0, "Quicktime", ""}, + {FFMPEG_MOV, "QUICKTIME", 0, "QuickTime", ""}, {FFMPEG_DV, "DV", 0, "DV", ""}, {FFMPEG_OGG, "OGG", 0, "Ogg", ""}, {FFMPEG_MKV, "MKV", 0, "Matroska", ""}, diff --git a/source/blender/makesrna/intern/rna_texture.c b/source/blender/makesrna/intern/rna_texture.c index 5a74cfa9964..f66fb2653b5 100644 --- a/source/blender/makesrna/intern/rna_texture.c +++ b/source/blender/makesrna/intern/rna_texture.c @@ -199,7 +199,7 @@ static void rna_Texture_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *pt } else if (GS(id->name) == ID_NT) { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; - ED_node_tag_update_nodetree(bmain, ntree, NULL); + ED_node_tree_propagate_change(NULL, bmain, ntree); } } diff --git a/source/blender/makesrna/intern/rna_tracking.c b/source/blender/makesrna/intern/rna_tracking.c index c81588aa8b5..03f4acdae79 100644 --- a/source/blender/makesrna/intern/rna_tracking.c +++ b/source/blender/makesrna/intern/rna_tracking.c @@ -24,6 +24,7 @@ #include "MEM_guardedalloc.h" #include "BKE_movieclip.h" +#include "BKE_node_tree_update.h" #include "BKE_tracking.h" #include "RNA_access.h" @@ -415,11 +416,12 @@ static void rna_tracking_stabRotTracks_active_index_range( *max = max_ii(0, clip->tracking.stabilization.tot_rot_track - 1); } -static void rna_tracking_flushUpdate(Main *UNUSED(bmain), Scene *scene, PointerRNA *ptr) +static void rna_tracking_flushUpdate(Main *bmain, Scene *UNUSED(scene), PointerRNA *ptr) { MovieClip *clip = (MovieClip *)ptr->owner_id; - nodeUpdateID(scene->nodetree, &clip->id); + BKE_ntree_update_tag_id_changed(bmain, &clip->id); + BKE_ntree_update_main(bmain, NULL); WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); WM_main_add_notifier(NC_SCENE, NULL); diff --git a/source/blender/makesrna/intern/rna_ui_api.c b/source/blender/makesrna/intern/rna_ui_api.c index f96b3fc5eee..a406e867d6c 100644 --- a/source/blender/makesrna/intern/rna_ui_api.c +++ b/source/blender/makesrna/intern/rna_ui_api.c @@ -582,6 +582,43 @@ static void rna_uiTemplateCacheFile(uiLayout *layout, uiTemplateCacheFile(layout, C, ptr, propname); } +static void rna_uiTemplateCacheFileVelocity(uiLayout *layout, + PointerRNA *ptr, + const char *propname) +{ + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { + return; + } + + uiTemplateCacheFileVelocity(layout, &fileptr); +} + +static void rna_uiTemplateCacheFileProcedural(uiLayout *layout, + bContext *C, + PointerRNA *ptr, + const char *propname) +{ + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { + return; + } + + uiTemplateCacheFileProcedural(layout, C, &fileptr); +} + +static void rna_uiTemplateCacheFileTimeSettings(uiLayout *layout, + PointerRNA *ptr, + const char *propname) +{ + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { + return; + } + + uiTemplateCacheFileTimeSettings(layout, &fileptr); +} + static void rna_uiTemplatePathBuilder(uiLayout *layout, PointerRNA *ptr, const char *propname, @@ -1795,6 +1832,21 @@ void RNA_api_ui_layout(StructRNA *srna) RNA_def_function_flag(func, FUNC_USE_CONTEXT); api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_cache_file_velocity", "rna_uiTemplateCacheFileVelocity"); + RNA_def_function_ui_description(func, "Show cache files velocity properties"); + api_ui_item_rna_common(func); + + func = RNA_def_function( + srna, "template_cache_file_procedural", "rna_uiTemplateCacheFileProcedural"); + RNA_def_function_ui_description(func, "Show cache files render procedural properties"); + RNA_def_function_flag(func, FUNC_USE_CONTEXT); + api_ui_item_rna_common(func); + + func = RNA_def_function( + srna, "template_cache_file_time_settings", "rna_uiTemplateCacheFileTimeSettings"); + RNA_def_function_ui_description(func, "Show cache files time settings"); + api_ui_item_rna_common(func); + func = RNA_def_function(srna, "template_recent_files", "uiTemplateRecentFiles"); RNA_def_function_ui_description(func, "Show list of recently saved .blend files"); RNA_def_int(func, "rows", 5, 1, INT_MAX, "", "Maximum number of items to show", 1, INT_MAX); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index dd1252ffebf..71c38311124 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -182,6 +182,7 @@ static const EnumPropertyItem rna_enum_userdef_viewport_aa_items[] = { # include "BKE_image.h" # include "BKE_main.h" # include "BKE_mesh_runtime.h" +# include "BKE_object.h" # include "BKE_paint.h" # include "BKE_pbvh.h" # include "BKE_preferences.h" @@ -578,6 +579,20 @@ static PointerRNA rna_UserDef_apps_get(PointerRNA *ptr) return rna_pointer_inherit_refine(ptr, &RNA_PreferencesApps, ptr->data); } +/* Reevaluate objects with a subsurf modifier as the last in their modifiers stacks. */ +static void rna_UserDef_subdivision_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + Object *ob; + + for (ob = bmain->objects.first; ob; ob = ob->id.next) { + if (BKE_object_get_last_subsurf_modifier(ob) != NULL) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + } + + rna_userdef_update(bmain, scene, ptr); +} + static void rna_UserDef_audio_update(Main *bmain, Scene *UNUSED(scene), PointerRNA *UNUSED(ptr)) { BKE_sound_init(bmain); @@ -2889,7 +2904,7 @@ static void rna_def_userdef_theme_space_node(BlenderRNA *brna) prop = RNA_def_property(srna, "group_node", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "syntaxc"); - RNA_def_property_array(prop, 4); + RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Group Node", ""); RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); @@ -5651,6 +5666,16 @@ static void rna_def_userdef_system(BlenderRNA *brna) "Use the depth buffer for picking 3D View selection " "(without this the front most object may not be selected first)"); + /* GPU subdivision evaluation. */ + + prop = RNA_def_property(srna, "use_gpu_subdivision", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "gpu_flag", USER_GPU_FLAG_SUBDIVISION_EVALUATION); + RNA_def_property_ui_text(prop, + "GPU Subdivision", + "Enable GPU acceleration for evaluating the last subdivision surface " + "modifiers in the stack"); + RNA_def_property_update(prop, 0, "rna_UserDef_subdivision_update"); + /* Audio */ prop = RNA_def_property(srna, "audio_mixing_buffer", PROP_ENUM, PROP_NONE); diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt index c30beaf001a..e5c94c36a13 100644 --- a/source/blender/modifiers/CMakeLists.txt +++ b/source/blender/modifiers/CMakeLists.txt @@ -114,7 +114,7 @@ set(SRC intern/MOD_weightvgedit.c intern/MOD_weightvgmix.c intern/MOD_weightvgproximity.c - intern/MOD_weld.c + intern/MOD_weld.cc intern/MOD_wireframe.c MOD_modifiertypes.h diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c index 2f0f11ab56d..fa5149a45ba 100644 --- a/source/blender/modifiers/intern/MOD_array.c +++ b/source/blender/modifiers/intern/MOD_array.c @@ -285,7 +285,8 @@ static void mesh_merge_transform(Mesh *result, int cap_nloops, int cap_npolys, int *remap, - int remap_len) + int remap_len, + const bool recalc_normals_later) { int *index_orig; int i; @@ -305,6 +306,15 @@ static void mesh_merge_transform(Mesh *result, mul_m4_v3(cap_offset, mv->co); /* Reset MVert flags for caps */ mv->flag = mv->bweight = 0; + + /* We have to correct normals too, if we do not tag them as dirty later! */ + if (!recalc_normals_later) { + float no[3]; + normal_short_to_float_v3(no, mv->no); + mul_mat3_m4_v3(cap_offset, no); + normalize_v3(no); + normal_float_to_short_v3(mv->no, no); + } } /* remap the vertex groups if necessary */ @@ -711,7 +721,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, start_cap_nloops, start_cap_npolys, vgroup_start_cap_remap, - vgroup_start_cap_remap_len); + vgroup_start_cap_remap_len, + use_recalc_normals); /* Identify doubles with first chunk */ if (use_merge) { dm_mvert_map_doubles(full_doubles_map, @@ -740,7 +751,8 @@ static Mesh *arrayModifier_doArray(ArrayModifierData *amd, end_cap_nloops, end_cap_npolys, vgroup_end_cap_remap, - vgroup_end_cap_remap_len); + vgroup_end_cap_remap_len, + use_recalc_normals); /* Identify doubles with last chunk */ if (use_merge) { dm_mvert_map_doubles(full_doubles_map, diff --git a/source/blender/modifiers/intern/MOD_mask.cc b/source/blender/modifiers/intern/MOD_mask.cc index f452b0c7091..090c4d5512e 100644 --- a/source/blender/modifiers/intern/MOD_mask.cc +++ b/source/blender/modifiers/intern/MOD_mask.cc @@ -702,7 +702,7 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx) Object *armature_ob = mmd->ob_arm; /* Return input mesh if there is no armature with bones. */ - if (ELEM(NULL, armature_ob, armature_ob->pose)) { + if (ELEM(nullptr, armature_ob, armature_ob->pose)) { return mesh; } diff --git a/source/blender/modifiers/intern/MOD_meshsequencecache.c b/source/blender/modifiers/intern/MOD_meshsequencecache.c index bcaf294ec8b..00f39e58b4d 100644 --- a/source/blender/modifiers/intern/MOD_meshsequencecache.c +++ b/source/blender/modifiers/intern/MOD_meshsequencecache.c @@ -328,14 +328,83 @@ static void panel_draw(const bContext *C, Panel *panel) uiItemR(layout, ptr, "use_vertex_interpolation", 0, NULL, ICON_NONE); } + modifier_panel_end(layout, ptr); +} + +static void velocity_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) { + return; + } + + if (RNA_pointer_is_null(&fileptr)) { + return; + } + + uiLayoutSetPropSep(layout, true); + uiTemplateCacheFileVelocity(layout, &fileptr); uiItemR(layout, ptr, "velocity_scale", 0, NULL, ICON_NONE); +} - modifier_panel_end(layout, ptr); +static void time_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) { + return; + } + + if (RNA_pointer_is_null(&fileptr)) { + return; + } + + uiLayoutSetPropSep(layout, true); + uiTemplateCacheFileTimeSettings(layout, &fileptr); +} + +static void render_procedural_panel_draw(const bContext *C, Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA ob_ptr; + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr); + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, "cache_file", &fileptr)) { + return; + } + + if (RNA_pointer_is_null(&fileptr)) { + return; + } + + uiLayoutSetPropSep(layout, true); + uiTemplateCacheFileProcedural(layout, C, &fileptr); } static void panelRegister(ARegionType *region_type) { - modifier_panel_register(region_type, eModifierType_MeshSequenceCache, panel_draw); + PanelType *panel_type = modifier_panel_register( + region_type, eModifierType_MeshSequenceCache, panel_draw); + modifier_subpanel_register(region_type, "time", "Time", NULL, time_panel_draw, panel_type); + modifier_subpanel_register(region_type, + "render_procedural", + "Render Procedural", + NULL, + render_procedural_panel_draw, + panel_type); + modifier_subpanel_register( + region_type, "velocity", "Velocity", NULL, velocity_panel_draw, panel_type); } static void blendRead(BlendDataReader *UNUSED(reader), ModifierData *md) diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index ec6cbeb43bf..cee5d0be65d 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -60,6 +60,7 @@ #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_modifier.h" +#include "BKE_node_tree_update.h" #include "BKE_object.h" #include "BKE_pointcloud.h" #include "BKE_screen.h" @@ -237,7 +238,7 @@ static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphConte NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); DEG_add_modifier_to_transform_relation(ctx->node, "Nodes Modifier"); if (nmd->node_group != nullptr) { - DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier"); + DEG_add_node_tree_output_relation(ctx->node, nmd->node_group, "Nodes Modifier"); Set<ID *> used_ids; find_used_ids_from_settings(nmd->settings, used_ids); @@ -725,7 +726,7 @@ void MOD_nodes_init(Main *bmain, NodesModifierData *nmd) group_input_node, (bNodeSocket *)group_input_node->outputs.first); - ntreeUpdateTree(bmain, ntree); + BKE_ntree_update_main_tree(bmain, ntree, nullptr); } static void initialize_group_input(NodesModifierData &nmd, @@ -1294,7 +1295,7 @@ static void add_attribute_search_button(const bContext &C, return; } - AttributeSearchData *data = OBJECT_GUARDED_NEW(AttributeSearchData); + AttributeSearchData *data = MEM_new<AttributeSearchData>(__func__); data->object_session_uid = object->id.session_uuid; STRNCPY(data->modifier_name, nmd.modifier.name); STRNCPY(data->socket_identifier, socket.identifier); diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index 4e808120f4a..6b79c9e0f68 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -66,31 +66,55 @@ struct SingleInputValue { void *value = nullptr; }; -struct MultiInputValueItem { +struct MultiInputValue { /** - * The socket where this value is coming from. This is required to sort the inputs correctly - * based on the link order later on. + * Ordered sockets connected to this multi-input. */ - DSocket origin; + Vector<DSocket> origins; /** - * Should only be null directly after construction. After that it should always point to a value - * of the correct type. + * A value for every origin socket. The order is determined by #origins. + * Note, the same origin can occur multiple times. However, it is guaranteed that values coming + * from the same origin have the same value (the pointer is different, but they point to values + * that would compare equal). */ - void *value = nullptr; -}; - -struct MultiInputValue { + Vector<void *> values; /** - * Collection of all the inputs that have been provided already. Note, the same origin can occur - * multiple times. However, it is guaranteed that if two items have the same origin, they will - * also have the same value (the pointer is different, but they point to values that would - * compare equal). + * Number of non-null values. */ - Vector<MultiInputValueItem> items; - /** - * Number of items that need to be added until all inputs have been provided. - */ - int expected_size = 0; + int provided_value_count = 0; + + bool all_values_available() const + { + return this->missing_values() == 0; + } + + int missing_values() const + { + return this->values.size() - this->provided_value_count; + } + + void add_value(const DSocket origin, void *value) + { + const int index = this->find_available_index(origin); + this->values[index] = value; + this->provided_value_count++; + } + + private: + int find_available_index(DSocket origin) const + { + for (const int i : origins.index_range()) { + if (values[i] != nullptr) { + continue; + } + if (origins[i] != origin) { + continue; + } + return i; + } + BLI_assert_unreachable(); + return -1; + } }; struct InputState { @@ -211,9 +235,10 @@ struct NodeState { MutableSpan<OutputState> outputs; /** - * Nodes that don't support laziness have some special handling the first time they are executed. + * Most nodes have inputs that are always required. Those have special handling to avoid an extra + * call to the node execution function. */ - bool non_lazy_node_is_initialized = false; + bool non_lazy_inputs_handled = false; /** * Used to check that nodes that don't support laziness do not run more than once. @@ -556,13 +581,14 @@ class GeometryNodesEvaluator { /* Construct the correct struct that can hold the input(s). */ if (socket->is_multi_input_socket()) { input_state.value.multi = allocator.construct<MultiInputValue>().release(); + MultiInputValue &multi_value = *input_state.value.multi; /* Count how many values should be added until the socket is complete. */ - socket.foreach_origin_socket( - [&](DSocket UNUSED(origin)) { input_state.value.multi->expected_size++; }); + socket.foreach_origin_socket([&](DSocket origin) { multi_value.origins.append(origin); }); /* If no links are connected, we do read the value from socket itself. */ - if (input_state.value.multi->expected_size == 0) { - input_state.value.multi->expected_size = 1; + if (multi_value.origins.is_empty()) { + multi_value.origins.append(socket); } + multi_value.values.resize(multi_value.origins.size(), nullptr); } else { input_state.value.single = allocator.construct<SingleInputValue>().release(); @@ -623,8 +649,10 @@ class GeometryNodesEvaluator { const InputSocketRef &socket_ref = node->input(i); if (socket_ref.is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; - for (MultiInputValueItem &item : multi_value.items) { - input_state.type->destruct(item.value); + for (void *value : multi_value.values) { + if (value != nullptr) { + input_state.type->destruct(value); + } } multi_value.~MultiInputValue(); } @@ -774,12 +802,12 @@ class GeometryNodesEvaluator { if (!this->prepare_node_outputs_for_execution(locked_node)) { return; } - /* Initialize nodes that don't support laziness. This is done after at least one output is + /* Initialize inputs that don't support laziness. This is done after at least one output is * required and before we check that all required inputs are provided. This reduces the * number of "round-trips" through the task pool by one for most nodes. */ - if (!node_state.non_lazy_node_is_initialized && !node_supports_laziness(node)) { - this->initialize_non_lazy_node(locked_node); - node_state.non_lazy_node_is_initialized = true; + if (!node_state.non_lazy_inputs_handled) { + this->require_non_lazy_inputs(locked_node); + node_state.non_lazy_inputs_handled = true; } /* Prepare inputs and check if all required inputs are provided. */ if (!this->prepare_node_inputs_for_execution(locked_node)) { @@ -853,17 +881,27 @@ class GeometryNodesEvaluator { return execution_is_necessary; } - void initialize_non_lazy_node(LockedNode &locked_node) + void require_non_lazy_inputs(LockedNode &locked_node) { + this->foreach_non_lazy_input(locked_node, [&](const DInputSocket socket) { + this->set_input_required(locked_node, socket); + }); + } + + void foreach_non_lazy_input(LockedNode &locked_node, FunctionRef<void(DInputSocket socket)> fn) + { + if (node_supports_laziness(locked_node.node)) { + /* In the future only some of the inputs may support lazyness. */ + return; + } + /* Nodes that don't support laziness require all inputs. */ for (const int i : locked_node.node->inputs().index_range()) { InputState &input_state = locked_node.node_state.inputs[i]; if (input_state.type == nullptr) { /* Ignore unavailable/non-data sockets. */ continue; } - /* Nodes that don't support laziness require all inputs. */ - const DInputSocket input_socket = locked_node.node.input(i); - this->set_input_required(locked_node, input_socket); + fn(locked_node.node.input(i)); } } @@ -892,7 +930,7 @@ class GeometryNodesEvaluator { if (socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; /* Checks if all the linked sockets have been provided already. */ - if (multi_value.items.size() == multi_value.expected_size) { + if (multi_value.all_values_available()) { input_state.was_ready_for_execution = true; } else if (is_required) { @@ -1243,7 +1281,7 @@ class GeometryNodesEvaluator { int missing_values = 0; if (input_socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; - missing_values = multi_value.expected_size - multi_value.items.size(); + missing_values = multi_value.missing_values(); } else { SingleInputValue &single_value = *input_state.value.single; @@ -1501,10 +1539,10 @@ class GeometryNodesEvaluator { if (socket->is_multi_input_socket()) { /* Add a new value to the multi-input. */ MultiInputValue &multi_value = *input_state.value.multi; - multi_value.items.append({origin, value.get()}); + multi_value.add_value(origin, value.get()); - if (multi_value.expected_size == multi_value.items.size()) { - this->log_socket_value({socket}, input_state, multi_value.items); + if (multi_value.all_values_available()) { + this->log_socket_value({socket}, input_state, multi_value.values); } } else { @@ -1543,9 +1581,9 @@ class GeometryNodesEvaluator { GMutablePointer value = this->get_value_from_socket(origin_socket, *input_state.type); if (input_socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; - multi_value.items.append({origin_socket, value.get()}); - if (multi_value.expected_size == multi_value.items.size()) { - this->log_socket_value({input_socket}, input_state, multi_value.items); + multi_value.add_value(origin_socket, value.get()); + if (multi_value.all_values_available()) { + this->log_socket_value({input_socket}, input_state, multi_value.values); } } else { @@ -1568,10 +1606,13 @@ class GeometryNodesEvaluator { InputState &input_state = locked_node.node_state.inputs[socket->index()]; if (socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; - for (MultiInputValueItem &item : multi_value.items) { - input_state.type->destruct(item.value); + for (void *&value : multi_value.values) { + if (value != nullptr) { + input_state.type->destruct(value); + value = nullptr; + } } - multi_value.items.clear(); + multi_value.provided_value_count = 0; } else { SingleInputValue &single_value = *input_state.value.single; @@ -1653,7 +1694,7 @@ class GeometryNodesEvaluator { return *node_states_.lookup_key_as(node).state; } - void log_socket_value(DSocket socket, InputState &input_state, Span<MultiInputValueItem> values) + void log_socket_value(DSocket socket, InputState &input_state, Span<void *> values) { if (params_.geo_logger == nullptr) { return; @@ -1662,8 +1703,8 @@ class GeometryNodesEvaluator { Vector<GPointer, 16> value_pointers; value_pointers.reserve(values.size()); const CPPType &type = *input_state.type; - for (const MultiInputValueItem &item : values) { - value_pointers.append({type, item.value}); + for (const void *value : values) { + value_pointers.append({type, value}); } params_.geo_logger->local().log_multi_value_socket(socket, value_pointers); } @@ -1749,7 +1790,7 @@ bool NodeParamsProvider::can_get_input(StringRef identifier) const if (socket->is_multi_input_socket()) { MultiInputValue &multi_value = *input_state.value.multi; - return multi_value.items.size() == multi_value.expected_size; + return multi_value.all_values_available(); } SingleInputValue &single_value = *input_state.value.single; return single_value.value != nullptr; @@ -1789,25 +1830,11 @@ Vector<GMutablePointer> NodeParamsProvider::extract_multi_input(StringRef identi MultiInputValue &multi_value = *input_state.value.multi; Vector<GMutablePointer> ret_values; - socket.foreach_origin_socket([&](DSocket origin) { - for (MultiInputValueItem &item : multi_value.items) { - if (item.origin == origin && item.value != nullptr) { - ret_values.append({*input_state.type, item.value}); - /* Make sure we do not use the same value again if two values have the same origin. */ - item.value = nullptr; - return; - } - } - BLI_assert_unreachable(); - }); - if (ret_values.is_empty()) { - /* If the socket is not linked, we just use the value from the socket itself. */ - BLI_assert(multi_value.items.size() == 1); - MultiInputValueItem &item = multi_value.items[0]; - BLI_assert(item.origin == socket); - ret_values.append({*input_state.type, item.value}); - } - multi_value.items.clear(); + for (void *&value : multi_value.values) { + BLI_assert(value != nullptr); + ret_values.append({*input_state.type, value}); + value = nullptr; + } return ret_values; } diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c index 7470f2abb15..00870d076ef 100644 --- a/source/blender/modifiers/intern/MOD_subsurf.c +++ b/source/blender/modifiers/intern/MOD_subsurf.c @@ -39,6 +39,7 @@ #include "DNA_screen_types.h" #include "BKE_context.h" +#include "BKE_editmesh.h" #include "BKE_mesh.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -46,6 +47,7 @@ #include "BKE_subdiv_ccg.h" #include "BKE_subdiv_deform.h" #include "BKE_subdiv_mesh.h" +#include "BKE_subdiv_modifier.h" #include "BKE_subsurf.h" #include "UI_interface.h" @@ -65,11 +67,6 @@ #include "intern/CCGSubSurf.h" -typedef struct SubsurfRuntimeData { - /* Cached subdivision surface descriptor, with topology and settings. */ - struct Subdiv *subdiv; -} SubsurfRuntimeData; - static void initData(ModifierData *md) { SubsurfModifierData *smd = (SubsurfModifierData *)md; @@ -155,37 +152,6 @@ static int subdiv_levels_for_modifier_get(const SubsurfModifierData *smd, return get_render_subsurf_level(&scene->r, requested_levels, use_render_params); } -static void subdiv_settings_init(SubdivSettings *settings, - const SubsurfModifierData *smd, - const ModifierEvalContext *ctx) -{ - const bool use_render_params = (ctx->flag & MOD_APPLY_RENDER); - const int requested_levels = (use_render_params) ? smd->renderLevels : smd->levels; - - settings->is_simple = (smd->subdivType == SUBSURF_TYPE_SIMPLE); - settings->is_adaptive = !(smd->flags & eSubsurfModifierFlag_UseRecursiveSubdivision); - settings->level = settings->is_simple ? - 1 : - (settings->is_adaptive ? smd->quality : requested_levels); - settings->use_creases = (smd->flags & eSubsurfModifierFlag_UseCrease); - settings->vtx_boundary_interpolation = BKE_subdiv_vtx_boundary_interpolation_from_subsurf( - smd->boundary_smooth); - settings->fvar_linear_interpolation = BKE_subdiv_fvar_interpolation_from_uv_smooth( - smd->uv_smooth); -} - -/* Main goal of this function is to give usable subdivision surface descriptor - * which matches settings and topology. */ -static Subdiv *subdiv_descriptor_ensure(SubsurfModifierData *smd, - const SubdivSettings *subdiv_settings, - const Mesh *mesh) -{ - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; - Subdiv *subdiv = BKE_subdiv_update_from_mesh(runtime_data->subdiv, subdiv_settings, mesh); - runtime_data->subdiv = subdiv; - return subdiv; -} - /* Subdivide into fully qualified mesh. */ static void subdiv_mesh_settings_init(SubdivToMeshSettings *settings, @@ -240,14 +206,17 @@ static Mesh *subdiv_as_ccg(SubsurfModifierData *smd, return result; } -static SubsurfRuntimeData *subsurf_ensure_runtime(SubsurfModifierData *smd) +/* Cache settings for lazy CPU evaluation. */ + +static void subdiv_cache_cpu_evaluation_settings(const ModifierEvalContext *ctx, + Mesh *me, + SubsurfModifierData *smd) { - SubsurfRuntimeData *runtime_data = (SubsurfRuntimeData *)smd->modifier.runtime; - if (runtime_data == NULL) { - runtime_data = MEM_callocN(sizeof(*runtime_data), "subsurf runtime"); - smd->modifier.runtime = runtime_data; - } - return runtime_data; + SubdivToMeshSettings mesh_settings; + subdiv_mesh_settings_init(&mesh_settings, smd, ctx); + me->runtime.subsurf_apply_render = (ctx->flag & MOD_APPLY_RENDER) != 0; + me->runtime.subsurf_resolution = mesh_settings.resolution; + me->runtime.subsurf_use_optimal_display = mesh_settings.use_optimal_display; } /* Modifier itself. */ @@ -261,12 +230,30 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * #endif SubsurfModifierData *smd = (SubsurfModifierData *)md; SubdivSettings subdiv_settings; - subdiv_settings_init(&subdiv_settings, smd, ctx); + BKE_subsurf_modifier_subdiv_settings_init( + &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0); if (subdiv_settings.level == 0) { return result; } - SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd); - Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh); + SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); + + /* Delay evaluation to the draw code if possible, provided we do not have to apply the modifier. + */ + if ((ctx->flag & MOD_APPLY_TO_BASE_MESH) == 0) { + Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph); + const bool is_render_mode = (ctx->flag & MOD_APPLY_RENDER) != 0; + /* Same check as in `DRW_mesh_batch_cache_create_requested` to keep both code coherent. */ + const bool is_editmode = (mesh->edit_mesh != NULL) && + (mesh->edit_mesh->mesh_eval_final != NULL); + const int required_mode = BKE_subsurf_modifier_eval_required_mode(is_render_mode, is_editmode); + if (BKE_subsurf_modifier_can_do_gpu_subdiv_ex(scene, ctx->object, smd, required_mode, false)) { + subdiv_cache_cpu_evaluation_settings(ctx, mesh, smd); + return result; + } + } + + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure( + smd, &subdiv_settings, mesh, false); if (subdiv == NULL) { /* Happens on bad topology, but also on empty input mesh. */ return result; @@ -320,12 +307,14 @@ static void deformMatrices(ModifierData *md, SubsurfModifierData *smd = (SubsurfModifierData *)md; SubdivSettings subdiv_settings; - subdiv_settings_init(&subdiv_settings, smd, ctx); + BKE_subsurf_modifier_subdiv_settings_init( + &subdiv_settings, smd, (ctx->flag & MOD_APPLY_RENDER) != 0); if (subdiv_settings.level == 0) { return; } - SubsurfRuntimeData *runtime_data = subsurf_ensure_runtime(smd); - Subdiv *subdiv = subdiv_descriptor_ensure(smd, &subdiv_settings, mesh); + SubsurfRuntimeData *runtime_data = BKE_subsurf_modifier_ensure_runtime(smd); + Subdiv *subdiv = BKE_subsurf_modifier_subdiv_descriptor_ensure( + smd, &subdiv_settings, mesh, false); if (subdiv == NULL) { /* Happens on bad topology, but also on empty input mesh. */ return; diff --git a/source/blender/modifiers/intern/MOD_volume_displace.cc b/source/blender/modifiers/intern/MOD_volume_displace.cc index fcf75040a9a..a1ca29f454c 100644 --- a/source/blender/modifiers/intern/MOD_volume_displace.cc +++ b/source/blender/modifiers/intern/MOD_volume_displace.cc @@ -203,9 +203,10 @@ struct DisplaceGridOp { template<typename GridType> void operator()() { - if constexpr (std::is_same_v<GridType, openvdb::points::PointDataGrid> || - std::is_same_v<GridType, openvdb::StringGrid> || - std::is_same_v<GridType, openvdb::MaskGrid>) { + if constexpr (blender::is_same_any_v<GridType, + openvdb::points::PointDataGrid, + openvdb::StringGrid, + openvdb::MaskGrid>) { /* We don't support displacing these grid types yet. */ return; } diff --git a/source/blender/modifiers/intern/MOD_weld.c b/source/blender/modifiers/intern/MOD_weld.cc index f842bef3298..92207e1fbe6 100644 --- a/source/blender/modifiers/intern/MOD_weld.c +++ b/source/blender/modifiers/intern/MOD_weld.cc @@ -31,14 +31,19 @@ //#define USE_WELD_NORMALS //#define USE_BVHTREEKDOP +#include <algorithm> + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_alloca.h" +#include "BLI_array.hh" #include "BLI_bitmap.h" +#include "BLI_index_range.hh" #include "BLI_kdtree.h" #include "BLI_math.h" +#include "BLI_span.hh" +#include "BLI_vector.hh" #include "BLT_translation.h" @@ -69,127 +74,133 @@ #include "MOD_modifiertypes.h" #include "MOD_ui_common.h" +using blender::Array; +using blender::IndexRange; +using blender::MutableSpan; +using blender::Span; +using blender::Vector; + /* Indicates when the element was not computed. */ -#define OUT_OF_CONTEXT (uint)(-1) +#define OUT_OF_CONTEXT (int)(-1) /* Indicates if the edge or face will be collapsed. */ -#define ELEM_COLLAPSED (uint)(-2) +#define ELEM_COLLAPSED (int)(-2) /* indicates whether an edge or vertex in groups_map will be merged. */ -#define ELEM_MERGED (uint)(-2) +#define ELEM_MERGED (int)(-2) /* Used to indicate a range in an array specifying a group. */ struct WeldGroup { - uint len; - uint ofs; + int len; + int ofs; }; /* Edge groups that will be merged. Final vertices are also indicated. */ struct WeldGroupEdge { struct WeldGroup group; - uint v1; - uint v2; + int v1; + int v2; }; -typedef struct WeldVert { +struct WeldVert { /* Indexes relative to the original Mesh. */ - uint vert_dest; - uint vert_orig; -} WeldVert; + int vert_dest; + int vert_orig; +}; -typedef struct WeldEdge { +struct WeldEdge { union { - uint flag; + int flag; struct { /* Indexes relative to the original Mesh. */ - uint edge_dest; - uint edge_orig; - uint vert_a; - uint vert_b; + int edge_dest; + int edge_orig; + int vert_a; + int vert_b; }; }; -} WeldEdge; +}; -typedef struct WeldLoop { +struct WeldLoop { union { - uint flag; + int flag; struct { /* Indexes relative to the original Mesh. */ - uint vert; - uint edge; - uint loop_orig; - uint loop_skip_to; + int vert; + int edge; + int loop_orig; + int loop_skip_to; }; }; -} WeldLoop; +}; -typedef struct WeldPoly { +struct WeldPoly { union { - uint flag; + int flag; struct { /* Indexes relative to the original Mesh. */ - uint poly_dst; - uint poly_orig; - uint loop_start; - uint loop_end; + int poly_dst; + int poly_orig; + int loop_start; + int loop_end; /* Final Polygon Size. */ - uint len; + int len; /* Group of loops that will be affected. */ struct WeldGroup loops; }; }; -} WeldPoly; +}; -typedef struct WeldMesh { +struct WeldMesh { /* Group of vertices to be merged. */ - struct WeldGroup *vert_groups; - uint *vert_groups_buffer; + Array<WeldGroup> vert_groups; + Array<int> vert_groups_buffer; /* Group of edges to be merged. */ - struct WeldGroupEdge *edge_groups; - uint *edge_groups_buffer; + Array<WeldGroupEdge> edge_groups; + Array<int> edge_groups_buffer; /* From the original index of the vertex, this indicates which group it is or is going to be * merged. */ - uint *edge_groups_map; + Array<int> edge_groups_map; /* References all polygons and loops that will be affected. */ - WeldLoop *wloop; - WeldPoly *wpoly; + Vector<WeldLoop> wloop; + Vector<WeldPoly> wpoly; WeldPoly *wpoly_new; - uint wloop_len; - uint wpoly_len; - uint wpoly_new_len; + int wloop_len; + int wpoly_len; + int wpoly_new_len; /* From the actual index of the element in the mesh, it indicates what is the index of the Weld * element above. */ - uint *loop_map; - uint *poly_map; + Array<int> loop_map; + Array<int> poly_map; - uint vert_kill_len; - uint edge_kill_len; - uint loop_kill_len; - uint poly_kill_len; /* Including the new polygons. */ + int vert_kill_len; + int edge_kill_len; + int loop_kill_len; + int poly_kill_len; /* Including the new polygons. */ /* Size of the affected polygon with more sides. */ - uint max_poly_len; -} WeldMesh; - -typedef struct WeldLoopOfPolyIter { - uint loop_start; - uint loop_end; - const WeldLoop *wloop; - const MLoop *mloop; - const uint *loop_map; + int max_poly_len; +}; + +struct WeldLoopOfPolyIter { + int loop_start; + int loop_end; + Span<WeldLoop> wloop; + Span<MLoop> mloop; + Span<int> loop_map; /* Weld group. */ - uint *group; + int *group; - uint l_curr; - uint l_next; + int l_curr; + int l_next; /* Return */ - uint group_len; - uint v; - uint e; + int group_len; + int v; + int e; char type; -} WeldLoopOfPolyIter; +}; /* -------------------------------------------------------------------- */ /** \name Debug Utils @@ -197,22 +208,20 @@ typedef struct WeldLoopOfPolyIter { #ifdef USE_WELD_DEBUG static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, - const WeldPoly *wp, - const WeldLoop *wloop, - const MLoop *mloop, - const uint *loop_map, - uint *group_buffer); + const WeldPoly &wp, + Span<WeldLoop> wloop, + Span<MLoop> mloop, + Span<int> loop_map, + int *group_buffer); static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter); -static void weld_assert_edge_kill_len(const WeldEdge *wedge, - const uint wedge_len, - const uint supposed_kill_len) +static void weld_assert_edge_kill_len(Span<WeldEdge> wedge, const int supposed_kill_len) { - uint kills = 0; + int kills = 0; const WeldEdge *we = &wedge[0]; - for (uint i = wedge_len; i--; we++) { - uint edge_dest = we->edge_dest; + for (int i = wedge.size(); i--; we++) { + int edge_dest = we->edge_dest; /* Magically includes collapsed edges. */ if (edge_dest != OUT_OF_CONTEXT) { kills++; @@ -221,28 +230,25 @@ static void weld_assert_edge_kill_len(const WeldEdge *wedge, BLI_assert(kills == supposed_kill_len); } -static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly, - const WeldPoly *wpoly_new, - const uint wpoly_new_len, - const WeldLoop *wloop, - const MLoop *mloop, - const uint *loop_map, - const uint *poly_map, - const MPoly *mpoly, - const uint mpoly_len, - const uint mloop_len, - const uint supposed_poly_kill_len, - const uint supposed_loop_kill_len) +static void weld_assert_poly_and_loop_kill_len(Span<WeldPoly> wpoly, + Span<WeldPoly> wpoly_new, + Span<WeldLoop> wloop, + Span<MLoop> mloop, + Span<int> loop_map, + Span<int> poly_map, + Span<MPoly> mpoly, + const int supposed_poly_kill_len, + const int supposed_loop_kill_len) { - uint poly_kills = 0; - uint loop_kills = mloop_len; + int poly_kills = 0; + int loop_kills = mloop.size(); const MPoly *mp = &mpoly[0]; - for (uint i = 0; i < mpoly_len; i++, mp++) { - uint poly_ctx = poly_map[i]; + for (int i = 0; i < mpoly.size(); i++, mp++) { + int poly_ctx = poly_map[i]; if (poly_ctx != OUT_OF_CONTEXT) { const WeldPoly *wp = &wpoly[poly_ctx]; WeldLoopOfPolyIter iter; - if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + if (!weld_iter_loop_of_poly_begin(&iter, *wp, wloop, mloop, loop_map, nullptr)) { poly_kills++; continue; } @@ -251,11 +257,11 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly, poly_kills++; continue; } - uint remain = wp->len; - uint l = wp->loop_start; + int remain = wp->len; + int l = wp->loop_start; while (remain) { - uint l_next = l + 1; - uint loop_ctx = loop_map[l]; + int l_next = l + 1; + int loop_ctx = loop_map[l]; if (loop_ctx != OUT_OF_CONTEXT) { const WeldLoop *wl = &wloop[loop_ctx]; if (wl->loop_skip_to != OUT_OF_CONTEXT) { @@ -279,17 +285,17 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly, } } - const WeldPoly *wp = &wpoly_new[0]; - for (uint i = wpoly_new_len; i--; wp++) { + const WeldPoly *wp = wpoly_new.data(); + for (int i = wpoly_new.size(); i--; wp++) { if (wp->poly_dst != OUT_OF_CONTEXT) { poly_kills++; continue; } - uint remain = wp->len; - uint l = wp->loop_start; + int remain = wp->len; + int l = wp->loop_start; while (remain) { - uint l_next = l + 1; - uint loop_ctx = loop_map[l]; + int l_next = l + 1; + int loop_ctx = loop_map[l]; if (loop_ctx != OUT_OF_CONTEXT) { const WeldLoop *wl = &wloop[loop_ctx]; if (wl->loop_skip_to != OUT_OF_CONTEXT) { @@ -312,46 +318,46 @@ static void weld_assert_poly_and_loop_kill_len(const WeldPoly *wpoly, BLI_assert(loop_kills == supposed_loop_kill_len); } -static void weld_assert_poly_no_vert_repetition(const WeldPoly *wp, - const WeldLoop *wloop, - const MLoop *mloop, - const uint *loop_map) +static void weld_assert_poly_no_vert_repetition(const WeldPoly &wp, + Span<WeldLoop> wloop, + Span<MLoop> mloop, + Span<int> loop_map) { - const uint len = wp->len; - uint *verts = BLI_array_alloca(verts, len); + const int len = wp.len; + Array<int, 64> verts(len); WeldLoopOfPolyIter iter; - if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + if (!weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) { return; } else { - uint i = 0; + int i = 0; while (weld_iter_loop_of_poly_next(&iter)) { verts[i++] = iter.v; } } - for (uint i = 0; i < len; i++) { - uint va = verts[i]; - for (uint j = i + 1; j < len; j++) { - uint vb = verts[j]; + for (int i = 0; i < len; i++) { + int va = verts[i]; + for (int j = i + 1; j < len; j++) { + int vb = verts[j]; BLI_assert(va != vb); } } } -static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop) +static void weld_assert_poly_len(const WeldPoly *wp, const Span<WeldLoop> wloop) { if (wp->flag == ELEM_COLLAPSED) { return; } - uint len = wp->len; + int len = wp->len; const WeldLoop *wl = &wloop[wp->loops.ofs]; BLI_assert(wp->loop_start <= wl->loop_orig); - uint end_wloop = wp->loops.ofs + wp->loops.len; + int end_wloop = wp->loops.ofs + wp->loops.len; const WeldLoop *wl_end = &wloop[end_wloop - 1]; - uint min_len = 0; + int min_len = 0; for (; wl <= wl_end; wl++) { BLI_assert(wl->loop_skip_to == OUT_OF_CONTEXT); /* Not for this case. */ if (wl->flag != ELEM_COLLAPSED) { @@ -360,7 +366,7 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop) } BLI_assert(len >= min_len); - uint max_len = wp->loop_end - wp->loop_start + 1; + int max_len = wp->loop_end - wp->loop_start + 1; BLI_assert(len <= max_len); } @@ -372,92 +378,71 @@ static void weld_assert_poly_len(const WeldPoly *wp, const WeldLoop *wloop) /** \name Weld Vert API * \{ */ -static void weld_vert_ctx_alloc_and_setup(const uint mvert_len, - uint *r_vert_dest_map, - WeldVert **r_wvert, - uint *r_wvert_len) +static Vector<WeldVert> weld_vert_ctx_alloc_and_setup(Span<int> vert_dest_map, + const int vert_kill_len) { - /* Vert Context. */ - uint wvert_len = 0; - - WeldVert *wvert, *wv; - wvert = MEM_mallocN(sizeof(*wvert) * mvert_len, __func__); - wv = &wvert[0]; - - uint *v_dest_iter = &r_vert_dest_map[0]; - for (uint i = 0; i < mvert_len; i++, v_dest_iter++) { - if (*v_dest_iter != OUT_OF_CONTEXT) { - wv->vert_dest = *v_dest_iter; - wv->vert_orig = i; - wv++; - wvert_len++; + Vector<WeldVert> wvert; + wvert.reserve(std::min<int>(2 * vert_kill_len, vert_dest_map.size())); + + for (const int i : vert_dest_map.index_range()) { + if (vert_dest_map[i] != OUT_OF_CONTEXT) { + wvert.append({vert_dest_map[i], i}); } } - - *r_wvert = MEM_reallocN(wvert, sizeof(*wvert) * wvert_len); - *r_wvert_len = wvert_len; + return wvert; } -static void weld_vert_groups_setup(const uint mvert_len, - const uint wvert_len, - const WeldVert *wvert, - const uint *vert_dest_map, - uint *r_vert_groups_map, - uint **r_vert_groups_buffer, - struct WeldGroup **r_vert_groups) +static void weld_vert_groups_setup(Span<WeldVert> wvert, + Span<int> vert_dest_map, + MutableSpan<int> r_vert_groups_map, + Array<int> &r_vert_groups_buffer, + Array<WeldGroup> &r_vert_groups) { /* Get weld vert groups. */ - uint wgroups_len = 0; - const uint *vert_dest_iter = &vert_dest_map[0]; - uint *group_map_iter = &r_vert_groups_map[0]; - for (uint i = 0; i < mvert_len; i++, group_map_iter++, vert_dest_iter++) { - uint vert_dest = *vert_dest_iter; + int wgroups_len = 0; + for (const int i : vert_dest_map.index_range()) { + const int vert_dest = vert_dest_map[i]; if (vert_dest != OUT_OF_CONTEXT) { if (vert_dest != i) { - *group_map_iter = ELEM_MERGED; + r_vert_groups_map[i] = ELEM_MERGED; } else { - *group_map_iter = wgroups_len; + r_vert_groups_map[i] = wgroups_len; wgroups_len++; } } else { - *group_map_iter = OUT_OF_CONTEXT; + r_vert_groups_map[i] = OUT_OF_CONTEXT; } } - struct WeldGroup *wgroups = MEM_callocN(sizeof(*wgroups) * wgroups_len, __func__); + r_vert_groups.reinitialize(wgroups_len); + r_vert_groups.fill({0, 0}); + MutableSpan<WeldGroup> wgroups = r_vert_groups; - const WeldVert *wv = &wvert[0]; - for (uint i = wvert_len; i--; wv++) { - uint group_index = r_vert_groups_map[wv->vert_dest]; + for (const WeldVert &wv : wvert) { + int group_index = r_vert_groups_map[wv.vert_dest]; wgroups[group_index].len++; } - uint ofs = 0; - struct WeldGroup *wg_iter = &wgroups[0]; - for (uint i = wgroups_len; i--; wg_iter++) { - wg_iter->ofs = ofs; - ofs += wg_iter->len; + int ofs = 0; + for (WeldGroup &wg : wgroups) { + wg.ofs = ofs; + ofs += wg.len; } - BLI_assert(ofs == wvert_len); + BLI_assert(ofs == wvert.size()); - uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__); - wv = &wvert[0]; - for (uint i = wvert_len; i--; wv++) { - uint group_index = r_vert_groups_map[wv->vert_dest]; - groups_buffer[wgroups[group_index].ofs++] = wv->vert_orig; + r_vert_groups_buffer.reinitialize(ofs); + for (const WeldVert &wv : wvert) { + int group_index = r_vert_groups_map[wv.vert_dest]; + r_vert_groups_buffer[wgroups[group_index].ofs++] = wv.vert_orig; } - wg_iter = &wgroups[0]; - for (uint i = wgroups_len; i--; wg_iter++) { - wg_iter->ofs -= wg_iter->len; + for (WeldGroup &wg : wgroups) { + wg.ofs -= wg.len; } - - *r_vert_groups = wgroups; - *r_vert_groups_buffer = groups_buffer; } /** \} */ @@ -466,31 +451,24 @@ static void weld_vert_groups_setup(const uint mvert_len, /** \name Weld Edge API * \{ */ -static void weld_edge_ctx_setup(const uint mvert_len, - const uint wedge_len, - struct WeldGroup *r_vlinks, - uint *r_edge_dest_map, - WeldEdge *r_wedge, - uint *r_edge_kiil_len) +static void weld_edge_ctx_setup(MutableSpan<WeldGroup> r_vlinks, + MutableSpan<int> r_edge_dest_map, + MutableSpan<WeldEdge> r_wedge, + int *r_edge_kiil_len) { - WeldEdge *we; - /* Setup Edge Overlap. */ - uint edge_kill_len = 0; + int edge_kill_len = 0; - struct WeldGroup *vl_iter, *v_links; - v_links = r_vlinks; - vl_iter = &v_links[0]; + MutableSpan<WeldGroup> v_links = r_vlinks; - we = &r_wedge[0]; - for (uint i = wedge_len; i--; we++) { - uint dst_vert_a = we->vert_a; - uint dst_vert_b = we->vert_b; + for (WeldEdge &we : r_wedge) { + int dst_vert_a = we.vert_a; + int dst_vert_b = we.vert_b; if (dst_vert_a == dst_vert_b) { - BLI_assert(we->edge_dest == OUT_OF_CONTEXT); - r_edge_dest_map[we->edge_orig] = ELEM_COLLAPSED; - we->flag = ELEM_COLLAPSED; + BLI_assert(we.edge_dest == OUT_OF_CONTEXT); + r_edge_dest_map[we.edge_orig] = ELEM_COLLAPSED; + we.flag = ELEM_COLLAPSED; edge_kill_len++; continue; } @@ -499,62 +477,60 @@ static void weld_edge_ctx_setup(const uint mvert_len, v_links[dst_vert_b].len++; } - uint link_len = 0; - vl_iter = &v_links[0]; - for (uint i = mvert_len; i--; vl_iter++) { - vl_iter->ofs = link_len; - link_len += vl_iter->len; + int link_len = 0; + for (WeldGroup &vl : r_vlinks) { + vl.ofs = link_len; + link_len += vl.len; } - if (link_len) { - uint *link_edge_buffer = MEM_mallocN(sizeof(*link_edge_buffer) * link_len, __func__); + if (link_len > 0) { + Array<int> link_edge_buffer(link_len); - we = &r_wedge[0]; - for (uint i = 0; i < wedge_len; i++, we++) { - if (we->flag == ELEM_COLLAPSED) { + for (const int i : r_wedge.index_range()) { + const WeldEdge &we = r_wedge[i]; + if (we.flag == ELEM_COLLAPSED) { continue; } - uint dst_vert_a = we->vert_a; - uint dst_vert_b = we->vert_b; + int dst_vert_a = we.vert_a; + int dst_vert_b = we.vert_b; link_edge_buffer[v_links[dst_vert_a].ofs++] = i; link_edge_buffer[v_links[dst_vert_b].ofs++] = i; } - vl_iter = &v_links[0]; - for (uint i = mvert_len; i--; vl_iter++) { + for (WeldGroup &vl : r_vlinks) { /* Fix offset */ - vl_iter->ofs -= vl_iter->len; + vl.ofs -= vl.len; } - we = &r_wedge[0]; - for (uint i = 0; i < wedge_len; i++, we++) { - if (we->edge_dest != OUT_OF_CONTEXT) { + for (const int i : r_wedge.index_range()) { + const WeldEdge &we = r_wedge[i]; + if (we.edge_dest != OUT_OF_CONTEXT) { /* No need to retest edges. * (Already includes collapsed edges). */ continue; } - uint dst_vert_a = we->vert_a; - uint dst_vert_b = we->vert_b; + int dst_vert_a = we.vert_a; + int dst_vert_b = we.vert_b; struct WeldGroup *link_a = &v_links[dst_vert_a]; struct WeldGroup *link_b = &v_links[dst_vert_b]; - uint edges_len_a = link_a->len; - uint edges_len_b = link_b->len; + int edges_len_a = link_a->len; + int edges_len_b = link_b->len; if (edges_len_a <= 1 || edges_len_b <= 1) { continue; } - uint *edges_ctx_a = &link_edge_buffer[link_a->ofs]; - uint *edges_ctx_b = &link_edge_buffer[link_b->ofs]; - uint edge_orig = we->edge_orig; + int *edges_ctx_a = &link_edge_buffer[link_a->ofs]; + int *edges_ctx_b = &link_edge_buffer[link_b->ofs]; + int edge_orig = we.edge_orig; for (; edges_len_a--; edges_ctx_a++) { - uint e_ctx_a = *edges_ctx_a; + int e_ctx_a = *edges_ctx_a; if (e_ctx_a == i) { continue; } @@ -565,7 +541,7 @@ static void weld_edge_ctx_setup(const uint mvert_len, if (edges_len_b == 0) { break; } - uint e_ctx_b = *edges_ctx_b; + int e_ctx_b = *edges_ctx_b; if (e_ctx_a == e_ctx_b) { WeldEdge *we_b = &r_wedge[e_ctx_b]; BLI_assert(ELEM(we_b->vert_a, dst_vert_a, dst_vert_b)); @@ -580,138 +556,118 @@ static void weld_edge_ctx_setup(const uint mvert_len, } #ifdef USE_WELD_DEBUG - weld_assert_edge_kill_len(r_wedge, wedge_len, edge_kill_len); + weld_assert_edge_kill_len(r_wedge, edge_kill_len); #endif - - MEM_freeN(link_edge_buffer); } *r_edge_kiil_len = edge_kill_len; } -static void weld_edge_ctx_alloc(const MEdge *medge, - const uint medge_len, - const uint *vert_dest_map, - uint *r_edge_dest_map, - uint **r_edge_ctx_map, - WeldEdge **r_wedge, - uint *r_wedge_len) +static Vector<WeldEdge> weld_edge_ctx_alloc(Span<MEdge> medge, + Span<int> vert_dest_map, + MutableSpan<int> r_edge_dest_map, + MutableSpan<int> r_edge_ctx_map) { /* Edge Context. */ - uint *edge_map = MEM_mallocN(sizeof(*edge_map) * medge_len, __func__); - uint wedge_len = 0; - - WeldEdge *wedge, *we; - wedge = MEM_mallocN(sizeof(*wedge) * medge_len, __func__); - we = &wedge[0]; - - const MEdge *me = &medge[0]; - uint *e_dest_iter = &r_edge_dest_map[0]; - uint *iter = &edge_map[0]; - for (uint i = 0; i < medge_len; i++, me++, iter++, e_dest_iter++) { - uint v1 = me->v1; - uint v2 = me->v2; - uint v_dest_1 = vert_dest_map[v1]; - uint v_dest_2 = vert_dest_map[v2]; + int wedge_len = 0; + + Vector<WeldEdge> wedge; + wedge.reserve(medge.size()); + + for (const int i : medge.index_range()) { + int v1 = medge[i].v1; + int v2 = medge[i].v2; + int v_dest_1 = vert_dest_map[v1]; + int v_dest_2 = vert_dest_map[v2]; if ((v_dest_1 != OUT_OF_CONTEXT) || (v_dest_2 != OUT_OF_CONTEXT)) { - we->vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1; - we->vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2; - we->edge_dest = OUT_OF_CONTEXT; - we->edge_orig = i; - we++; - *e_dest_iter = i; - *iter = wedge_len++; + WeldEdge we{}; + we.vert_a = (v_dest_1 != OUT_OF_CONTEXT) ? v_dest_1 : v1; + we.vert_b = (v_dest_2 != OUT_OF_CONTEXT) ? v_dest_2 : v2; + we.edge_dest = OUT_OF_CONTEXT; + we.edge_orig = i; + wedge.append(we); + r_edge_dest_map[i] = i; + r_edge_ctx_map[i] = wedge_len++; } else { - *e_dest_iter = OUT_OF_CONTEXT; - *iter = OUT_OF_CONTEXT; + r_edge_dest_map[i] = OUT_OF_CONTEXT; + r_edge_ctx_map[i] = OUT_OF_CONTEXT; } } - *r_wedge = MEM_reallocN(wedge, sizeof(*wedge) * wedge_len); - *r_wedge_len = wedge_len; - *r_edge_ctx_map = edge_map; + return wedge; } -static void weld_edge_groups_setup(const uint medge_len, - const uint edge_kill_len, - const uint wedge_len, - WeldEdge *wedge, - const uint *wedge_map, - uint *r_edge_groups_map, - uint **r_edge_groups_buffer, - struct WeldGroupEdge **r_edge_groups) +static void weld_edge_groups_setup(const int medge_len, + const int edge_kill_len, + MutableSpan<WeldEdge> wedge, + Span<int> wedge_map, + MutableSpan<int> r_edge_groups_map, + Array<int> &r_edge_groups_buffer, + Array<WeldGroupEdge> &r_edge_groups) { - /* Get weld edge groups. */ - struct WeldGroupEdge *wegroups, *wegrp_iter; + struct WeldGroupEdge *wegrp_iter; - uint wgroups_len = wedge_len - edge_kill_len; - wegroups = MEM_callocN(sizeof(*wegroups) * wgroups_len, __func__); - wegrp_iter = &wegroups[0]; + int wgroups_len = wedge.size() - edge_kill_len; + r_edge_groups.reinitialize(wgroups_len); + r_edge_groups.fill({0}); + MutableSpan<WeldGroupEdge> wegroups = r_edge_groups; + wegrp_iter = &r_edge_groups[0]; wgroups_len = 0; - const uint *edge_ctx_iter = &wedge_map[0]; - uint *group_map_iter = &r_edge_groups_map[0]; - for (uint i = medge_len; i--; edge_ctx_iter++, group_map_iter++) { - uint edge_ctx = *edge_ctx_iter; + for (const int i : IndexRange(medge_len)) { + int edge_ctx = wedge_map[i]; if (edge_ctx != OUT_OF_CONTEXT) { WeldEdge *we = &wedge[edge_ctx]; - uint edge_dest = we->edge_dest; + int edge_dest = we->edge_dest; if (edge_dest != OUT_OF_CONTEXT) { BLI_assert(edge_dest != we->edge_orig); - *group_map_iter = ELEM_MERGED; + r_edge_groups_map[i] = ELEM_MERGED; } else { we->edge_dest = we->edge_orig; wegrp_iter->v1 = we->vert_a; wegrp_iter->v2 = we->vert_b; - *group_map_iter = wgroups_len; + r_edge_groups_map[i] = wgroups_len; wgroups_len++; wegrp_iter++; } } else { - *group_map_iter = OUT_OF_CONTEXT; + r_edge_groups_map[i] = OUT_OF_CONTEXT; } } - BLI_assert(wgroups_len == wedge_len - edge_kill_len); + BLI_assert(wgroups_len == wedge.size() - edge_kill_len); - WeldEdge *we = &wedge[0]; - for (uint i = wedge_len; i--; we++) { - if (we->flag == ELEM_COLLAPSED) { + for (const WeldEdge &we : wedge) { + if (we.flag == ELEM_COLLAPSED) { continue; } - uint group_index = r_edge_groups_map[we->edge_dest]; + int group_index = r_edge_groups_map[we.edge_dest]; wegroups[group_index].group.len++; } - uint ofs = 0; - wegrp_iter = &wegroups[0]; - for (uint i = wgroups_len; i--; wegrp_iter++) { - wegrp_iter->group.ofs = ofs; - ofs += wegrp_iter->group.len; + int ofs = 0; + for (WeldGroupEdge &wegrp : wegroups) { + wegrp.group.ofs = ofs; + ofs += wegrp.group.len; } - uint *groups_buffer = MEM_mallocN(sizeof(*groups_buffer) * ofs, __func__); - we = &wedge[0]; - for (uint i = wedge_len; i--; we++) { - if (we->flag == ELEM_COLLAPSED) { + r_edge_groups_buffer.reinitialize(ofs); + for (const WeldEdge &we : wedge) { + if (we.flag == ELEM_COLLAPSED) { continue; } - uint group_index = r_edge_groups_map[we->edge_dest]; - groups_buffer[wegroups[group_index].group.ofs++] = we->edge_orig; + int group_index = r_edge_groups_map[we.edge_dest]; + r_edge_groups_buffer[wegroups[group_index].group.ofs++] = we.edge_orig; } - wegrp_iter = &wegroups[0]; - for (uint i = wgroups_len; i--; wegrp_iter++) { - wegrp_iter->group.ofs -= wegrp_iter->group.len; + for (WeldGroupEdge &wegrp : wegroups) { + wegrp.group.ofs -= wegrp.group.len; } - - *r_edge_groups_buffer = groups_buffer; - *r_edge_groups = wegroups; } /** \} */ @@ -721,31 +677,31 @@ static void weld_edge_groups_setup(const uint medge_len, * \{ */ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, - const WeldPoly *wp, - const WeldLoop *wloop, - const MLoop *mloop, - const uint *loop_map, - uint *group_buffer) + const WeldPoly &wp, + Span<WeldLoop> wloop, + Span<MLoop> mloop, + Span<int> loop_map, + int *group_buffer) { - if (wp->flag == ELEM_COLLAPSED) { + if (wp.flag == ELEM_COLLAPSED) { return false; } - iter->loop_start = wp->loop_start; - iter->loop_end = wp->loop_end; + iter->loop_start = wp.loop_start; + iter->loop_end = wp.loop_end; iter->wloop = wloop; iter->mloop = mloop; iter->loop_map = loop_map; iter->group = group_buffer; - uint group_len = 0; + int group_len = 0; if (group_buffer) { /* First loop group needs more attention. */ - uint loop_start, loop_end, l; + int loop_start, loop_end, l; loop_start = iter->loop_start; loop_end = l = iter->loop_end; while (l >= loop_start) { - const uint loop_ctx = loop_map[l]; + const int loop_ctx = loop_map[l]; if (loop_ctx != OUT_OF_CONTEXT) { const WeldLoop *wl = &wloop[loop_ctx]; if (wl->flag == ELEM_COLLAPSED) { @@ -774,10 +730,10 @@ static bool weld_iter_loop_of_poly_begin(WeldLoopOfPolyIter *iter, static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) { - uint loop_end = iter->loop_end; - const WeldLoop *wloop = iter->wloop; - const uint *loop_map = iter->loop_map; - uint l = iter->l_curr = iter->l_next; + int loop_end = iter->loop_end; + Span<WeldLoop> wloop = iter->wloop; + Span<int> loop_map = iter->loop_map; + int l = iter->l_curr = iter->l_next; if (l == iter->loop_start) { /* `grupo_len` is already calculated in the first loop */ } @@ -785,8 +741,8 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) iter->group_len = 0; } while (l <= loop_end) { - uint l_next = l + 1; - const uint loop_ctx = loop_map[l]; + int l_next = l + 1; + const int loop_ctx = loop_map[l]; if (loop_ctx != OUT_OF_CONTEXT) { const WeldLoop *wl = &wloop[loop_ctx]; if (wl->loop_skip_to != OUT_OF_CONTEXT) { @@ -809,7 +765,7 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) else { const MLoop *ml = &iter->mloop[l]; #ifdef USE_WELD_DEBUG - BLI_assert(iter->v != ml->v); + BLI_assert((uint)iter->v != ml->v); #endif iter->v = ml->v; iter->e = ml->e; @@ -825,129 +781,119 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter *iter) return false; } -static void weld_poly_loop_ctx_alloc(const MPoly *mpoly, - const uint mpoly_len, - const MLoop *mloop, - const uint mloop_len, - const uint *vert_dest_map, - const uint *edge_dest_map, +static void weld_poly_loop_ctx_alloc(Span<MPoly> mpoly, + Span<MLoop> mloop, + Span<int> vert_dest_map, + Span<int> edge_dest_map, WeldMesh *r_weld_mesh) { /* Loop/Poly Context. */ - uint *loop_map = MEM_mallocN(sizeof(*loop_map) * mloop_len, __func__); - uint *poly_map = MEM_mallocN(sizeof(*poly_map) * mpoly_len, __func__); - uint wloop_len = 0; - uint wpoly_len = 0; - uint max_ctx_poly_len = 4; + Array<int> loop_map(mloop.size()); + Array<int> poly_map(mpoly.size()); + int wloop_len = 0; + int wpoly_len = 0; + int max_ctx_poly_len = 4; - WeldLoop *wloop, *wl; - wloop = MEM_mallocN(sizeof(*wloop) * mloop_len, __func__); - wl = &wloop[0]; + Vector<WeldLoop> wloop; + wloop.reserve(mloop.size()); - WeldPoly *wpoly, *wp; - wpoly = MEM_mallocN(sizeof(*wpoly) * mpoly_len, __func__); - wp = &wpoly[0]; + Vector<WeldPoly> wpoly; + wpoly.reserve(mpoly.size()); - uint maybe_new_poly = 0; + int maybe_new_poly = 0; - const MPoly *mp = &mpoly[0]; - uint *iter = &poly_map[0]; - uint *loop_map_iter = &loop_map[0]; - for (uint i = 0; i < mpoly_len; i++, mp++, iter++) { - const uint loopstart = mp->loopstart; - const uint totloop = mp->totloop; - - uint vert_ctx_len = 0; - - uint l = loopstart; - uint prev_wloop_len = wloop_len; - const MLoop *ml = &mloop[l]; - for (uint j = totloop; j--; l++, ml++, loop_map_iter++) { - uint v = ml->v; - uint e = ml->e; - uint v_dest = vert_dest_map[v]; - uint e_dest = edge_dest_map[e]; + for (const int i : mpoly.index_range()) { + const MPoly &mp = mpoly[i]; + const int loopstart = mp.loopstart; + const int totloop = mp.totloop; + + int vert_ctx_len = 0; + + int prev_wloop_len = wloop_len; + for (const int i_loop : mloop.index_range().slice(loopstart, totloop)) { + int v = mloop[i_loop].v; + int e = mloop[i_loop].e; + int v_dest = vert_dest_map[v]; + int e_dest = edge_dest_map[e]; bool is_vert_ctx = v_dest != OUT_OF_CONTEXT; bool is_edge_ctx = e_dest != OUT_OF_CONTEXT; if (is_vert_ctx) { vert_ctx_len++; } if (is_vert_ctx || is_edge_ctx) { - wl->vert = is_vert_ctx ? v_dest : v; - wl->edge = is_edge_ctx ? e_dest : e; - wl->loop_orig = l; - wl->loop_skip_to = OUT_OF_CONTEXT; - wl++; - - *loop_map_iter = wloop_len++; + WeldLoop wl{}; + wl.vert = is_vert_ctx ? v_dest : v; + wl.edge = is_edge_ctx ? e_dest : e; + wl.loop_orig = i_loop; + wl.loop_skip_to = OUT_OF_CONTEXT; + wloop.append(wl); + + loop_map[i_loop] = wloop_len++; } else { - *loop_map_iter = OUT_OF_CONTEXT; + loop_map[i_loop] = OUT_OF_CONTEXT; } } if (wloop_len != prev_wloop_len) { - uint loops_len = wloop_len - prev_wloop_len; - - wp->poly_dst = OUT_OF_CONTEXT; - wp->poly_orig = i; - wp->loops.len = loops_len; - wp->loops.ofs = prev_wloop_len; - wp->loop_start = loopstart; - wp->loop_end = loopstart + totloop - 1; - wp->len = totloop; - wp++; - - *iter = wpoly_len++; + int loops_len = wloop_len - prev_wloop_len; + WeldPoly wp{}; + wp.poly_dst = OUT_OF_CONTEXT; + wp.poly_orig = i; + wp.loops.len = loops_len; + wp.loops.ofs = prev_wloop_len; + wp.loop_start = loopstart; + wp.loop_end = loopstart + totloop - 1; + wp.len = totloop; + wpoly.append(wp); + + poly_map[i] = wpoly_len++; if (totloop > 5 && vert_ctx_len > 1) { - uint max_new = (totloop / 3) - 1; + int max_new = (totloop / 3) - 1; vert_ctx_len /= 2; maybe_new_poly += MIN2(max_new, vert_ctx_len); CLAMP_MIN(max_ctx_poly_len, totloop); } } else { - *iter = OUT_OF_CONTEXT; + poly_map[i] = OUT_OF_CONTEXT; } } - if (mpoly_len < (wpoly_len + maybe_new_poly)) { - WeldPoly *wpoly_tmp = wpoly; - wpoly = MEM_mallocN(sizeof(*wpoly) * ((size_t)wpoly_len + maybe_new_poly), __func__); - memcpy(wpoly, wpoly_tmp, sizeof(*wpoly) * wpoly_len); - MEM_freeN(wpoly_tmp); + if (mpoly.size() < (wpoly_len + maybe_new_poly)) { + wpoly.resize(wpoly_len + maybe_new_poly); } - WeldPoly *poly_new = &wpoly[wpoly_len]; + WeldPoly *poly_new = wpoly.data() + wpoly_len; - r_weld_mesh->wloop = MEM_reallocN(wloop, sizeof(*wloop) * wloop_len); - r_weld_mesh->wpoly = wpoly; + r_weld_mesh->wloop = std::move(wloop); + r_weld_mesh->wpoly = std::move(wpoly); r_weld_mesh->wpoly_new = poly_new; r_weld_mesh->wloop_len = wloop_len; r_weld_mesh->wpoly_len = wpoly_len; r_weld_mesh->wpoly_new_len = 0; - r_weld_mesh->loop_map = loop_map; - r_weld_mesh->poly_map = poly_map; + r_weld_mesh->loop_map = std::move(loop_map); + r_weld_mesh->poly_map = std::move(poly_map); r_weld_mesh->max_poly_len = max_ctx_poly_len; } -static void weld_poly_split_recursive(const uint *vert_dest_map, +static void weld_poly_split_recursive(Span<int> vert_dest_map, #ifdef USE_WELD_DEBUG - const MLoop *mloop, + const Span<MLoop> mloop, #endif - uint ctx_verts_len, + int ctx_verts_len, WeldPoly *r_wp, WeldMesh *r_weld_mesh, - uint *r_poly_kill, - uint *r_loop_kill) + int *r_poly_kill, + int *r_loop_kill) { - uint poly_len = r_wp->len; + int poly_len = r_wp->len; if (poly_len > 3 && ctx_verts_len > 1) { - const uint ctx_loops_len = r_wp->loops.len; - const uint ctx_loops_ofs = r_wp->loops.ofs; - WeldLoop *wloop = r_weld_mesh->wloop; + const int ctx_loops_len = r_wp->loops.len; + const int ctx_loops_ofs = r_wp->loops.ofs; + MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop; WeldPoly *wpoly_new = r_weld_mesh->wpoly_new; - uint loop_kill = 0; + int loop_kill = 0; WeldLoop *poly_loops = &wloop[ctx_loops_ofs]; WeldLoop *wla = &poly_loops[0]; @@ -955,19 +901,19 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, while (wla_prev->flag == ELEM_COLLAPSED) { wla_prev--; } - const uint la_len = ctx_loops_len - 1; - for (uint la = 0; la < la_len; la++, wla++) { + const int la_len = ctx_loops_len - 1; + for (int la = 0; la < la_len; la++, wla++) { wa_continue: if (wla->flag == ELEM_COLLAPSED) { continue; } - uint vert_a = wla->vert; + int vert_a = wla->vert; /* Only test vertices that will be merged. */ if (vert_dest_map[vert_a] != OUT_OF_CONTEXT) { - uint lb = la + 1; + int lb = la + 1; WeldLoop *wlb = wla + 1; WeldLoop *wlb_prev = wla; - uint killed_ab = 0; + int killed_ab = 0; ctx_verts_len = 1; for (; lb < ctx_loops_len; lb++, wlb++) { BLI_assert(wlb->loop_skip_to == OUT_OF_CONTEXT); @@ -975,13 +921,13 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, killed_ab++; continue; } - uint vert_b = wlb->vert; + int vert_b = wlb->vert; if (vert_dest_map[vert_b] != OUT_OF_CONTEXT) { ctx_verts_len++; } if (vert_a == vert_b) { - const uint dist_a = wlb->loop_orig - wla->loop_orig - killed_ab; - const uint dist_b = poly_len - dist_a; + const int dist_a = wlb->loop_orig - wla->loop_orig - killed_ab; + const int dist_b = poly_len - dist_a; BLI_assert(dist_a != 0 && dist_b != 0); if (dist_a == 1 || dist_b == 1) { @@ -989,7 +935,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, BLI_assert((wla->flag == ELEM_COLLAPSED) || (wlb->flag == ELEM_COLLAPSED)); } else { - WeldLoop *wl_tmp = NULL; + WeldLoop *wl_tmp = nullptr; if (dist_a == 2) { wl_tmp = wlb_prev; BLI_assert(wla->flag != ELEM_COLLAPSED); @@ -1000,7 +946,7 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, poly_len -= 2; } if (dist_b == 2) { - if (wl_tmp != NULL) { + if (wl_tmp != nullptr) { r_wp->flag = ELEM_COLLAPSED; *r_poly_kill += 1; } @@ -1014,9 +960,9 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, loop_kill += 2; poly_len -= 2; } - if (wl_tmp == NULL) { - const uint new_loops_len = lb - la; - const uint new_loops_ofs = ctx_loops_ofs + la; + if (wl_tmp == nullptr) { + const int new_loops_len = lb - la; + const int new_loops_ofs = ctx_loops_ofs + la; WeldPoly *new_wp = &wpoly_new[r_weld_mesh->wpoly_new_len++]; new_wp->poly_dst = OUT_OF_CONTEXT; @@ -1065,56 +1011,53 @@ static void weld_poly_split_recursive(const uint *vert_dest_map, *r_loop_kill += loop_kill; #ifdef USE_WELD_DEBUG - weld_assert_poly_no_vert_repetition(r_wp, wloop, mloop, r_weld_mesh->loop_map); + weld_assert_poly_no_vert_repetition(*r_wp, wloop, mloop, r_weld_mesh->loop_map); #endif } } -static void weld_poly_loop_ctx_setup(const MLoop *mloop, +static void weld_poly_loop_ctx_setup(Span<MLoop> mloop, #ifdef USE_WELD_DEBUG - const MPoly *mpoly, - const uint mpoly_len, - const uint mloop_len, + Span<MPoly> mpoly, #endif - const uint mvert_len, - const uint *vert_dest_map, - const uint remain_edge_ctx_len, - struct WeldGroup *r_vlinks, + const int mvert_len, + Span<int> vert_dest_map, + const int remain_edge_ctx_len, + MutableSpan<WeldGroup> r_vlinks, WeldMesh *r_weld_mesh) { - uint poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len; + int poly_kill_len, loop_kill_len, wpoly_len, wpoly_new_len; - WeldPoly *wpoly_new, *wpoly, *wp; - WeldLoop *wloop, *wl; + WeldPoly *wpoly_new; + WeldLoop *wl; - wpoly = r_weld_mesh->wpoly; - wloop = r_weld_mesh->wloop; + MutableSpan<WeldPoly> wpoly = r_weld_mesh->wpoly; + MutableSpan<WeldLoop> wloop = r_weld_mesh->wloop; wpoly_new = r_weld_mesh->wpoly_new; wpoly_len = r_weld_mesh->wpoly_len; wpoly_new_len = 0; poly_kill_len = 0; loop_kill_len = 0; - const uint *loop_map = r_weld_mesh->loop_map; + Span<int> loop_map = r_weld_mesh->loop_map; if (remain_edge_ctx_len) { - /* Setup Poly/Loop. */ + /* Setup Poly/Loop. Note that `wpoly_len` may be different than `wpoly.size()` here. */ + for (const int i : IndexRange(wpoly_len)) { + WeldPoly &wp = wpoly[i]; + const int ctx_loops_len = wp.loops.len; + const int ctx_loops_ofs = wp.loops.ofs; - wp = &wpoly[0]; - for (uint i = wpoly_len; i--; wp++) { - const uint ctx_loops_len = wp->loops.len; - const uint ctx_loops_ofs = wp->loops.ofs; - - uint poly_len = wp->len; - uint ctx_verts_len = 0; + int poly_len = wp.len; + int ctx_verts_len = 0; wl = &wloop[ctx_loops_ofs]; - for (uint l = ctx_loops_len; l--; wl++) { - const uint edge_dest = wl->edge; + for (int l = ctx_loops_len; l--; wl++) { + const int edge_dest = wl->edge; if (edge_dest == ELEM_COLLAPSED) { wl->flag = ELEM_COLLAPSED; if (poly_len == 3) { - wp->flag = ELEM_COLLAPSED; + wp.flag = ELEM_COLLAPSED; poly_kill_len++; loop_kill_len += 3; poly_len = 0; @@ -1124,7 +1067,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, poly_len--; } else { - const uint vert_dst = wl->vert; + const int vert_dst = wl->vert; if (vert_dest_map[vert_dst] != OUT_OF_CONTEXT) { ctx_verts_len++; } @@ -1132,7 +1075,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, } if (poly_len) { - wp->len = poly_len; + wp.len = poly_len; #ifdef USE_WELD_DEBUG weld_assert_poly_len(wp, wloop); #endif @@ -1142,7 +1085,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, mloop, #endif ctx_verts_len, - wp, + &wp, r_weld_mesh, &poly_kill_len, &loop_kill_len); @@ -1153,75 +1096,70 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, #ifdef USE_WELD_DEBUG weld_assert_poly_and_loop_kill_len(wpoly, - wpoly_new, - wpoly_new_len, + {wpoly_new, wpoly_new_len}, wloop, mloop, loop_map, r_weld_mesh->poly_map, mpoly, - mpoly_len, - mloop_len, poly_kill_len, loop_kill_len); #endif /* Setup Polygon Overlap. */ - uint wpoly_and_new_len = wpoly_len + wpoly_new_len; + int wpoly_and_new_len = wpoly_len + wpoly_new_len; - struct WeldGroup *vl_iter, *v_links = r_vlinks; - memset(v_links, 0, sizeof(*v_links) * mvert_len); + r_vlinks.fill({0, 0}); + MutableSpan<WeldGroup> v_links = r_vlinks; - wp = &wpoly[0]; - for (uint i = wpoly_and_new_len; i--; wp++) { + for (const int i : IndexRange(wpoly_and_new_len)) { + const WeldPoly &wp = wpoly[i]; WeldLoopOfPolyIter iter; - if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) { while (weld_iter_loop_of_poly_next(&iter)) { v_links[iter.v].len++; } } } - uint link_len = 0; - vl_iter = &v_links[0]; - for (uint i = mvert_len; i--; vl_iter++) { - vl_iter->ofs = link_len; - link_len += vl_iter->len; + int link_len = 0; + for (const int i : IndexRange(mvert_len)) { + v_links[i].ofs = link_len; + link_len += v_links[i].len; } if (link_len) { - uint *link_poly_buffer = MEM_mallocN(sizeof(*link_poly_buffer) * link_len, __func__); + Array<int> link_poly_buffer(link_len); - wp = &wpoly[0]; - for (uint i = 0; i < wpoly_and_new_len; i++, wp++) { + for (const int i : IndexRange(wpoly_and_new_len)) { + const WeldPoly &wp = wpoly[i]; WeldLoopOfPolyIter iter; - if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL)) { + if (weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr)) { while (weld_iter_loop_of_poly_next(&iter)) { link_poly_buffer[v_links[iter.v].ofs++] = i; } } } - vl_iter = &v_links[0]; - for (uint i = mvert_len; i--; vl_iter++) { + for (WeldGroup &vl : r_vlinks) { /* Fix offset */ - vl_iter->ofs -= vl_iter->len; + vl.ofs -= vl.len; } - uint polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b; + int polys_len_a, polys_len_b, *polys_ctx_a, *polys_ctx_b, p_ctx_a, p_ctx_b; polys_len_b = p_ctx_b = 0; /* silence warnings */ - wp = &wpoly[0]; - for (uint i = 0; i < wpoly_and_new_len; i++, wp++) { - if (wp->poly_dst != OUT_OF_CONTEXT) { + for (const int i : IndexRange(wpoly_and_new_len)) { + const WeldPoly &wp = wpoly[i]; + if (wp.poly_dst != OUT_OF_CONTEXT) { /* No need to retest poly. * (Already includes collapsed polygons). */ continue; } WeldLoopOfPolyIter iter; - weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, NULL); + weld_iter_loop_of_poly_begin(&iter, wp, wloop, mloop, loop_map, nullptr); weld_iter_loop_of_poly_next(&iter); struct WeldGroup *link_a = &v_links[iter.v]; polys_len_a = link_a->len; @@ -1229,7 +1167,7 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, BLI_assert(link_poly_buffer[link_a->ofs] == i); continue; } - uint wp_len = wp->len; + int wp_len = wp.len; polys_ctx_a = &link_poly_buffer[link_a->ofs]; for (; polys_len_a--; polys_ctx_a++) { p_ctx_a = *polys_ctx_a; @@ -1275,36 +1213,31 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, BLI_assert(p_ctx_a > i); BLI_assert(p_ctx_a == p_ctx_b); BLI_assert(wp_tmp->poly_dst == OUT_OF_CONTEXT); - BLI_assert(wp_tmp != wp); - wp_tmp->poly_dst = wp->poly_orig; + BLI_assert(wp_tmp != &wp); + wp_tmp->poly_dst = wp.poly_orig; loop_kill_len += wp_tmp->len; poly_kill_len++; } } - MEM_freeN(link_poly_buffer); } } else { poly_kill_len = r_weld_mesh->wpoly_len; loop_kill_len = r_weld_mesh->wloop_len; - wp = &wpoly[0]; - for (uint i = wpoly_len; i--; wp++) { - wp->flag = ELEM_COLLAPSED; + for (WeldPoly &wp : wpoly) { + wp.flag = ELEM_COLLAPSED; } } #ifdef USE_WELD_DEBUG weld_assert_poly_and_loop_kill_len(wpoly, - wpoly_new, - wpoly_new_len, + {wpoly_new, wpoly_new_len}, wloop, mloop, loop_map, r_weld_mesh->poly_map, mpoly, - mpoly_len, - mloop_len, poly_kill_len, loop_kill_len); #endif @@ -1321,87 +1254,53 @@ static void weld_poly_loop_ctx_setup(const MLoop *mloop, * \{ */ static void weld_mesh_context_create(const Mesh *mesh, - uint *vert_dest_map, - const uint vert_kill_len, + MutableSpan<int> vert_dest_map, + const int vert_kill_len, WeldMesh *r_weld_mesh) { - const MEdge *medge = mesh->medge; - const MLoop *mloop = mesh->mloop; - const MPoly *mpoly = mesh->mpoly; - const uint mvert_len = mesh->totvert; - const uint medge_len = mesh->totedge; - const uint mloop_len = mesh->totloop; - const uint mpoly_len = mesh->totpoly; - - uint *edge_dest_map = MEM_mallocN(sizeof(*edge_dest_map) * medge_len, __func__); - struct WeldGroup *v_links = MEM_callocN(sizeof(*v_links) * mvert_len, __func__); - - WeldVert *wvert; - uint wvert_len; + Span<MEdge> medge{mesh->medge, mesh->totedge}; + Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly}; + Span<MLoop> mloop{mesh->mloop, mesh->totloop}; + const int mvert_len = mesh->totvert; + + Vector<WeldVert> wvert = weld_vert_ctx_alloc_and_setup(vert_dest_map, vert_kill_len); r_weld_mesh->vert_kill_len = vert_kill_len; - weld_vert_ctx_alloc_and_setup(mvert_len, vert_dest_map, &wvert, &wvert_len); - uint *edge_ctx_map; - WeldEdge *wedge; - uint wedge_len; - weld_edge_ctx_alloc( - medge, medge_len, vert_dest_map, edge_dest_map, &edge_ctx_map, &wedge, &wedge_len); + Array<int> edge_dest_map(medge.size()); + Array<int> edge_ctx_map(medge.size()); + Vector<WeldEdge> wedge = weld_edge_ctx_alloc(medge, vert_dest_map, edge_dest_map, edge_ctx_map); - weld_edge_ctx_setup( - mvert_len, wedge_len, v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len); + Array<WeldGroup> v_links(mvert_len, {0, 0}); + weld_edge_ctx_setup(v_links, edge_dest_map, wedge, &r_weld_mesh->edge_kill_len); - weld_poly_loop_ctx_alloc( - mpoly, mpoly_len, mloop, mloop_len, vert_dest_map, edge_dest_map, r_weld_mesh); + weld_poly_loop_ctx_alloc(mpoly, mloop, vert_dest_map, edge_dest_map, r_weld_mesh); weld_poly_loop_ctx_setup(mloop, #ifdef USE_WELD_DEBUG mpoly, - mpoly_len, - mloop_len, + #endif mvert_len, vert_dest_map, - wedge_len - r_weld_mesh->edge_kill_len, + wedge.size() - r_weld_mesh->edge_kill_len, v_links, r_weld_mesh); - weld_vert_groups_setup(mvert_len, - wvert_len, - wvert, + weld_vert_groups_setup(wvert, vert_dest_map, vert_dest_map, - &r_weld_mesh->vert_groups_buffer, - &r_weld_mesh->vert_groups); + r_weld_mesh->vert_groups_buffer, + r_weld_mesh->vert_groups); - weld_edge_groups_setup(medge_len, + weld_edge_groups_setup(medge.size(), r_weld_mesh->edge_kill_len, - wedge_len, wedge, edge_ctx_map, edge_dest_map, - &r_weld_mesh->edge_groups_buffer, - &r_weld_mesh->edge_groups); - - r_weld_mesh->edge_groups_map = edge_dest_map; - MEM_freeN(v_links); - MEM_freeN(wvert); - MEM_freeN(edge_ctx_map); - MEM_freeN(wedge); -} - -static void weld_mesh_context_free(WeldMesh *weld_mesh) -{ - MEM_freeN(weld_mesh->vert_groups); - MEM_freeN(weld_mesh->vert_groups_buffer); - - MEM_freeN(weld_mesh->edge_groups); - MEM_freeN(weld_mesh->edge_groups_buffer); - MEM_freeN(weld_mesh->edge_groups_map); + r_weld_mesh->edge_groups_buffer, + r_weld_mesh->edge_groups); - MEM_freeN(weld_mesh->wloop); - MEM_freeN(weld_mesh->wpoly); - MEM_freeN(weld_mesh->loop_map); - MEM_freeN(weld_mesh->poly_map); + r_weld_mesh->edge_groups_map = std::move(edge_dest_map); } /** \} */ @@ -1411,14 +1310,14 @@ static void weld_mesh_context_free(WeldMesh *weld_mesh) * \{ */ static void customdata_weld( - const CustomData *source, CustomData *dest, const uint *src_indices, int count, int dest_index) + const CustomData *source, CustomData *dest, const int *src_indices, int count, int dest_index) { if (count == 1) { CustomData_copy_data(source, dest, src_indices[0], dest_index, 1); return; } - CustomData_interp(source, dest, (const int *)src_indices, NULL, NULL, count, dest_index); + CustomData_interp(source, dest, (const int *)src_indices, nullptr, nullptr, count, dest_index); int src_i, dest_i; int j; @@ -1427,8 +1326,8 @@ static void customdata_weld( #ifdef USE_WELD_NORMALS float no[3] = {0.0f, 0.0f, 0.0f}; #endif - uint crease = 0; - uint bweight = 0; + int crease = 0; + int bweight = 0; short flag = 0; /* interpolates a layer at a time */ @@ -1572,37 +1471,35 @@ static bool bvhtree_weld_overlap_cb(void *userdata, int index_a, int index_b, in /** Use for #MOD_WELD_MODE_CONNECTED calculation. */ struct WeldVertexCluster { float co[3]; - uint merged_verts; + int merged_verts; }; static Mesh *weldModifier_doWeld(WeldModifierData *wmd, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh) { - Mesh *result = mesh; - - BLI_bitmap *v_mask = NULL; + BLI_bitmap *v_mask = nullptr; int v_mask_act = 0; - const MVert *mvert; - const MLoop *mloop; - const MPoly *mpoly, *mp; - uint totvert, totedge, totloop, totpoly; - - mvert = mesh->mvert; - totvert = mesh->totvert; + Span<MVert> mvert{mesh->mvert, mesh->totvert}; + Span<MEdge> medge{mesh->medge, mesh->totedge}; + Span<MPoly> mpoly{mesh->mpoly, mesh->totpoly}; + Span<MLoop> mloop{mesh->mloop, mesh->totloop}; + const int totvert = mesh->totvert; + const int totedge = mesh->totedge; + const int totloop = mesh->totloop; + const int totpoly = mesh->totpoly; /* Vertex Group. */ const int defgrp_index = BKE_id_defgroup_name_index(&mesh->id, wmd->defgrp_name); if (defgrp_index != -1) { - MDeformVert *dvert, *dv; - dvert = CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT); + MDeformVert *dvert; + dvert = static_cast<MDeformVert *>(CustomData_get_layer(&mesh->vdata, CD_MDEFORMVERT)); if (dvert) { const bool invert_vgroup = (wmd->flag & MOD_WELD_INVERT_VGROUP) != 0; - dv = &dvert[0]; v_mask = BLI_BITMAP_NEW(totvert, __func__); - for (uint i = 0; i < totvert; i++, dv++) { - const bool found = BKE_defvert_find_weight(dv, defgrp_index) > 0.0f; + for (const int i : IndexRange(totvert)) { + const bool found = BKE_defvert_find_weight(&dvert[i], defgrp_index) > 0.0f; if (found != invert_vgroup) { BLI_BITMAP_ENABLE(v_mask, i); v_mask_act++; @@ -1613,15 +1510,15 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, /* From the original index of the vertex. * This indicates which vert it is or is going to be merged. */ - uint *vert_dest_map = MEM_malloc_arrayN(totvert, sizeof(*vert_dest_map), __func__); - uint vert_kill_len = 0; + Array<int> vert_dest_map(totvert); + int vert_kill_len = 0; if (wmd->mode == MOD_WELD_MODE_ALL) #ifdef USE_BVHTREEKDOP { /* Get overlap map. */ struct BVHTreeFromMesh treedata; BVHTree *bvhtree = bvhtree_from_mesh_verts_ex(&treedata, - mvert, + mvert.data(), totvert, false, v_mask, @@ -1630,8 +1527,8 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, 2, 6, 0, - NULL, - NULL); + nullptr, + nullptr); if (bvhtree) { struct WeldOverlapData data; @@ -1649,20 +1546,20 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, free_bvhtree_from_mesh(&treedata); if (overlap) { - range_vn_u(vert_dest_map, totvert, 0); + range_vn_i(vert_dest_map.data(), totvert, 0); const BVHTreeOverlap *overlap_iter = &overlap[0]; - for (uint i = 0; i < overlap_len; i++, overlap_iter++) { - uint indexA = overlap_iter->indexA; - uint indexB = overlap_iter->indexB; + for (int i = 0; i < overlap_len; i++, overlap_iter++) { + int indexA = overlap_iter->indexA; + int indexB = overlap_iter->indexB; BLI_assert(indexA < indexB); - uint va_dst = vert_dest_map[indexA]; + int va_dst = vert_dest_map[indexA]; while (va_dst != vert_dest_map[va_dst]) { va_dst = vert_dest_map[va_dst]; } - uint vb_dst = vert_dest_map[indexB]; + int vb_dst = vert_dest_map[indexB]; while (vb_dst != vert_dest_map[vb_dst]) { vb_dst = vert_dest_map[vb_dst]; } @@ -1670,19 +1567,19 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, continue; } if (va_dst > vb_dst) { - SWAP(uint, va_dst, vb_dst); + SWAP(int, va_dst, vb_dst); } vert_kill_len++; vert_dest_map[vb_dst] = va_dst; } /* Fix #r_vert_dest_map for next step. */ - for (uint i = 0; i < totvert; i++) { + for (int i = 0; i < totvert; i++) { if (i == vert_dest_map[i]) { vert_dest_map[i] = OUT_OF_CONTEXT; } else { - uint v = i; + int v = i; while (v != vert_dest_map[v] && vert_dest_map[v] != OUT_OF_CONTEXT) { v = vert_dest_map[v]; } @@ -1698,7 +1595,7 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, #else { KDTree_3d *tree = BLI_kdtree_3d_new(v_mask ? v_mask_act : totvert); - for (uint i = 0; i < totvert; i++) { + for (const int i : IndexRange(totvert)) { if (!v_mask || BLI_BITMAP_TEST(v_mask, i)) { BLI_kdtree_3d_insert(tree, i, mvert[i].co); } @@ -1707,37 +1604,30 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, BLI_kdtree_3d_balance(tree); vert_kill_len = BLI_kdtree_3d_calc_duplicates_fast( - tree, wmd->merge_dist, false, (int *)vert_dest_map); + tree, wmd->merge_dist, false, vert_dest_map.data()); BLI_kdtree_3d_free(tree); } #endif else { BLI_assert(wmd->mode == MOD_WELD_MODE_CONNECTED); - MEdge *medge, *me; - - medge = mesh->medge; - totvert = mesh->totvert; - totedge = mesh->totedge; + Array<WeldVertexCluster> vert_clusters(totvert); - struct WeldVertexCluster *vert_clusters = MEM_malloc_arrayN( - totvert, sizeof(*vert_clusters), __func__); - struct WeldVertexCluster *vc = &vert_clusters[0]; - for (uint i = 0; i < totvert; i++, vc++) { - copy_v3_v3(vc->co, mvert[i].co); - vc->merged_verts = 0; + for (const int i : mvert.index_range()) { + WeldVertexCluster &vc = vert_clusters[i]; + copy_v3_v3(vc.co, mvert[i].co); + vc.merged_verts = 0; } const float merge_dist_sq = square_f(wmd->merge_dist); - range_vn_u(vert_dest_map, totvert, 0); + range_vn_i(vert_dest_map.data(), totvert, 0); /* Collapse Edges that are shorter than the threshold. */ - me = &medge[0]; - for (uint i = 0; i < totedge; i++, me++) { - uint v1 = me->v1; - uint v2 = me->v2; + for (const int i : medge.index_range()) { + int v1 = medge[i].v1; + int v2 = medge[i].v2; - if (wmd->flag & MOD_WELD_LOOSE_EDGES && (me->flag & ME_LOOSEEDGE) == 0) { + if (wmd->flag & MOD_WELD_LOOSE_EDGES && (medge[i].flag & ME_LOOSEEDGE) == 0) { continue; } while (v1 != vert_dest_map[v1]) { @@ -1753,10 +1643,10 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, continue; } if (v1 > v2) { - SWAP(uint, v1, v2); + SWAP(int, v1, v2); } - struct WeldVertexCluster *v1_cluster = &vert_clusters[v1]; - struct WeldVertexCluster *v2_cluster = &vert_clusters[v2]; + WeldVertexCluster *v1_cluster = &vert_clusters[v1]; + WeldVertexCluster *v2_cluster = &vert_clusters[v2]; float edgedir[3]; sub_v3_v3v3(edgedir, v2_cluster->co, v1_cluster->co); @@ -1772,14 +1662,12 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, } } - MEM_freeN(vert_clusters); - - for (uint i = 0; i < totvert; i++) { + for (const int i : IndexRange(totvert)) { if (i == vert_dest_map[i]) { vert_dest_map[i] = OUT_OF_CONTEXT; } else { - uint v = i; + int v = i; while ((v != vert_dest_map[v]) && (vert_dest_map[v] != OUT_OF_CONTEXT)) { v = vert_dest_map[v]; } @@ -1793,174 +1681,139 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, MEM_freeN(v_mask); } - if (vert_kill_len) { - WeldMesh weld_mesh; - weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh); - - mloop = mesh->mloop; - mpoly = mesh->mpoly; - - totedge = mesh->totedge; - totloop = mesh->totloop; - totpoly = mesh->totpoly; - - const int result_nverts = totvert - weld_mesh.vert_kill_len; - const int result_nedges = totedge - weld_mesh.edge_kill_len; - const int result_nloops = totloop - weld_mesh.loop_kill_len; - const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; - - result = BKE_mesh_new_nomain_from_template( - mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); - - /* Vertices */ - - uint *vert_final = vert_dest_map; - uint *index_iter = &vert_final[0]; - int dest_index = 0; - for (uint i = 0; i < totvert; i++, index_iter++) { - int source_index = i; - int count = 0; - while (i < totvert && *index_iter == OUT_OF_CONTEXT) { - *index_iter = dest_index + count; - index_iter++; - count++; - i++; - } - if (count) { - CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count); - dest_index += count; - } - if (i == totvert) { - break; - } - if (*index_iter != ELEM_MERGED) { - struct WeldGroup *wgroup = &weld_mesh.vert_groups[*index_iter]; - customdata_weld(&mesh->vdata, - &result->vdata, - &weld_mesh.vert_groups_buffer[wgroup->ofs], - wgroup->len, - dest_index); - *index_iter = dest_index; - dest_index++; - } - } + if (vert_kill_len == 0) { + return mesh; + } - BLI_assert(dest_index == result_nverts); - - /* Edges */ - - uint *edge_final = weld_mesh.edge_groups_map; - index_iter = &edge_final[0]; - dest_index = 0; - for (uint i = 0; i < totedge; i++, index_iter++) { - int source_index = i; - int count = 0; - while (i < totedge && *index_iter == OUT_OF_CONTEXT) { - *index_iter = dest_index + count; - index_iter++; - count++; - i++; - } - if (count) { - CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count); - MEdge *me = &result->medge[dest_index]; - dest_index += count; - for (; count--; me++) { - me->v1 = vert_final[me->v1]; - me->v2 = vert_final[me->v2]; - } - } - if (i == totedge) { - break; - } - if (*index_iter != ELEM_MERGED) { - struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[*index_iter]; - customdata_weld(&mesh->edata, - &result->edata, - &weld_mesh.edge_groups_buffer[wegrp->group.ofs], - wegrp->group.len, - dest_index); - MEdge *me = &result->medge[dest_index]; - me->v1 = vert_final[wegrp->v1]; - me->v2 = vert_final[wegrp->v2]; - me->flag |= ME_LOOSEEDGE; - - *index_iter = dest_index; - dest_index++; - } + WeldMesh weld_mesh; + weld_mesh_context_create(mesh, vert_dest_map, vert_kill_len, &weld_mesh); + + const int result_nverts = totvert - weld_mesh.vert_kill_len; + const int result_nedges = totedge - weld_mesh.edge_kill_len; + const int result_nloops = totloop - weld_mesh.loop_kill_len; + const int result_npolys = totpoly - weld_mesh.poly_kill_len + weld_mesh.wpoly_new_len; + + Mesh *result = BKE_mesh_new_nomain_from_template( + mesh, result_nverts, result_nedges, 0, result_nloops, result_npolys); + + /* Vertices. */ + + /* Be careful when editing this array, to avoid new allocations it uses the same buffer as + * #vert_dest_map. This map will be used to adjust the edges, polys and loops. */ + MutableSpan<int> vert_final = vert_dest_map; + + int dest_index = 0; + for (int i = 0; i < totvert; i++) { + int source_index = i; + int count = 0; + while (i < totvert && vert_dest_map[i] == OUT_OF_CONTEXT) { + vert_final[i] = dest_index + count; + count++; + i++; } + if (count) { + CustomData_copy_data(&mesh->vdata, &result->vdata, source_index, dest_index, count); + dest_index += count; + } + if (i == totvert) { + break; + } + if (vert_dest_map[i] != ELEM_MERGED) { + struct WeldGroup *wgroup = &weld_mesh.vert_groups[vert_dest_map[i]]; + customdata_weld(&mesh->vdata, + &result->vdata, + &weld_mesh.vert_groups_buffer[wgroup->ofs], + wgroup->len, + dest_index); + vert_final[i] = dest_index; + dest_index++; + } + } - BLI_assert(dest_index == result_nedges); - - /* Polys/Loops */ - - mp = &mpoly[0]; - MPoly *r_mp = &result->mpoly[0]; - MLoop *r_ml = &result->mloop[0]; - uint r_i = 0; - int loop_cur = 0; - uint *group_buffer = BLI_array_alloca(group_buffer, weld_mesh.max_poly_len); - for (uint i = 0; i < totpoly; i++, mp++) { - int loop_start = loop_cur; - uint poly_ctx = weld_mesh.poly_map[i]; - if (poly_ctx == OUT_OF_CONTEXT) { - uint mp_loop_len = mp->totloop; - CustomData_copy_data(&mesh->ldata, &result->ldata, mp->loopstart, loop_cur, mp_loop_len); - loop_cur += mp_loop_len; - for (; mp_loop_len--; r_ml++) { - r_ml->v = vert_final[r_ml->v]; - r_ml->e = edge_final[r_ml->e]; - } - } - else { - WeldPoly *wp = &weld_mesh.wpoly[poly_ctx]; - WeldLoopOfPolyIter iter; - if (!weld_iter_loop_of_poly_begin( - &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) { - continue; - } + BLI_assert(dest_index == result_nverts); - if (wp->poly_dst != OUT_OF_CONTEXT) { - continue; - } - while (weld_iter_loop_of_poly_next(&iter)) { - customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur); - uint v = vert_final[iter.v]; - uint e = edge_final[iter.e]; - r_ml->v = v; - r_ml->e = e; - r_ml++; - loop_cur++; - if (iter.type) { - result->medge[e].flag &= ~ME_LOOSEEDGE; - } - BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0); - } - } + /* Edges. */ + + /* Be careful when editing this array, to avoid new allocations it uses the same buffer as + * #edge_groups_map. This map will be used to adjust the polys and loops. */ + MutableSpan<int> edge_final = weld_mesh.edge_groups_map; - CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1); - r_mp->loopstart = loop_start; - r_mp->totloop = loop_cur - loop_start; - r_mp++; - r_i++; + dest_index = 0; + for (int i = 0; i < totedge; i++) { + int source_index = i; + int count = 0; + while (i < totedge && weld_mesh.edge_groups_map[i] == OUT_OF_CONTEXT) { + edge_final[i] = dest_index + count; + count++; + i++; + } + if (count) { + CustomData_copy_data(&mesh->edata, &result->edata, source_index, dest_index, count); + MEdge *me = &result->medge[dest_index]; + dest_index += count; + for (; count--; me++) { + me->v1 = vert_final[me->v1]; + me->v2 = vert_final[me->v2]; + } + } + if (i == totedge) { + break; } + if (weld_mesh.edge_groups_map[i] != ELEM_MERGED) { + struct WeldGroupEdge *wegrp = &weld_mesh.edge_groups[weld_mesh.edge_groups_map[i]]; + customdata_weld(&mesh->edata, + &result->edata, + &weld_mesh.edge_groups_buffer[wegrp->group.ofs], + wegrp->group.len, + dest_index); + MEdge *me = &result->medge[dest_index]; + me->v1 = vert_final[wegrp->v1]; + me->v2 = vert_final[wegrp->v2]; + me->flag |= ME_LOOSEEDGE; + + edge_final[i] = dest_index; + dest_index++; + } + } - WeldPoly *wp = &weld_mesh.wpoly_new[0]; - for (uint i = 0; i < weld_mesh.wpoly_new_len; i++, wp++) { - int loop_start = loop_cur; + BLI_assert(dest_index == result_nedges); + + /* Polys/Loops. */ + + MPoly *r_mp = &result->mpoly[0]; + MLoop *r_ml = &result->mloop[0]; + int r_i = 0; + int loop_cur = 0; + Array<int, 64> group_buffer(weld_mesh.max_poly_len); + for (const int i : mpoly.index_range()) { + const MPoly &mp = mpoly[i]; + int loop_start = loop_cur; + int poly_ctx = weld_mesh.poly_map[i]; + if (poly_ctx == OUT_OF_CONTEXT) { + int mp_loop_len = mp.totloop; + CustomData_copy_data(&mesh->ldata, &result->ldata, mp.loopstart, loop_cur, mp_loop_len); + loop_cur += mp_loop_len; + for (; mp_loop_len--; r_ml++) { + r_ml->v = vert_final[r_ml->v]; + r_ml->e = edge_final[r_ml->e]; + } + } + else { + const WeldPoly &wp = weld_mesh.wpoly[poly_ctx]; WeldLoopOfPolyIter iter; if (!weld_iter_loop_of_poly_begin( - &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer)) { + &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { continue; } - if (wp->poly_dst != OUT_OF_CONTEXT) { + if (wp.poly_dst != OUT_OF_CONTEXT) { continue; } while (weld_iter_loop_of_poly_next(&iter)) { - customdata_weld(&mesh->ldata, &result->ldata, group_buffer, iter.group_len, loop_cur); - uint v = vert_final[iter.v]; - uint e = edge_final[iter.e]; + customdata_weld( + &mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur); + int v = vert_final[iter.v]; + int e = edge_final[iter.e]; r_ml->v = v; r_ml->e = e; r_ml++; @@ -1970,23 +1823,54 @@ static Mesh *weldModifier_doWeld(WeldModifierData *wmd, } BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0); } - - r_mp->loopstart = loop_start; - r_mp->totloop = loop_cur - loop_start; - r_mp++; - r_i++; } - BLI_assert((int)r_i == result_npolys); - BLI_assert(loop_cur == result_nloops); + CustomData_copy_data(&mesh->pdata, &result->pdata, i, r_i, 1); + r_mp->loopstart = loop_start; + r_mp->totloop = loop_cur - loop_start; + r_mp++; + r_i++; + } - /* is this needed? */ - BKE_mesh_normals_tag_dirty(result); + for (const int i : IndexRange(weld_mesh.wpoly_new_len)) { + const WeldPoly &wp = weld_mesh.wpoly_new[i]; + int loop_start = loop_cur; + WeldLoopOfPolyIter iter; + if (!weld_iter_loop_of_poly_begin( + &iter, wp, weld_mesh.wloop, mloop, weld_mesh.loop_map, group_buffer.data())) { + continue; + } - weld_mesh_context_free(&weld_mesh); + if (wp.poly_dst != OUT_OF_CONTEXT) { + continue; + } + while (weld_iter_loop_of_poly_next(&iter)) { + customdata_weld(&mesh->ldata, &result->ldata, group_buffer.data(), iter.group_len, loop_cur); + int v = vert_final[iter.v]; + int e = edge_final[iter.e]; + r_ml->v = v; + r_ml->e = e; + r_ml++; + loop_cur++; + if (iter.type) { + result->medge[e].flag &= ~ME_LOOSEEDGE; + } + BLI_assert((result->medge[e].flag & ME_LOOSEEDGE) == 0); + } + + r_mp->loopstart = loop_start; + r_mp->totloop = loop_cur - loop_start; + r_mp++; + r_i++; } - MEM_freeN(vert_dest_map); + BLI_assert((int)r_i == result_npolys); + BLI_assert(loop_cur == result_nloops); + + /* We could only update the normals of the elements in context, but the next modifier can make it + * dirty anyway which would make the work useless. */ + BKE_mesh_normals_tag_dirty(result); + return result; } @@ -2027,12 +1911,12 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiLayoutSetPropSep(layout, true); - uiItemR(layout, ptr, "mode", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "mode", 0, nullptr, ICON_NONE); uiItemR(layout, ptr, "merge_threshold", 0, IFACE_("Distance"), ICON_NONE); if (weld_mode == MOD_WELD_MODE_CONNECTED) { - uiItemR(layout, ptr, "loose_edges", 0, NULL, ICON_NONE); + uiItemR(layout, ptr, "loose_edges", 0, nullptr, ICON_NONE); } - modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", NULL); + modifier_vgroup_ui(layout, ptr, &ob_ptr, "vertex_group", "invert_vertex_group", nullptr); modifier_panel_end(layout, ptr); } @@ -2048,34 +1932,35 @@ ModifierTypeInfo modifierType_Weld = { /* structSize */ sizeof(WeldModifierData), /* srna */ &RNA_WeldModifier, /* type */ eModifierTypeType_Constructive, - /* flags */ eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | - eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | - eModifierTypeFlag_AcceptsCVs, + /* flags */ + (ModifierTypeFlag)(eModifierTypeFlag_AcceptsMesh | eModifierTypeFlag_SupportsMapping | + eModifierTypeFlag_SupportsEditmode | eModifierTypeFlag_EnableInEditmode | + eModifierTypeFlag_AcceptsCVs), /* icon */ ICON_AUTOMERGE_OFF, /* TODO: Use correct icon. */ /* copyData */ BKE_modifier_copydata_generic, - /* deformVerts */ NULL, - /* deformMatrices */ NULL, - /* deformVertsEM */ NULL, - /* deformMatricesEM */ NULL, + /* deformVerts */ nullptr, + /* deformMatrices */ nullptr, + /* deformVertsEM */ nullptr, + /* deformMatricesEM */ nullptr, /* modifyMesh */ modifyMesh, - /* modifyHair */ NULL, - /* modifyGeometrySet */ NULL, + /* modifyHair */ nullptr, + /* modifyGeometrySet */ nullptr, /* initData */ initData, /* requiredDataMask */ requiredDataMask, - /* freeData */ NULL, - /* isDisabled */ NULL, - /* updateDepsgraph */ NULL, - /* dependsOnTime */ NULL, - /* dependsOnNormals */ NULL, - /* foreachIDLink */ NULL, - /* foreachTexLink */ NULL, - /* freeRuntimeData */ NULL, + /* freeData */ nullptr, + /* isDisabled */ nullptr, + /* updateDepsgraph */ nullptr, + /* dependsOnTime */ nullptr, + /* dependsOnNormals */ nullptr, + /* foreachIDLink */ nullptr, + /* foreachTexLink */ nullptr, + /* freeRuntimeData */ nullptr, /* panelRegister */ panelRegister, - /* blendWrite */ NULL, - /* blendRead */ NULL, + /* blendWrite */ nullptr, + /* blendRead */ nullptr, }; /** \} */ diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 5f61d13a3af..4d31cd3e4f5 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(composite) +add_subdirectory(function) add_subdirectory(geometry) add_subdirectory(shader) @@ -49,114 +51,6 @@ set(INC set(SRC - composite/nodes/node_composite_alphaOver.cc - composite/nodes/node_composite_antialiasing.cc - composite/nodes/node_composite_bilateralblur.cc - composite/nodes/node_composite_blur.cc - composite/nodes/node_composite_bokehblur.cc - composite/nodes/node_composite_bokehimage.cc - composite/nodes/node_composite_boxmask.cc - composite/nodes/node_composite_brightness.cc - composite/nodes/node_composite_channelMatte.cc - composite/nodes/node_composite_chromaMatte.cc - composite/nodes/node_composite_colorMatte.cc - composite/nodes/node_composite_colorSpill.cc - composite/nodes/node_composite_colorbalance.cc - composite/nodes/node_composite_colorcorrection.cc - composite/nodes/node_composite_common.cc - composite/nodes/node_composite_composite.cc - composite/nodes/node_composite_cornerpin.cc - composite/nodes/node_composite_crop.cc - composite/nodes/node_composite_cryptomatte.cc - composite/nodes/node_composite_curves.cc - composite/nodes/node_composite_defocus.cc - composite/nodes/node_composite_denoise.cc - composite/nodes/node_composite_despeckle.cc - composite/nodes/node_composite_diffMatte.cc - composite/nodes/node_composite_dilate.cc - composite/nodes/node_composite_directionalblur.cc - composite/nodes/node_composite_displace.cc - composite/nodes/node_composite_distanceMatte.cc - composite/nodes/node_composite_doubleEdgeMask.cc - composite/nodes/node_composite_ellipsemask.cc - composite/nodes/node_composite_exposure.cc - composite/nodes/node_composite_filter.cc - composite/nodes/node_composite_flip.cc - composite/nodes/node_composite_gamma.cc - composite/nodes/node_composite_glare.cc - composite/nodes/node_composite_hueSatVal.cc - composite/nodes/node_composite_huecorrect.cc - composite/nodes/node_composite_idMask.cc - composite/nodes/node_composite_image.cc - composite/nodes/node_composite_inpaint.cc - composite/nodes/node_composite_invert.cc - composite/nodes/node_composite_keying.cc - composite/nodes/node_composite_keyingscreen.cc - composite/nodes/node_composite_lensdist.cc - composite/nodes/node_composite_levels.cc - composite/nodes/node_composite_lummaMatte.cc - composite/nodes/node_composite_mapRange.cc - composite/nodes/node_composite_mapUV.cc - composite/nodes/node_composite_mapValue.cc - composite/nodes/node_composite_mask.cc - composite/nodes/node_composite_math.cc - composite/nodes/node_composite_mixrgb.cc - composite/nodes/node_composite_movieclip.cc - composite/nodes/node_composite_moviedistortion.cc - composite/nodes/node_composite_normal.cc - composite/nodes/node_composite_normalize.cc - composite/nodes/node_composite_outputFile.cc - composite/nodes/node_composite_pixelate.cc - composite/nodes/node_composite_planetrackdeform.cc - composite/nodes/node_composite_posterize.cc - composite/nodes/node_composite_premulkey.cc - composite/nodes/node_composite_rgb.cc - composite/nodes/node_composite_rotate.cc - composite/nodes/node_composite_scale.cc - composite/nodes/node_composite_sepcombHSVA.cc - composite/nodes/node_composite_sepcombRGBA.cc - composite/nodes/node_composite_sepcombYCCA.cc - composite/nodes/node_composite_sepcombYUVA.cc - composite/nodes/node_composite_setalpha.cc - composite/nodes/node_composite_splitViewer.cc - composite/nodes/node_composite_stabilize2d.cc - composite/nodes/node_composite_sunbeams.cc - composite/nodes/node_composite_switch.cc - composite/nodes/node_composite_switchview.cc - composite/nodes/node_composite_texture.cc - composite/nodes/node_composite_tonemap.cc - composite/nodes/node_composite_trackpos.cc - composite/nodes/node_composite_transform.cc - composite/nodes/node_composite_translate.cc - composite/nodes/node_composite_valToRgb.cc - composite/nodes/node_composite_value.cc - composite/nodes/node_composite_vecBlur.cc - composite/nodes/node_composite_viewer.cc - composite/nodes/node_composite_zcombine.cc - - composite/node_composite_tree.cc - composite/node_composite_util.cc - - function/nodes/legacy/node_fn_random_float.cc - - function/nodes/node_fn_align_euler_to_vector.cc - function/nodes/node_fn_boolean_math.cc - function/nodes/node_fn_compare.cc - function/nodes/node_fn_float_to_int.cc - function/nodes/node_fn_input_bool.cc - function/nodes/node_fn_input_color.cc - function/nodes/node_fn_input_int.cc - function/nodes/node_fn_input_special_characters.cc - function/nodes/node_fn_input_string.cc - function/nodes/node_fn_input_vector.cc - function/nodes/node_fn_random_value.cc - function/nodes/node_fn_replace_string.cc - function/nodes/node_fn_rotate_euler.cc - function/nodes/node_fn_slice_string.cc - function/nodes/node_fn_string_length.cc - function/nodes/node_fn_value_to_string.cc - function/node_function_util.cc - texture/nodes/node_texture_at.c texture/nodes/node_texture_bricks.c texture/nodes/node_texture_checker.c @@ -197,8 +91,6 @@ set(SRC intern/node_tree_ref.cc intern/node_util.c - composite/node_composite_util.hh - function/node_function_util.hh texture/node_texture_util.h NOD_common.h @@ -227,6 +119,8 @@ set(SRC set(LIB bf_bmesh bf_functions + bf_nodes_composite + bf_nodes_function bf_nodes_geometry bf_nodes_shader ) @@ -282,13 +176,6 @@ if(WITH_IMAGE_OPENEXR) add_definitions(-DWITH_OPENEXR) endif() -if(WITH_COMPOSITOR) - list(APPEND INC - ../compositor - ) - add_definitions(-DWITH_COMPOSITOR) -endif() - if(WITH_FREESTYLE) add_definitions(-DWITH_FREESTYLE) endif() diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index a0b8e237f19..96a5e1d87a6 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -49,6 +49,7 @@ void register_node_type_geo_legacy_select_by_material(void); void register_node_type_geo_legacy_subdivision_surface(void); void register_node_type_geo_legacy_volume_to_mesh(void); +void register_node_type_geo_accumulate_field(void); void register_node_type_geo_align_rotation_to_vector(void); void register_node_type_geo_attribute_capture(void); void register_node_type_geo_attribute_clamp(void); @@ -87,8 +88,8 @@ void register_node_type_geo_curve_resample(void); void register_node_type_geo_curve_reverse(void); void register_node_type_geo_curve_sample(void); void register_node_type_geo_curve_set_handles(void); -void register_node_type_geo_curve_spline_type(void); void register_node_type_geo_curve_spline_parameter(void); +void register_node_type_geo_curve_spline_type(void); void register_node_type_geo_curve_subdivide(void); void register_node_type_geo_curve_to_mesh(void); void register_node_type_geo_curve_to_points(void); @@ -105,6 +106,7 @@ void register_node_type_geo_input_id(void); void register_node_type_geo_input_index(void); void register_node_type_geo_input_material_index(void); void register_node_type_geo_input_material(void); +void register_node_type_geo_input_mesh_edge_angle(void); void register_node_type_geo_input_mesh_edge_neighbors(void); void register_node_type_geo_input_mesh_edge_vertices(void); void register_node_type_geo_input_mesh_face_area(void); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index f225b3b94b2..2246cc29dc4 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -134,12 +134,8 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || - std::is_same_v<T, int> || - std::is_same_v<T, bool> || - std::is_same_v<T, ColorGeometry4f> || - std::is_same_v<T, float3> || - std::is_same_v<T, std::string>; + static inline constexpr bool is_field_base_type_v = + is_same_any_v<T, float, int, bool, ColorGeometry4f, float3, std::string>; /** * Get the input value for the input socket with the given identifier. diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index af2130ec452..113e8ffc93d 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -95,6 +95,7 @@ class SocketDeclaration { bool compact_ = false; bool is_multi_input_ = false; bool no_mute_links_ = false; + bool is_unavailable_ = false; bool is_attribute_name_ = false; bool is_default_link_socket_ = false; @@ -185,12 +186,23 @@ class SocketDeclarationBuilder : public BaseSocketDeclarationBuilder { decl_->description_ = std::move(value); return *(Self *)this; } + Self &no_muted_links(bool value = true) { decl_->no_mute_links_ = value; return *(Self *)this; } + /** + * Used for sockets that are always unavailable and should not be seen by the user. + * Ideally, no new calls to this method should be added over time. + */ + Self &unavailable(bool value = true) + { + decl_->is_unavailable_ = value; + return *(Self *)this; + } + Self &is_attribute_name(bool value = true) { decl_->is_attribute_name_ = value; @@ -288,10 +300,13 @@ class NodeDeclarationBuilder { /** * All inputs support fields, and all outputs are fields if any of the inputs is a field. - * Calling field status definitions on each socket is unnecessary. + * Calling field status definitions on each socket is unnecessary. Must be called before adding + * any sockets. */ void is_function_node(bool value = true) { + BLI_assert_msg(declaration_.inputs().is_empty() && declaration_.outputs().is_empty(), + "is_function_node() must be called before any socket is created"); declaration_.is_function_node_ = value; } @@ -476,6 +491,10 @@ inline typename DeclType::Builder &NodeDeclarationBuilder::add_socket(StringRef socket_decl->name_ = name; socket_decl->identifier_ = identifier.is_empty() ? name : identifier; socket_decl->in_out_ = in_out; + if (declaration_.is_function_node()) { + socket_decl->input_field_type_ = InputSocketFieldType::IsSupported; + socket_decl->output_field_dependency_ = OutputFieldDependency::ForDependentField(); + } declarations.append(std::move(socket_decl)); Builder &socket_decl_builder_ref = *socket_decl_builder; builders_.append(std::move(socket_decl_builder)); diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh index 65789069231..ebbec20a139 100644 --- a/source/blender/nodes/NOD_node_tree_ref.hh +++ b/source/blender/nodes/NOD_node_tree_ref.hh @@ -262,6 +262,7 @@ class NodeTreeRef : NonCopyable, NonMovable { Vector<LinkRef *> links_; MultiValueMap<const bNodeType *, NodeRef *> nodes_by_type_; Vector<std::unique_ptr<SocketIndexByIdentifierMap>> owned_identifier_maps_; + const NodeRef *group_output_node_ = nullptr; public: NodeTreeRef(bNodeTree *btree); @@ -280,6 +281,11 @@ class NodeTreeRef : NonCopyable, NonMovable { const NodeRef *find_node(const bNode &bnode) const; /** + * This is the active group output node if there are multiple. + */ + const NodeRef *group_output_node() const; + + /** * \return True when there is a link cycle. Unavailable sockets are ignored. */ bool has_link_cycles() const; @@ -759,6 +765,11 @@ inline Span<const LinkRef *> NodeTreeRef::links() const return links_; } +inline const NodeRef *NodeTreeRef::group_output_node() const +{ + return group_output_node_; +} + inline bNodeTree *NodeTreeRef::btree() const { return btree_; diff --git a/source/blender/nodes/NOD_socket_declarations.hh b/source/blender/nodes/NOD_socket_declarations.hh index 3fb21a4263d..c0ba949e337 100644 --- a/source/blender/nodes/NOD_socket_declarations.hh +++ b/source/blender/nodes/NOD_socket_declarations.hh @@ -231,7 +231,7 @@ class Shader : public SocketDeclaration { bNodeSocket &build(bNodeTree &ntree, bNode &node) const override; bool matches(const bNodeSocket &socket) const override; - bool can_connect(const bNodeSocket &socket) const; + bool can_connect(const bNodeSocket &socket) const override; }; class ShaderBuilder : public SocketDeclarationBuilder<Shader> { diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 84bc7bf0ceb..74f1531bd90 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -323,9 +323,9 @@ DefNode(GeometryNode, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, 0, "LEGACY_SELECT_BY_M DefNode(GeometryNode, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, def_geo_subdivision_surface, "LEGACY_SUBDIVISION_SURFACE", LegacySubdivisionSurface, "Subdivision Surface", "") DefNode(GeometryNode, GEO_NODE_LEGACY_VOLUME_TO_MESH, def_geo_volume_to_mesh, "LEGACY_VOLUME_TO_MESH", LegacyVolumeToMesh, "Volume to Mesh", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_REMOVE, 0, "ATTRIBUTE_REMOVE", AttributeRemove, "Attribute Remove", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_STATISTIC, def_geo_attribute_statistic, "ATTRIBUTE_STATISTIC", AttributeStatistic, "Attribute Statistic", "") -DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, def_geo_attribute_domain_size, "ATTRIBUTE_DOMAIN_SIZE", AttributeDomainSize, "Domain Size", "") DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "") DefNode(GeometryNode, GEO_NODE_CAPTURE_ATTRIBUTE, def_geo_attribute_capture, "CAPTURE_ATTRIBUTE", CaptureAttribute, "Capture Attribute", "") DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "") @@ -333,7 +333,6 @@ DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Conve DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINT_SELECTION, 0, "CURVE_ENDPOINT_SELECTION", CurveEndpointSelection, "Endpoint Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, def_geo_curve_handle_type_selection, "CURVE_HANDLE_TYPE_SELECTION", CurveHandleTypeSelection, "Handle Type Selection", "") DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "") -DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "") @@ -342,11 +341,13 @@ DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_prim DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "") DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "") DefNode(GeometryNode, GEO_NODE_CURVE_SET_HANDLES, def_geo_curve_set_handles, "CURVE_SET_HANDLES", CurveSetHandles, "Set Handle Type", "") +DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_PARAMETER, 0, "SPLINE_PARAMETER", SplineParameter, "Spline Parameter", "") DefNode(GeometryNode, GEO_NODE_CURVE_SPLINE_TYPE, def_geo_curve_spline_type, "CURVE_SPLINE_TYPE", CurveSplineType, "Set Spline Type", "") DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "") DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "") DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, def_geo_delete_geometry, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "") DefNode(GeometryNode, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, def_geo_distribute_points_on_faces, "DISTRIBUTE_POINTS_ON_FACES", DistributePointsOnFaces, "Distribute Points on Faces", "") +DefNode(GeometryNode, GEO_NODE_ACCUMULATE_FIELD, def_geo_accumulate_field, "ACCUMULATE_FIELD", AccumulateField, "Accumulate Field", "") DefNode(GeometryNode, GEO_NODE_DUAL_MESH, 0, "DUAL_MESH", DualMesh, "Dual Mesh", "") DefNode(GeometryNode, GEO_NODE_FILL_CURVE, def_geo_curve_fill, "FILL_CURVE", FillCurve, "Fill Curve", "") DefNode(GeometryNode, GEO_NODE_FILLET_CURVE, def_geo_curve_fillet, "FILLET_CURVE", FilletCurve, "Fillet Curve", "") @@ -358,6 +359,7 @@ DefNode(GeometryNode, GEO_NODE_INPUT_ID, 0, "INPUT_ID", InputID, "ID", "") DefNode(GeometryNode, GEO_NODE_INPUT_INDEX, 0, "INDEX", InputIndex, "Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL_INDEX, 0, "INPUT_MATERIAL_INDEX", InputMaterialIndex, "Material Index", "") DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "") +DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_ANGLE, 0, "MESH_EDGE_ANGLE", InputMeshEdgeAngle, "Edge Angle", "") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, 0, "MESH_EDGE_NEIGHBORS", InputMeshEdgeNeighbors, "Edge Neighbors", "") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_EDGE_VERTICES, 0, "MESH_EDGE_VERTICES", InputMeshEdgeVertices, "Edge Vertices", "") DefNode(GeometryNode, GEO_NODE_INPUT_MESH_FACE_AREA, 0, "MESH_FACE_AREA", InputMeshFaceArea, "Face Area", "") diff --git a/source/blender/nodes/composite/CMakeLists.txt b/source/blender/nodes/composite/CMakeLists.txt new file mode 100644 index 00000000000..e9fc24bbbee --- /dev/null +++ b/source/blender/nodes/composite/CMakeLists.txt @@ -0,0 +1,150 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2021, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../editors/include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../depsgraph + ../../imbuf + ../../makesdna + ../../makesrna + ../../render + ../../windowmanager + ../../../../intern/guardedalloc +) + + +set(SRC + nodes/node_composite_alphaOver.cc + nodes/node_composite_antialiasing.cc + nodes/node_composite_bilateralblur.cc + nodes/node_composite_blur.cc + nodes/node_composite_bokehblur.cc + nodes/node_composite_bokehimage.cc + nodes/node_composite_boxmask.cc + nodes/node_composite_brightness.cc + nodes/node_composite_channelMatte.cc + nodes/node_composite_chromaMatte.cc + nodes/node_composite_colorMatte.cc + nodes/node_composite_colorSpill.cc + nodes/node_composite_colorbalance.cc + nodes/node_composite_colorcorrection.cc + nodes/node_composite_common.cc + nodes/node_composite_composite.cc + nodes/node_composite_cornerpin.cc + nodes/node_composite_crop.cc + nodes/node_composite_cryptomatte.cc + nodes/node_composite_curves.cc + nodes/node_composite_defocus.cc + nodes/node_composite_denoise.cc + nodes/node_composite_despeckle.cc + nodes/node_composite_diffMatte.cc + nodes/node_composite_dilate.cc + nodes/node_composite_directionalblur.cc + nodes/node_composite_displace.cc + nodes/node_composite_distanceMatte.cc + nodes/node_composite_doubleEdgeMask.cc + nodes/node_composite_ellipsemask.cc + nodes/node_composite_exposure.cc + nodes/node_composite_filter.cc + nodes/node_composite_flip.cc + nodes/node_composite_gamma.cc + nodes/node_composite_glare.cc + nodes/node_composite_hueSatVal.cc + nodes/node_composite_huecorrect.cc + nodes/node_composite_idMask.cc + nodes/node_composite_image.cc + nodes/node_composite_inpaint.cc + nodes/node_composite_invert.cc + nodes/node_composite_keying.cc + nodes/node_composite_keyingscreen.cc + nodes/node_composite_lensdist.cc + nodes/node_composite_levels.cc + nodes/node_composite_lummaMatte.cc + nodes/node_composite_mapRange.cc + nodes/node_composite_mapUV.cc + nodes/node_composite_mapValue.cc + nodes/node_composite_mask.cc + nodes/node_composite_math.cc + nodes/node_composite_mixrgb.cc + nodes/node_composite_movieclip.cc + nodes/node_composite_moviedistortion.cc + nodes/node_composite_normal.cc + nodes/node_composite_normalize.cc + nodes/node_composite_outputFile.cc + nodes/node_composite_pixelate.cc + nodes/node_composite_planetrackdeform.cc + nodes/node_composite_posterize.cc + nodes/node_composite_premulkey.cc + nodes/node_composite_rgb.cc + nodes/node_composite_rotate.cc + nodes/node_composite_scale.cc + nodes/node_composite_sepcombHSVA.cc + nodes/node_composite_sepcombRGBA.cc + nodes/node_composite_sepcombYCCA.cc + nodes/node_composite_sepcombYUVA.cc + nodes/node_composite_setalpha.cc + nodes/node_composite_splitViewer.cc + nodes/node_composite_stabilize2d.cc + nodes/node_composite_sunbeams.cc + nodes/node_composite_switch.cc + nodes/node_composite_switchview.cc + nodes/node_composite_texture.cc + nodes/node_composite_tonemap.cc + nodes/node_composite_trackpos.cc + nodes/node_composite_transform.cc + nodes/node_composite_translate.cc + nodes/node_composite_valToRgb.cc + nodes/node_composite_value.cc + nodes/node_composite_vecBlur.cc + nodes/node_composite_viewer.cc + nodes/node_composite_zcombine.cc + + node_composite_tree.cc + node_composite_util.cc + + node_composite_util.hh +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_IMAGE_OPENEXR) + add_definitions(-DWITH_OPENEXR) +endif() + +if(WITH_COMPOSITOR) + list(APPEND INC + ../../compositor + ) + add_definitions(-DWITH_COMPOSITOR) +endif() + +if(WITH_OPENIMAGEDENOISE) + add_definitions(-DWITH_OPENIMAGEDENOISE) +endif() + +blender_add_lib(bf_nodes_composite "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/composite/node_composite_tree.cc b/source/blender/nodes/composite/node_composite_tree.cc index 1326c9edab1..08dbd4ad6f0 100644 --- a/source/blender/nodes/composite/node_composite_tree.cc +++ b/source/blender/nodes/composite/node_composite_tree.cc @@ -33,8 +33,11 @@ #include "BKE_global.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_tracking.h" +#include "UI_resources.h" + #include "node_common.h" #include "node_util.h" @@ -117,29 +120,11 @@ static void localize(bNodeTree *localtree, bNodeTree *ntree) } } - bNodeSocket *output_sock = (bNodeSocket *)node->outputs.first; - bNodeSocket *local_output_sock = (bNodeSocket *)local_node->outputs.first; - while (output_sock != nullptr) { - local_output_sock->cache = output_sock->cache; - output_sock->cache = nullptr; - /* This is actually link to original: someone was just lazy enough and tried to save few - * bytes in the cost of readability. */ - local_output_sock->new_sock = output_sock; - - output_sock = output_sock->next; - local_output_sock = local_output_sock->next; - } - node = node->next; local_node = local_node->next; } } -static void local_sync(bNodeTree *localtree, bNodeTree *ntree) -{ - BKE_node_preview_sync_tree(ntree, localtree); -} - static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) { bNode *lnode; @@ -149,11 +134,11 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) BKE_node_preview_merge_tree(ntree, localtree, true); for (lnode = (bNode *)localtree->nodes.first; lnode; lnode = lnode->next) { - if (ntreeNodeExists(ntree, lnode->new_node)) { + if (bNode *orig_node = nodeFindNodebyName(ntree, lnode->name)) { if (ELEM(lnode->type, CMP_NODE_VIEWER, CMP_NODE_SPLITVIEWER)) { if (lnode->id && (lnode->flag & NODE_DO_OUTPUT)) { /* image_merge does sanity check for pointers */ - BKE_image_merge(bmain, (Image *)lnode->new_node->id, (Image *)lnode->id); + BKE_image_merge(bmain, (Image *)orig_node->id, (Image *)lnode->id); } } else if (lnode->type == CMP_NODE_MOVIEDISTORTION) { @@ -161,20 +146,19 @@ static void local_merge(Main *bmain, bNodeTree *localtree, bNodeTree *ntree) * and to achieve much better performance on further calls this context should be * copied back to original node */ if (lnode->storage) { - if (lnode->new_node->storage) { - BKE_tracking_distortion_free((MovieDistortion *)lnode->new_node->storage); + if (orig_node->storage) { + BKE_tracking_distortion_free((MovieDistortion *)orig_node->storage); } - lnode->new_node->storage = BKE_tracking_distortion_copy( - (MovieDistortion *)lnode->storage); + orig_node->storage = BKE_tracking_distortion_copy((MovieDistortion *)lnode->storage); } } for (lsock = (bNodeSocket *)lnode->outputs.first; lsock; lsock = lsock->next) { - if (ntreeOutputExists(lnode->new_node, lsock->new_sock)) { - lsock->new_sock->cache = lsock->cache; + if (bNodeSocket *orig_socket = nodeFindSocket(orig_node, SOCK_OUT, lsock->identifier)) { + orig_socket->cache = lsock->cache; lsock->cache = nullptr; - lsock->new_sock = nullptr; + orig_socket = nullptr; } } } @@ -186,11 +170,6 @@ static void update(bNodeTree *ntree) ntreeSetOutput(ntree); ntree_update_reroute_nodes(ntree); - - if (ntree->update & NTREE_UPDATE_NODES) { - /* clean up preview cache, in case nodes have been removed */ - BKE_node_preview_remove_unused(ntree); - } } static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode) @@ -214,20 +193,18 @@ bNodeTreeType *ntreeType_Composite; void register_node_tree_type_cmp() { - bNodeTreeType *tt = ntreeType_Composite = (bNodeTreeType *)MEM_callocN( - sizeof(bNodeTreeType), "compositor node tree type"); + bNodeTreeType *tt = ntreeType_Composite = MEM_cnew<bNodeTreeType>(__func__); tt->type = NTREE_COMPOSIT; strcpy(tt->idname, "CompositorNodeTree"); strcpy(tt->ui_name, N_("Compositor")); - tt->ui_icon = 0; /* Defined in `drawnode.c`. */ + tt->ui_icon = ICON_NODE_COMPOSITING; strcpy(tt->ui_description, N_("Compositing nodes")); tt->free_cache = free_cache; tt->free_node_cache = free_node_cache; tt->foreach_nodeclass = foreach_nodeclass; tt->localize = localize; - tt->local_sync = local_sync; tt->local_merge = local_merge; tt->update = update; tt->get_from_context = composite_get_from_context; @@ -301,14 +278,15 @@ void ntreeCompositTagRender(Scene *scene) if (sce_iter->nodetree) { LISTBASE_FOREACH (bNode *, node, &sce_iter->nodetree->nodes) { if (node->id == (ID *)scene || node->type == CMP_NODE_COMPOSITE) { - nodeUpdate(sce_iter->nodetree, node); + BKE_ntree_update_tag_node_property(sce_iter->nodetree, node); } else if (node->type == CMP_NODE_TEXTURE) /* uses scene size_x/size_y */ { - nodeUpdate(sce_iter->nodetree, node); + BKE_ntree_update_tag_node_property(sce_iter->nodetree, node); } } } } + BKE_ntree_update_main(G_MAIN, nullptr); } /* XXX after render animation system gets a refresh, this call allows composite to end clean */ diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc index 1262dfad11f..1f892c1c9e2 100644 --- a/source/blender/nodes/composite/node_composite_util.cc +++ b/source/blender/nodes/composite/node_composite_util.cc @@ -47,9 +47,9 @@ void cmp_node_update_default(bNodeTree *UNUSED(ntree), bNode *node) node->need_exec = 1; } -void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) +void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { - node_type_base(ntype, type, name, nclass, flag); + node_type_base(ntype, type, name, nclass); ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; diff --git a/source/blender/nodes/composite/node_composite_util.hh b/source/blender/nodes/composite/node_composite_util.hh index 04708d0d854..65dbc2065ef 100644 --- a/source/blender/nodes/composite/node_composite_util.hh +++ b/source/blender/nodes/composite/node_composite_util.hh @@ -52,5 +52,4 @@ bool cmp_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); void cmp_node_update_default(struct bNodeTree *ntree, struct bNode *node); -void cmp_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void cmp_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc index 5e6d59edfd5..82ef5df8403 100644 --- a/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc +++ b/source/blender/nodes/composite/nodes/node_composite_alphaOver.cc @@ -42,7 +42,7 @@ static void cmp_node_alphaover_declare(NodeDeclarationBuilder &b) static void node_alphaover_init(bNodeTree *UNUSED(ntree), bNode *node) { - node->storage = MEM_callocN(sizeof(NodeTwoFloats), "NodeTwoFloats"); + node->storage = MEM_cnew<NodeTwoFloats>(__func__); } static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -58,7 +58,7 @@ void register_node_type_cmp_alphaover() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_ALPHAOVER, "Alpha Over", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_alphaover_declare; ntype.draw_buttons = node_composit_buts_alphaover; node_type_init(&ntype, node_alphaover_init); diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc index 02b2652ed6a..b42b219ced9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc +++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.cc @@ -42,8 +42,7 @@ static void cmp_node_antialiasing_declare(NodeDeclarationBuilder &b) static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAntiAliasingData *data = (NodeAntiAliasingData *)MEM_callocN(sizeof(NodeAntiAliasingData), - "node antialiasing data"); + NodeAntiAliasingData *data = MEM_cnew<NodeAntiAliasingData>(__func__); data->threshold = CMP_DEFAULT_SMAA_THRESHOLD; data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT; @@ -67,10 +66,10 @@ void register_node_type_cmp_antialiasing() { static bNodeType ntype; - cmp_node_type_base( - &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_antialiasing_declare; ntype.draw_buttons = node_composit_buts_antialiasing; + ntype.flag |= NODE_PREVIEW; node_type_size(&ntype, 170, 140, 200); node_type_init(&ntype, node_composit_init_antialiasing); node_type_storage( diff --git a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc index 3f107a13a44..2b4030935a0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bilateralblur.cc @@ -41,8 +41,7 @@ static void cmp_node_bilateralblur_declare(NodeDeclarationBuilder &b) static void node_composit_init_bilateralblur(bNodeTree *UNUSED(ntree), bNode *node) { - NodeBilateralBlurData *nbbd = (NodeBilateralBlurData *)MEM_callocN(sizeof(NodeBilateralBlurData), - "node bilateral blur data"); + NodeBilateralBlurData *nbbd = MEM_cnew<NodeBilateralBlurData>(__func__); node->storage = nbbd; nbbd->iter = 1; nbbd->sigma_color = 0.3; @@ -65,7 +64,7 @@ void register_node_type_cmp_bilateralblur() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_BILATERALBLUR, "Bilateral Blur", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_bilateralblur_declare; ntype.draw_buttons = node_composit_buts_bilateralblur; node_type_init(&ntype, node_composit_init_bilateralblur); diff --git a/source/blender/nodes/composite/nodes/node_composite_blur.cc b/source/blender/nodes/composite/nodes/node_composite_blur.cc index bcc8c786ae5..b7904ffdafe 100644 --- a/source/blender/nodes/composite/nodes/node_composite_blur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_blur.cc @@ -44,7 +44,7 @@ static void cmp_node_blur_declare(NodeDeclarationBuilder &b) static void node_composit_init_blur(bNodeTree *UNUSED(ntree), bNode *node) { - NodeBlurData *data = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data"); + NodeBlurData *data = MEM_cnew<NodeBlurData>(__func__); data->filtertype = R_FILTER_GAUSS; node->storage = data; } @@ -94,9 +94,10 @@ void register_node_type_cmp_blur() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_BLUR, "Blur", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_blur_declare; ntype.draw_buttons = node_composit_buts_blur; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_blur); node_type_storage( &ntype, "NodeBlurData", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc index d0659f6a51e..bffaceee067 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehblur.cc @@ -25,7 +25,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** BLUR ******************** */ @@ -60,7 +60,7 @@ void register_node_type_cmp_bokehblur() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_BOKEHBLUR, "Bokeh Blur", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_bokehblur_declare; ntype.draw_buttons = node_composit_buts_bokehblur; node_type_init(&ntype, node_composit_init_bokehblur); diff --git a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc index 8817a07a422..93a00cb210d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc +++ b/source/blender/nodes/composite/nodes/node_composite_bokehimage.cc @@ -24,7 +24,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** Bokeh image Tools ******************** */ @@ -39,7 +39,7 @@ static void cmp_node_bokehimage_declare(NodeDeclarationBuilder &b) static void node_composit_init_bokehimage(bNodeTree *UNUSED(ntree), bNode *node) { - NodeBokehImage *data = (NodeBokehImage *)MEM_callocN(sizeof(NodeBokehImage), "NodeBokehImage"); + NodeBokehImage *data = MEM_cnew<NodeBokehImage>(__func__); data->angle = 0.0f; data->flaps = 5; data->rounding = 0.0f; @@ -67,9 +67,10 @@ void register_node_type_cmp_bokehimage() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_BOKEHIMAGE, "Bokeh Image", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_bokehimage_declare; ntype.draw_buttons = node_composit_buts_bokehimage; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_bokehimage); node_type_storage( &ntype, "NodeBokehImage", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc index 40859922154..68c79d89435 100644 --- a/source/blender/nodes/composite/nodes/node_composite_boxmask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_boxmask.cc @@ -24,7 +24,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** SCALAR MATH ******************** */ @@ -41,7 +41,7 @@ static void cmp_node_boxmask_declare(NodeDeclarationBuilder &b) static void node_composit_init_boxmask(bNodeTree *UNUSED(ntree), bNode *node) { - NodeBoxMask *data = (NodeBoxMask *)MEM_callocN(sizeof(NodeBoxMask), "NodeBoxMask"); + NodeBoxMask *data = MEM_cnew<NodeBoxMask>(__func__); data->x = 0.5; data->y = 0.5; data->width = 0.2; @@ -70,7 +70,7 @@ void register_node_type_cmp_boxmask() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_MASK_BOX, "Box Mask", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_boxmask_declare; ntype.draw_buttons = node_composit_buts_boxmask; node_type_init(&ntype, node_composit_init_boxmask); diff --git a/source/blender/nodes/composite/nodes/node_composite_brightness.cc b/source/blender/nodes/composite/nodes/node_composite_brightness.cc index ca03a9b4fbf..ea1684a6ca7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_brightness.cc +++ b/source/blender/nodes/composite/nodes/node_composite_brightness.cc @@ -56,7 +56,7 @@ void register_node_type_cmp_brightcontrast() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_brightcontrast_declare; ntype.draw_buttons = node_composit_buts_brightcontrast; node_type_init(&ntype, node_composit_init_brightcontrast); diff --git a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc index 1b4be78c71b..9d3bc97f2dc 100644 --- a/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_channelMatte.cc @@ -43,7 +43,7 @@ static void cmp_node_channel_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_channel_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->t1 = 1.0f; c->t2 = 0.0f; @@ -101,10 +101,10 @@ void register_node_type_cmp_channel_matte() { static bNodeType ntype; - cmp_node_type_base( - &ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_CHANNEL_MATTE, "Channel Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_channel_matte_declare; ntype.draw_buttons = node_composit_buts_channel_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_channel_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc index a7e3a1c148f..be27f747af0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_chromaMatte.cc @@ -42,7 +42,7 @@ static void cmp_node_chroma_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_chroma_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->t1 = DEG2RADF(30.0f); c->t2 = DEG2RADF(10.0f); @@ -71,9 +71,10 @@ void register_node_type_cmp_chroma_matte() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_CHROMA_MATTE, "Chroma Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_chroma_matte_declare; ntype.draw_buttons = node_composit_buts_chroma_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_chroma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc index 367b046f3f6..58040c2076b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorMatte.cc @@ -42,7 +42,7 @@ static void cmp_node_color_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_color_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node color"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->t1 = 0.01f; c->t2 = 0.1f; @@ -72,9 +72,10 @@ void register_node_type_cmp_color_matte() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_COLOR_MATTE, "Color Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_color_matte_declare; ntype.draw_buttons = node_composit_buts_color_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_color_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc index e136041cf6e..187b1dfdfc5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorSpill.cc @@ -43,7 +43,7 @@ static void cmp_node_color_spill_declare(NodeDeclarationBuilder &b) static void node_composit_init_color_spill(bNodeTree *UNUSED(ntree), bNode *node) { - NodeColorspill *ncs = (NodeColorspill *)MEM_callocN(sizeof(NodeColorspill), "node colorspill"); + NodeColorspill *ncs = MEM_cnew<NodeColorspill>(__func__); node->storage = ncs; node->custom1 = 2; /* green channel */ node->custom2 = 0; /* simple limit algorithm */ @@ -102,7 +102,7 @@ void register_node_type_cmp_color_spill() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_COLOR_SPILL, "Color Spill", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_color_spill_declare; ntype.draw_buttons = node_composit_buts_color_spill; node_type_init(&ntype, node_composit_init_color_spill); diff --git a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc index a35b3d813e6..bddd702bcca 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorbalance.cc @@ -71,8 +71,7 @@ void ntreeCompositColorBalanceSyncFromCDL(bNodeTree *UNUSED(ntree), bNode *node) static void node_composit_init_colorbalance(bNodeTree *UNUSED(ntree), bNode *node) { - NodeColorBalance *n = (NodeColorBalance *)MEM_callocN(sizeof(NodeColorBalance), - "node colorbalance"); + NodeColorBalance *n = MEM_cnew<NodeColorBalance>(__func__); n->lift[0] = n->lift[1] = n->lift[2] = 1.0f; n->gamma[0] = n->gamma[1] = n->gamma[2] = 1.0f; @@ -162,7 +161,7 @@ void register_node_type_cmp_colorbalance() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COLORBALANCE, "Color Balance", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_colorbalance_declare; ntype.draw_buttons = node_composit_buts_colorbalance; ntype.draw_buttons_ex = node_composit_buts_colorbalance_ex; diff --git a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc index e3bba3b6c4f..16d1ad90757 100644 --- a/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc +++ b/source/blender/nodes/composite/nodes/node_composite_colorcorrection.cc @@ -41,8 +41,7 @@ static void cmp_node_colorcorrection_declare(NodeDeclarationBuilder &b) static void node_composit_init_colorcorrection(bNodeTree *UNUSED(ntree), bNode *node) { - NodeColorCorrection *n = (NodeColorCorrection *)MEM_callocN(sizeof(NodeColorCorrection), - "node colorcorrection"); + NodeColorCorrection *n = MEM_cnew<NodeColorCorrection>(__func__); n->startmidtones = 0.2f; n->endmidtones = 0.7f; n->master.contrast = 1.0f; @@ -289,7 +288,7 @@ void register_node_type_cmp_colorcorrection() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_COLORCORRECTION, "Color Correction", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_colorcorrection_declare; ntype.draw_buttons = node_composit_buts_colorcorrection; ntype.draw_buttons_ex = node_composit_buts_colorcorrection_ex; diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index aa81cecc3e2..36678baafa5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -38,7 +38,7 @@ void register_node_type_cmp_group() /* NOTE: Cannot use sh_node_type_base for node group, because it would map the node type * to the shared NODE_GROUP integer type id. */ - node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP, 0); + node_type_base_custom(&ntype, "CompositorNodeGroup", "Group", NODE_CLASS_GROUP); ntype.type = NODE_GROUP; ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index 547e5123579..5f694d0738e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -48,9 +48,10 @@ void register_node_type_cmp_composite() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT); ntype.declare = blender::nodes::cmp_node_composite_declare; ntype.draw_buttons = node_composit_buts_composite; + ntype.flag |= NODE_PREVIEW; ntype.no_muting = true; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc index 2e7a87a576d..2bd188e4182 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cornerpin.cc @@ -54,7 +54,7 @@ void register_node_type_cmp_cornerpin() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_CORNERPIN, "Corner Pin", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_cornerpin_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_crop.cc b/source/blender/nodes/composite/nodes/node_composite_crop.cc index fa33caa4c0e..2969e0564b1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_crop.cc +++ b/source/blender/nodes/composite/nodes/node_composite_crop.cc @@ -42,7 +42,7 @@ static void cmp_node_crop_declare(NodeDeclarationBuilder &b) static void node_composit_init_crop(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTwoXYs *nxy = (NodeTwoXYs *)MEM_callocN(sizeof(NodeTwoXYs), "node xy data"); + NodeTwoXYs *nxy = MEM_cnew<NodeTwoXYs>(__func__); node->storage = nxy; nxy->x1 = 0; nxy->x2 = 0; @@ -76,7 +76,7 @@ void register_node_type_cmp_crop() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_CROP, "Crop", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_crop_declare; ntype.draw_buttons = node_composit_buts_crop; node_type_init(&ntype, node_composit_init_crop); diff --git a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc index 65b1f6799d7..c059a2883f6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_cryptomatte.cc @@ -136,8 +136,7 @@ static void cryptomatte_add(const Scene &scene, return; } - CryptomatteEntry *entry = static_cast<CryptomatteEntry *>( - MEM_callocN(sizeof(CryptomatteEntry), __func__)); + CryptomatteEntry *entry = MEM_cnew<CryptomatteEntry>(__func__); entry->encoded_hash = encoded_hash; blender::bke::cryptomatte::CryptomatteSessionPtr session = cryptomatte_init_from_node( scene, node, true); @@ -199,8 +198,7 @@ void ntreeCompositCryptomatteUpdateLayerNames(const Scene *scene, bNode *node) if (session) { for (blender::StringRef layer_name : blender::bke::cryptomatte::BKE_cryptomatte_layer_names_get(*session)) { - CryptomatteLayer *layer = static_cast<CryptomatteLayer *>( - MEM_callocN(sizeof(CryptomatteLayer), __func__)); + CryptomatteLayer *layer = MEM_cnew<CryptomatteLayer>(__func__); layer_name.copy(layer->name); BLI_addtail(&n->runtime.layers, layer); } @@ -245,8 +243,7 @@ CryptomatteSession *ntreeCompositCryptomatteSession(const Scene *scene, bNode *n static void node_init_cryptomatte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeCryptomatte *user = static_cast<NodeCryptomatte *>( - MEM_callocN(sizeof(NodeCryptomatte), __func__)); + NodeCryptomatte *user = MEM_cnew<NodeCryptomatte>(__func__); node->storage = user; } @@ -312,7 +309,7 @@ void register_node_type_cmp_cryptomatte() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE, "Cryptomatte", NODE_CLASS_MATTE); node_type_socket_templates(&ntype, cmp_node_cryptomatte_in, cmp_node_cryptomatte_out); node_type_size(&ntype, 240, 100, 700); node_type_init(&ntype, node_init_cryptomatte); @@ -369,7 +366,7 @@ void register_node_type_cmp_cryptomatte_legacy() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_CRYPTOMATTE_LEGACY, "Cryptomatte", NODE_CLASS_MATTE); node_type_socket_templates(&ntype, nullptr, cmp_node_cryptomatte_out); node_type_init(&ntype, node_init_cryptomatte_legacy); node_type_storage(&ntype, "NodeCryptomatte", node_free_cryptomatte, node_copy_cryptomatte); diff --git a/source/blender/nodes/composite/nodes/node_composite_curves.cc b/source/blender/nodes/composite/nodes/node_composite_curves.cc index 518b57dc405..6be8a04a6e1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_curves.cc +++ b/source/blender/nodes/composite/nodes/node_composite_curves.cc @@ -49,9 +49,9 @@ void register_node_type_cmp_curve_time() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_TIME, "Time", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_time_declare; - node_type_size(&ntype, 140, 100, 320); + node_type_size(&ntype, 200, 140, 320); node_type_init(&ntype, node_composit_init_curves_time); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); @@ -84,7 +84,7 @@ void register_node_type_cmp_curve_vec() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR); ntype.declare = blender::nodes::cmp_node_curve_vec_declare; ntype.draw_buttons = node_buts_curvevec; node_type_size(&ntype, 200, 140, 320); @@ -119,7 +119,7 @@ void register_node_type_cmp_curve_rgb() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_rgbcurves_declare; node_type_size(&ntype, 200, 140, 320); node_type_init(&ntype, node_composit_init_curve_rgb); diff --git a/source/blender/nodes/composite/nodes/node_composite_defocus.cc b/source/blender/nodes/composite/nodes/node_composite_defocus.cc index 0ee8a8da1e8..cfe377f72f1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_defocus.cc +++ b/source/blender/nodes/composite/nodes/node_composite_defocus.cc @@ -46,7 +46,7 @@ static void cmp_node_defocus_declare(NodeDeclarationBuilder &b) static void node_composit_init_defocus(bNodeTree *UNUSED(ntree), bNode *node) { /* defocus node */ - NodeDefocus *nbd = (NodeDefocus *)MEM_callocN(sizeof(NodeDefocus), "node defocus data"); + NodeDefocus *nbd = MEM_cnew<NodeDefocus>(__func__); nbd->bktype = 0; nbd->rotation = 0.0f; nbd->preview = 1; @@ -103,7 +103,7 @@ void register_node_type_cmp_defocus() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_DEFOCUS, "Defocus", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_defocus_declare; ntype.draw_buttons = node_composit_buts_defocus; node_type_init(&ntype, node_composit_init_defocus); diff --git a/source/blender/nodes/composite/nodes/node_composite_denoise.cc b/source/blender/nodes/composite/nodes/node_composite_denoise.cc index f1e5388a7a3..8dce28b4ac0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_denoise.cc +++ b/source/blender/nodes/composite/nodes/node_composite_denoise.cc @@ -23,6 +23,8 @@ * \ingroup cmpnodes */ +#include "BLI_system.h" + #include "UI_interface.h" #include "UI_resources.h" @@ -46,7 +48,7 @@ static void cmp_node_denoise_declare(NodeDeclarationBuilder &b) static void node_composit_init_denonise(bNodeTree *UNUSED(ntree), bNode *node) { - NodeDenoise *ndg = (NodeDenoise *)MEM_callocN(sizeof(NodeDenoise), "node denoise data"); + NodeDenoise *ndg = MEM_cnew<NodeDenoise>(__func__); ndg->hdr = true; ndg->prefilter = CMP_NODE_DENOISE_PREFILTER_ACCURATE; node->storage = ndg; @@ -74,7 +76,7 @@ void register_node_type_cmp_denoise() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_DENOISE, "Denoise", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_denoise_declare; ntype.draw_buttons = node_composit_buts_denoise; node_type_init(&ntype, node_composit_init_denonise); diff --git a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc index 411bad14f25..3555bd6a693 100644 --- a/source/blender/nodes/composite/nodes/node_composite_despeckle.cc +++ b/source/blender/nodes/composite/nodes/node_composite_despeckle.cc @@ -58,9 +58,10 @@ void register_node_type_cmp_despeckle() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_DESPECKLE, "Despeckle", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_despeckle_declare; ntype.draw_buttons = node_composit_buts_despeckle; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_despeckle); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc index a9e3258c8fb..2bc171161be 100644 --- a/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_diffMatte.cc @@ -42,7 +42,7 @@ static void cmp_node_diff_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_diff_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->t1 = 0.1f; c->t2 = 0.1f; @@ -62,10 +62,10 @@ void register_node_type_cmp_diff_matte() { static bNodeType ntype; - cmp_node_type_base( - &ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_DIFF_MATTE, "Difference Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_diff_matte_declare; ntype.draw_buttons = node_composit_buts_diff_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_diff_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_dilate.cc b/source/blender/nodes/composite/nodes/node_composite_dilate.cc index 1af2bb0433b..867fc7f828f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_dilate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_dilate.cc @@ -42,8 +42,7 @@ static void cmp_node_dilate_declare(NodeDeclarationBuilder &b) static void node_composit_init_dilateerode(bNodeTree *UNUSED(ntree), bNode *node) { - NodeDilateErode *data = (NodeDilateErode *)MEM_callocN(sizeof(NodeDilateErode), - "NodeDilateErode"); + NodeDilateErode *data = MEM_cnew<NodeDilateErode>(__func__); data->falloff = PROP_SMOOTH; node->storage = data; } @@ -66,7 +65,7 @@ void register_node_type_cmp_dilateerode() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_DILATEERODE, "Dilate/Erode", NODE_CLASS_OP_FILTER); ntype.draw_buttons = node_composit_buts_dilateerode; ntype.declare = blender::nodes::cmp_node_dilate_declare; node_type_init(&ntype, node_composit_init_dilateerode); diff --git a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc index 36b130d55a4..8f39a25cf77 100644 --- a/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_directionalblur.cc @@ -38,7 +38,7 @@ static void cmp_node_directional_blur_declare(NodeDeclarationBuilder &b) static void node_composit_init_dblur(bNodeTree *UNUSED(ntree), bNode *node) { - NodeDBlurData *ndbd = (NodeDBlurData *)MEM_callocN(sizeof(NodeDBlurData), "node dblur data"); + NodeDBlurData *ndbd = MEM_cnew<NodeDBlurData>(__func__); node->storage = ndbd; ndbd->iter = 1; ndbd->center_x = 0.5; @@ -73,7 +73,7 @@ void register_node_type_cmp_dblur() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_DBLUR, "Directional Blur", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_directional_blur_declare; ntype.draw_buttons = node_composit_buts_dblur; node_type_init(&ntype, node_composit_init_dblur); diff --git a/source/blender/nodes/composite/nodes/node_composite_displace.cc b/source/blender/nodes/composite/nodes/node_composite_displace.cc index 0137c1f7da8..dd53b3f46a5 100644 --- a/source/blender/nodes/composite/nodes/node_composite_displace.cc +++ b/source/blender/nodes/composite/nodes/node_composite_displace.cc @@ -46,7 +46,7 @@ void register_node_type_cmp_displace() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_DISPLACE, "Displace", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_displace_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc index 47a48ed141e..2b6d5068d74 100644 --- a/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_distanceMatte.cc @@ -42,7 +42,7 @@ static void cmp_node_distance_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_distance_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->channel = 1; c->t1 = 0.1f; @@ -70,9 +70,10 @@ void register_node_type_cmp_distance_matte() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_DIST_MATTE, "Distance Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_distance_matte_declare; ntype.draw_buttons = node_composit_buts_distance_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_distance_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc index 4fde539e6fb..1a0d268941e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_doubleEdgeMask.cc @@ -57,7 +57,7 @@ void register_node_type_cmp_doubleedgemask() { static bNodeType ntype; /* Allocate a node type data structure. */ - cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_DOUBLEEDGEMASK, "Double Edge Mask", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_double_edge_mask_declare; ntype.draw_buttons = node_composit_buts_double_edge_mask; diff --git a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc index 8eb89e53790..1ae5bd9644c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_ellipsemask.cc @@ -24,7 +24,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** SCALAR MATH ******************** */ @@ -41,8 +41,7 @@ static void cmp_node_ellipsemask_declare(NodeDeclarationBuilder &b) static void node_composit_init_ellipsemask(bNodeTree *UNUSED(ntree), bNode *node) { - NodeEllipseMask *data = (NodeEllipseMask *)MEM_callocN(sizeof(NodeEllipseMask), - "NodeEllipseMask"); + NodeEllipseMask *data = MEM_cnew<NodeEllipseMask>(__func__); data->x = 0.5; data->y = 0.5; data->width = 0.2; @@ -69,7 +68,7 @@ void register_node_type_cmp_ellipsemask() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_MASK_ELLIPSE, "Ellipse Mask", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_ellipsemask_declare; ntype.draw_buttons = node_composit_buts_ellipsemask; node_type_size(&ntype, 260, 110, 320); diff --git a/source/blender/nodes/composite/nodes/node_composite_exposure.cc b/source/blender/nodes/composite/nodes/node_composite_exposure.cc index b696db41a3c..bee172b24c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_exposure.cc +++ b/source/blender/nodes/composite/nodes/node_composite_exposure.cc @@ -40,7 +40,7 @@ void register_node_type_cmp_exposure() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_EXPOSURE, "Exposure", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_exposure_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_filter.cc b/source/blender/nodes/composite/nodes/node_composite_filter.cc index 3671d502539..cc348af585e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_filter.cc +++ b/source/blender/nodes/composite/nodes/node_composite_filter.cc @@ -48,10 +48,11 @@ void register_node_type_cmp_filter() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_FILTER, "Filter", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_filter_declare; ntype.draw_buttons = node_composit_buts_filter; ntype.labelfunc = node_filter_label; + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_flip.cc b/source/blender/nodes/composite/nodes/node_composite_flip.cc index 38bc0f8b855..1087254ac7a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_flip.cc +++ b/source/blender/nodes/composite/nodes/node_composite_flip.cc @@ -47,7 +47,7 @@ void register_node_type_cmp_flip() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_FLIP, "Flip", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_flip_declare; ntype.draw_buttons = node_composit_buts_flip; diff --git a/source/blender/nodes/composite/nodes/node_composite_gamma.cc b/source/blender/nodes/composite/nodes/node_composite_gamma.cc index 438770865ae..2ad2b955b9d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_gamma.cc +++ b/source/blender/nodes/composite/nodes/node_composite_gamma.cc @@ -44,7 +44,7 @@ void register_node_type_cmp_gamma() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_gamma_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_glare.cc b/source/blender/nodes/composite/nodes/node_composite_glare.cc index adaf22395c3..89701b3551a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_glare.cc +++ b/source/blender/nodes/composite/nodes/node_composite_glare.cc @@ -40,7 +40,7 @@ static void cmp_node_glare_declare(NodeDeclarationBuilder &b) static void node_composit_init_glare(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGlare *ndg = (NodeGlare *)MEM_callocN(sizeof(NodeGlare), "node glare data"); + NodeGlare *ndg = MEM_cnew<NodeGlare>(__func__); ndg->quality = 1; ndg->type = 2; ndg->iter = 3; @@ -97,7 +97,7 @@ void register_node_type_cmp_glare() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_GLARE, "Glare", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_glare_declare; ntype.draw_buttons = node_composit_buts_glare; node_type_init(&ntype, node_composit_init_glare); diff --git a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc index 47fbaa4d384..5453ee4fae4 100644 --- a/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_hueSatVal.cc @@ -51,7 +51,7 @@ void register_node_type_cmp_hue_sat() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_huesatval_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc index e78ba0c7f9c..a98e4cdd3ba 100644 --- a/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc +++ b/source/blender/nodes/composite/nodes/node_composite_huecorrect.cc @@ -55,7 +55,7 @@ void register_node_type_cmp_huecorrect() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_HUECORRECT, "Hue Correct", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_huecorrect_declare; node_type_size(&ntype, 320, 140, 500); node_type_init(&ntype, node_composit_init_huecorrect); diff --git a/source/blender/nodes/composite/nodes/node_composite_idMask.cc b/source/blender/nodes/composite/nodes/node_composite_idMask.cc index f5b8cb6c567..c898734e758 100644 --- a/source/blender/nodes/composite/nodes/node_composite_idMask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_idMask.cc @@ -48,7 +48,7 @@ void register_node_type_cmp_idmask() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_ID_MASK, "ID Mask", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_idmask_declare; ntype.draw_buttons = node_composit_buts_id_mask; diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 8e3cc9bcd95..bb87991630d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -108,8 +108,7 @@ static void cmp_node_image_add_pass_output(bNodeTree *ntree, sock = nodeAddStaticSocket(ntree, node, SOCK_OUT, type, PROP_NONE, name, name); } /* extra socket info */ - NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer), - "node image layer"); + NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__); sock->storage = sockdata; } @@ -412,7 +411,7 @@ static void cmp_node_image_update(bNodeTree *ntree, bNode *node) static void node_composit_init_image(bNodeTree *ntree, bNode *node) { - ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user"); + ImageUser *iuser = MEM_cnew<ImageUser>(__func__); node->storage = iuser; iuser->frames = 1; iuser->sfra = 1; @@ -452,11 +451,12 @@ void register_node_type_cmp_image() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_IMAGE, "Image", NODE_CLASS_INPUT); node_type_init(&ntype, node_composit_init_image); node_type_storage(&ntype, "ImageUser", node_composit_free_image, node_composit_copy_image); node_type_update(&ntype, cmp_node_image_update); ntype.labelfunc = node_image_label; + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } @@ -489,8 +489,7 @@ static void node_composit_init_rlayers(const bContext *C, PointerRNA *ptr) for (bNodeSocket *sock = (bNodeSocket *)node->outputs.first; sock; sock = sock->next, sock_index++) { - NodeImageLayer *sockdata = (NodeImageLayer *)MEM_callocN(sizeof(NodeImageLayer), - "node image layer"); + NodeImageLayer *sockdata = MEM_cnew<NodeImageLayer>(__func__); sock->storage = sockdata; BLI_strncpy(sockdata->pass_name, @@ -607,11 +606,12 @@ void register_node_type_cmp_rlayers() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_R_LAYERS, "Render Layers", NODE_CLASS_INPUT); node_type_socket_templates(&ntype, nullptr, cmp_node_rlayers_out); ntype.draw_buttons = node_composit_buts_viewlayers; ntype.initfunc_api = node_composit_init_rlayers; ntype.poll = node_composit_poll_rlayers; + ntype.flag |= NODE_PREVIEW; node_type_storage(&ntype, nullptr, node_composit_free_rlayers, node_composit_copy_rlayers); node_type_update(&ntype, cmp_node_rlayers_update); node_type_init(&ntype, node_cmp_rlayers_outputs); diff --git a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc index 976b1cd5a15..6776837f002 100644 --- a/source/blender/nodes/composite/nodes/node_composite_inpaint.cc +++ b/source/blender/nodes/composite/nodes/node_composite_inpaint.cc @@ -47,7 +47,7 @@ void register_node_type_cmp_inpaint() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_INPAINT, "Inpaint", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_inpaint_declare; ntype.draw_buttons = node_composit_buts_inpaint; diff --git a/source/blender/nodes/composite/nodes/node_composite_invert.cc b/source/blender/nodes/composite/nodes/node_composite_invert.cc index 2243608d5c3..c149e943c6d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_invert.cc +++ b/source/blender/nodes/composite/nodes/node_composite_invert.cc @@ -58,7 +58,7 @@ void register_node_type_cmp_invert() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_invert_declare; ntype.draw_buttons = node_composit_buts_invert; node_type_init(&ntype, node_composit_init_invert); diff --git a/source/blender/nodes/composite/nodes/node_composite_keying.cc b/source/blender/nodes/composite/nodes/node_composite_keying.cc index de1da3289f9..0d392f65f3f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keying.cc +++ b/source/blender/nodes/composite/nodes/node_composite_keying.cc @@ -51,7 +51,7 @@ static void cmp_node_keying_declare(NodeDeclarationBuilder &b) static void node_composit_init_keying(bNodeTree *UNUSED(ntree), bNode *node) { - NodeKeyingData *data = (NodeKeyingData *)MEM_callocN(sizeof(NodeKeyingData), "node keying data"); + NodeKeyingData *data = MEM_cnew<NodeKeyingData>(__func__); data->screen_balance = 0.5f; data->despill_balance = 0.5f; @@ -85,7 +85,7 @@ void register_node_type_cmp_keying() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_KEYING, "Keying", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_keying_declare; ntype.draw_buttons = node_composit_buts_keying; node_type_init(&ntype, node_composit_init_keying); diff --git a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc index d90fbe05211..785a904d1fa 100644 --- a/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc +++ b/source/blender/nodes/composite/nodes/node_composite_keyingscreen.cc @@ -46,8 +46,7 @@ static void cmp_node_keyingscreen_declare(NodeDeclarationBuilder &b) static void node_composit_init_keyingscreen(bNodeTree *UNUSED(ntree), bNode *node) { - NodeKeyingScreenData *data = (NodeKeyingScreenData *)MEM_callocN(sizeof(NodeKeyingScreenData), - "node keyingscreen data"); + NodeKeyingScreenData *data = MEM_cnew<NodeKeyingScreenData>(__func__); node->storage = data; } @@ -82,7 +81,7 @@ void register_node_type_cmp_keyingscreen() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE, 0); + cmp_node_type_base(&ntype, CMP_NODE_KEYINGSCREEN, "Keying Screen", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_keyingscreen_declare; ntype.draw_buttons = node_composit_buts_keyingscreen; node_type_init(&ntype, node_composit_init_keyingscreen); diff --git a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc index 11ee0cf0aa3..de8dea9947c 100644 --- a/source/blender/nodes/composite/nodes/node_composite_lensdist.cc +++ b/source/blender/nodes/composite/nodes/node_composite_lensdist.cc @@ -42,7 +42,7 @@ static void cmp_node_lensdist_declare(NodeDeclarationBuilder &b) static void node_composit_init_lensdist(bNodeTree *UNUSED(ntree), bNode *node) { - NodeLensDist *nld = (NodeLensDist *)MEM_callocN(sizeof(NodeLensDist), "node lensdist data"); + NodeLensDist *nld = MEM_cnew<NodeLensDist>(__func__); nld->jit = nld->proj = nld->fit = 0; node->storage = nld; } @@ -64,7 +64,7 @@ void register_node_type_cmp_lensdist() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_LENSDIST, "Lens Distortion", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_lensdist_declare; ntype.draw_buttons = node_composit_buts_lensdist; node_type_init(&ntype, node_composit_init_lensdist); diff --git a/source/blender/nodes/composite/nodes/node_composite_levels.cc b/source/blender/nodes/composite/nodes/node_composite_levels.cc index 891f79f9bf9..817de75ef55 100644 --- a/source/blender/nodes/composite/nodes/node_composite_levels.cc +++ b/source/blender/nodes/composite/nodes/node_composite_levels.cc @@ -53,9 +53,10 @@ void register_node_type_cmp_view_levels() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_VIEW_LEVELS, "Levels", NODE_CLASS_OUTPUT); ntype.declare = blender::nodes::cmp_node_levels_declare; ntype.draw_buttons = node_composit_buts_view_levels; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_view_levels); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc index f5193bd5df2..313bbf73955 100644 --- a/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc +++ b/source/blender/nodes/composite/nodes/node_composite_lummaMatte.cc @@ -41,7 +41,7 @@ static void cmp_node_luma_matte_declare(NodeDeclarationBuilder &b) static void node_composit_init_luma_matte(bNodeTree *UNUSED(ntree), bNode *node) { - NodeChroma *c = (NodeChroma *)MEM_callocN(sizeof(NodeChroma), "node chroma"); + NodeChroma *c = MEM_cnew<NodeChroma>(__func__); node->storage = c; c->t1 = 1.0f; c->t2 = 0.0f; @@ -62,9 +62,10 @@ void register_node_type_cmp_luma_matte() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_LUMA_MATTE, "Luminance Key", NODE_CLASS_MATTE); ntype.declare = blender::nodes::cmp_node_luma_matte_declare; ntype.draw_buttons = node_composit_buts_luma_matte; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_luma_matte); node_type_storage(&ntype, "NodeChroma", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc index 1ae80f68dfd..3d90c050fa7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapRange.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapRange.cc @@ -54,7 +54,7 @@ void register_node_type_cmp_map_range() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_MAP_RANGE, "Map Range", NODE_CLASS_OP_VECTOR); ntype.declare = blender::nodes::cmp_node_map_range_declare; ntype.draw_buttons = node_composit_buts_map_range; diff --git a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc index 71446e3a3c4..924a17d5c0b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapUV.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapUV.cc @@ -48,7 +48,7 @@ void register_node_type_cmp_mapuv() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_MAP_UV, "Map UV", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_map_uv_declare; ntype.draw_buttons = node_composit_buts_map_uv; diff --git a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc index 4bd9124fa68..b94ea676ca0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mapValue.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mapValue.cc @@ -70,7 +70,7 @@ void register_node_type_cmp_map_value() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_MAP_VALUE, "Map Value", NODE_CLASS_OP_VECTOR); ntype.declare = blender::nodes::cmp_node_map_value_declare; ntype.draw_buttons = node_composit_buts_map_value; node_type_init(&ntype, node_composit_init_map_value); diff --git a/source/blender/nodes/composite/nodes/node_composite_mask.cc b/source/blender/nodes/composite/nodes/node_composite_mask.cc index 8cbf526a289..0fea7148a4d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mask.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mask.cc @@ -41,7 +41,7 @@ static void cmp_node_mask_declare(NodeDeclarationBuilder &b) static void node_composit_init_mask(bNodeTree *UNUSED(ntree), bNode *node) { - NodeMask *data = (NodeMask *)MEM_callocN(sizeof(NodeMask), "NodeMask"); + NodeMask *data = MEM_cnew<NodeMask>(__func__); data->size_x = data->size_y = 256; node->storage = data; @@ -96,7 +96,7 @@ void register_node_type_cmp_mask() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_MASK, "Mask", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_mask_declare; ntype.draw_buttons = node_composit_buts_mask; node_type_init(&ntype, node_composit_init_mask); diff --git a/source/blender/nodes/composite/nodes/node_composite_math.cc b/source/blender/nodes/composite/nodes/node_composite_math.cc index b34cfab5eb5..21d76756e0e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_math.cc +++ b/source/blender/nodes/composite/nodes/node_composite_math.cc @@ -47,7 +47,7 @@ void register_node_type_cmp_math() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_MATH, "Math", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_math_declare; ntype.labelfunc = node_math_label; node_type_update(&ntype, node_math_update); diff --git a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc index 4432b031ee7..7bc37fd5024 100644 --- a/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_mixrgb.cc @@ -42,7 +42,8 @@ void register_node_type_cmp_mix_rgb() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR); + ntype.flag |= NODE_PREVIEW; ntype.declare = blender::nodes::cmp_node_mixrgb_declare; ntype.labelfunc = node_blend_label; diff --git a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc index 47a2c89a2f9..3c0be471564 100644 --- a/source/blender/nodes/composite/nodes/node_composite_movieclip.cc +++ b/source/blender/nodes/composite/nodes/node_composite_movieclip.cc @@ -49,8 +49,7 @@ static void init(const bContext *C, PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; Scene *scene = CTX_data_scene(C); - MovieClipUser *user = (MovieClipUser *)MEM_callocN(sizeof(MovieClipUser), - "node movie clip user"); + MovieClipUser *user = MEM_cnew<MovieClipUser>(__func__); node->id = (ID *)scene->clip; id_us_plus(node->id); @@ -101,11 +100,12 @@ void register_node_type_cmp_movieclip() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_MOVIECLIP, "Movie Clip", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_movieclip_declare; ntype.draw_buttons = node_composit_buts_movieclip; ntype.draw_buttons_ex = node_composit_buts_movieclip_ex; ntype.initfunc_api = init; + ntype.flag |= NODE_PREVIEW; node_type_storage( &ntype, "MovieClipUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc index e7d9cac7c1a..17c9fd29b1d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc +++ b/source/blender/nodes/composite/nodes/node_composite_moviedistortion.cc @@ -102,7 +102,7 @@ void register_node_type_cmp_moviedistortion() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_MOVIEDISTORTION, "Movie Distortion", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_moviedistortion_declare; ntype.draw_buttons = node_composit_buts_moviedistortion; ntype.labelfunc = label; diff --git a/source/blender/nodes/composite/nodes/node_composite_normal.cc b/source/blender/nodes/composite/nodes/node_composite_normal.cc index b541761a8cc..c84e02967b8 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normal.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normal.cc @@ -44,7 +44,7 @@ void register_node_type_cmp_normal() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR); ntype.declare = blender::nodes::cmp_node_normal_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_normalize.cc b/source/blender/nodes/composite/nodes/node_composite_normalize.cc index dd3939fa6e2..e89af5fb9fb 100644 --- a/source/blender/nodes/composite/nodes/node_composite_normalize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_normalize.cc @@ -39,7 +39,7 @@ void register_node_type_cmp_normalize() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_NORMALIZE, "Normalize", NODE_CLASS_OP_VECTOR); ntype.declare = blender::nodes::cmp_node_normalize_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc index 79074375a23..f4699ec02d0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_outputFile.cc +++ b/source/blender/nodes/composite/nodes/node_composite_outputFile.cc @@ -135,8 +135,7 @@ bNodeSocket *ntreeCompositOutputFileAddSocket(bNodeTree *ntree, ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, nullptr, name); /* create format data for the input socket */ - NodeImageMultiFileSocket *sockdata = (NodeImageMultiFileSocket *)MEM_callocN( - sizeof(NodeImageMultiFileSocket), "socket image format"); + NodeImageMultiFileSocket *sockdata = MEM_cnew<NodeImageMultiFileSocket>(__func__); sock->storage = sockdata; BLI_strncpy_utf8(sockdata->path, name, sizeof(sockdata->path)); @@ -203,8 +202,7 @@ static void init_output_file(const bContext *C, PointerRNA *ptr) Scene *scene = CTX_data_scene(C); bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - NodeImageMultiFile *nimf = (NodeImageMultiFile *)MEM_callocN(sizeof(NodeImageMultiFile), - "node image multi file"); + NodeImageMultiFile *nimf = MEM_cnew<NodeImageMultiFile>(__func__); ImageFormatData *format = nullptr; node->storage = nimf; @@ -441,11 +439,12 @@ void register_node_type_cmp_output_file() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_OUTPUT_FILE, "File Output", NODE_CLASS_OUTPUT); node_type_socket_templates(&ntype, nullptr, nullptr); ntype.draw_buttons = node_composit_buts_file_output; ntype.draw_buttons_ex = node_composit_buts_file_output_ex; ntype.initfunc_api = init_output_file; + ntype.flag |= NODE_PREVIEW; node_type_storage(&ntype, "NodeImageMultiFile", free_output_file, copy_output_file); node_type_update(&ntype, update_output_file); diff --git a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc index 3679aada759..7fe4d84ed72 100644 --- a/source/blender/nodes/composite/nodes/node_composite_pixelate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_pixelate.cc @@ -39,7 +39,7 @@ void register_node_type_cmp_pixelate() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_PIXELATE, "Pixelate", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_pixelate_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc index d9d362f5175..4e5299d8b5f 100644 --- a/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc +++ b/source/blender/nodes/composite/nodes/node_composite_planetrackdeform.cc @@ -41,8 +41,7 @@ static void cmp_node_planetrackdeform_declare(NodeDeclarationBuilder &b) static void init(bNodeTree *UNUSED(ntree), bNode *node) { - NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)MEM_callocN( - sizeof(NodePlaneTrackDeformData), "node plane track deform data"); + NodePlaneTrackDeformData *data = MEM_cnew<NodePlaneTrackDeformData>(__func__); data->motion_blur_samples = 16; data->motion_blur_shutter = 0.5f; node->storage = data; @@ -101,8 +100,7 @@ void register_node_type_cmp_planetrackdeform() { static bNodeType ntype; - cmp_node_type_base( - &ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_PLANETRACKDEFORM, "Plane Track Deform", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_planetrackdeform_declare; ntype.draw_buttons = node_composit_buts_planetrackdeform; node_type_init(&ntype, init); diff --git a/source/blender/nodes/composite/nodes/node_composite_posterize.cc b/source/blender/nodes/composite/nodes/node_composite_posterize.cc index 8437c72e76c..347901a6578 100644 --- a/source/blender/nodes/composite/nodes/node_composite_posterize.cc +++ b/source/blender/nodes/composite/nodes/node_composite_posterize.cc @@ -40,7 +40,7 @@ void register_node_type_cmp_posterize() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_POSTERIZE, "Posterize", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_posterize_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc index a70adf68692..ad29d231b11 100644 --- a/source/blender/nodes/composite/nodes/node_composite_premulkey.cc +++ b/source/blender/nodes/composite/nodes/node_composite_premulkey.cc @@ -47,7 +47,7 @@ void register_node_type_cmp_premulkey() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_PREMULKEY, "Alpha Convert", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_premulkey_declare; ntype.draw_buttons = node_composit_buts_premulkey; diff --git a/source/blender/nodes/composite/nodes/node_composite_rgb.cc b/source/blender/nodes/composite/nodes/node_composite_rgb.cc index 54f152d1cd0..b7db175e1b1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rgb.cc @@ -38,7 +38,7 @@ void register_node_type_cmp_rgb() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_RGB, "RGB", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_rgb_declare; node_type_size_preset(&ntype, NODE_SIZE_SMALL); diff --git a/source/blender/nodes/composite/nodes/node_composite_rotate.cc b/source/blender/nodes/composite/nodes/node_composite_rotate.cc index cc1589a47ca..a147d81a344 100644 --- a/source/blender/nodes/composite/nodes/node_composite_rotate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_rotate.cc @@ -57,7 +57,7 @@ void register_node_type_cmp_rotate() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_rotate_declare; ntype.draw_buttons = node_composit_buts_rotate; node_type_init(&ntype, node_composit_init_rotate); diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index 98c9f6619f4..1aecf63d049 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -77,7 +77,7 @@ void register_node_type_cmp_scale() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_SCALE, "Scale", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_scale_declare; ntype.draw_buttons = node_composit_buts_scale; node_type_update(&ntype, node_composite_update_scale); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc index 9eafc0e3594..45db11d26b7 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombHSVA.cc @@ -42,7 +42,7 @@ void register_node_type_cmp_sephsva() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPHSVA, "Separate HSVA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_sephsva_declare; nodeRegisterType(&ntype); } @@ -66,7 +66,7 @@ void register_node_type_cmp_combhsva() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBHSVA, "Combine HSVA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_combhsva_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc index e81ea6f31be..0d4584f2d60 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombRGBA.cc @@ -41,7 +41,7 @@ void register_node_type_cmp_seprgba() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPRGBA, "Separate RGBA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_seprgba_declare; nodeRegisterType(&ntype); @@ -66,7 +66,7 @@ void register_node_type_cmp_combrgba() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBRGBA, "Combine RGBA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_combrgba_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc index 15c8efc2ef8..73790499a58 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYCCA.cc @@ -47,7 +47,7 @@ void register_node_type_cmp_sepycca() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPYCCA, "Separate YCbCrA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_sepycca_declare; node_type_init(&ntype, node_composit_init_mode_sepycca); @@ -78,7 +78,7 @@ void register_node_type_cmp_combycca() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBYCCA, "Combine YCbCrA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_combycca_declare; node_type_init(&ntype, node_composit_init_mode_combycca); diff --git a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc index 4d4b01c2fb3..c026244d13b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sepcombYUVA.cc @@ -42,7 +42,7 @@ void register_node_type_cmp_sepyuva() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SEPYUVA, "Separate YUVA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_sepyuva_declare; nodeRegisterType(&ntype); @@ -67,7 +67,7 @@ void register_node_type_cmp_combyuva() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_COMBYUVA, "Combine YUVA", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_combyuva_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc index 3e66f884efd..8912e793a1d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_setalpha.cc +++ b/source/blender/nodes/composite/nodes/node_composite_setalpha.cc @@ -41,7 +41,7 @@ static void cmp_node_setalpha_declare(NodeDeclarationBuilder &b) static void node_composit_init_setalpha(bNodeTree *UNUSED(ntree), bNode *node) { - NodeSetAlpha *settings = (NodeSetAlpha *)MEM_callocN(sizeof(NodeSetAlpha), __func__); + NodeSetAlpha *settings = MEM_cnew<NodeSetAlpha>(__func__); node->storage = settings; settings->mode = CMP_NODE_SETALPHA_MODE_APPLY; } @@ -55,7 +55,7 @@ void register_node_type_cmp_setalpha() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SETALPHA, "Set Alpha", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_setalpha_declare; ntype.draw_buttons = node_composit_buts_set_alpha; node_type_init(&ntype, node_composit_init_setalpha); diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc index 63772a52840..2ff64c3d735 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc @@ -43,7 +43,7 @@ static void cmp_node_split_viewer_declare(NodeDeclarationBuilder &b) static void node_composit_init_splitviewer(bNodeTree *UNUSED(ntree), bNode *node) { - ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user"); + ImageUser *iuser = MEM_cnew<ImageUser>(__func__); node->storage = iuser; iuser->sfra = 1; node->custom1 = 50; /* default 50% split */ @@ -65,10 +65,10 @@ void register_node_type_cmp_splitviewer() { static bNodeType ntype; - cmp_node_type_base( - &ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_SPLITVIEWER, "Split Viewer", NODE_CLASS_OUTPUT); ntype.declare = blender::nodes::cmp_node_split_viewer_declare; ntype.draw_buttons = node_composit_buts_splitviewer; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_splitviewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc index de6cc21ccd5..7ab933ab8ea 100644 --- a/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc +++ b/source/blender/nodes/composite/nodes/node_composite_stabilize2d.cc @@ -80,7 +80,7 @@ void register_node_type_cmp_stabilize2d() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_STABILIZE2D, "Stabilize 2D", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_stabilize2d_declare; ntype.draw_buttons = node_composit_buts_stabilize2d; ntype.initfunc_api = init; diff --git a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc index f5d69c7d17b..7ae9d927a81 100644 --- a/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc +++ b/source/blender/nodes/composite/nodes/node_composite_sunbeams.cc @@ -38,7 +38,7 @@ static void cmp_node_sunbeams_declare(NodeDeclarationBuilder &b) static void init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeSunBeams *data = (NodeSunBeams *)MEM_callocN(sizeof(NodeSunBeams), "sun beams node"); + NodeSunBeams *data = MEM_cnew<NodeSunBeams>(__func__); data->source[0] = 0.5f; data->source[1] = 0.5f; @@ -60,7 +60,7 @@ void register_node_type_cmp_sunbeams() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SUNBEAMS, "Sun Beams", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_sunbeams_declare; ntype.draw_buttons = node_composit_buts_sunbeams; node_type_init(&ntype, init); diff --git a/source/blender/nodes/composite/nodes/node_composite_switch.cc b/source/blender/nodes/composite/nodes/node_composite_switch.cc index d13bcc28d10..3ecd29230d1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switch.cc +++ b/source/blender/nodes/composite/nodes/node_composite_switch.cc @@ -24,7 +24,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** Switch ******************** */ @@ -49,7 +49,7 @@ void register_node_type_cmp_switch() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_SWITCH, "Switch", NODE_CLASS_LAYOUT); ntype.declare = blender::nodes::cmp_node_switch_declare; ntype.draw_buttons = node_composit_buts_switch; node_type_size_preset(&ntype, NODE_SIZE_SMALL); diff --git a/source/blender/nodes/composite/nodes/node_composite_switchview.cc b/source/blender/nodes/composite/nodes/node_composite_switchview.cc index 159d66fc6cc..69bb8f532d6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_switchview.cc +++ b/source/blender/nodes/composite/nodes/node_composite_switchview.cc @@ -28,7 +28,7 @@ #include "UI_interface.h" #include "UI_resources.h" -#include "../node_composite_util.hh" +#include "node_composite_util.hh" /* **************** SWITCH VIEW ******************** */ @@ -159,7 +159,7 @@ void register_node_type_cmp_switch_view() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_SWITCH_VIEW, "Switch View", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, nullptr, cmp_node_switch_view_out); ntype.draw_buttons_ex = node_composit_buts_switch_view_ex; ntype.initfunc_api = init_switch_view; diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc index 5e5fca755b2..67bf95c5ae9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_texture.cc +++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc @@ -45,8 +45,9 @@ void register_node_type_cmp_texture() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_texture_declare; + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc index c6015eda08c..fccfa6a3de9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_tonemap.cc +++ b/source/blender/nodes/composite/nodes/node_composite_tonemap.cc @@ -40,7 +40,7 @@ static void cmp_node_tonemap_declare(NodeDeclarationBuilder &b) static void node_composit_init_tonemap(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTonemap *ntm = (NodeTonemap *)MEM_callocN(sizeof(NodeTonemap), "node tonemap data"); + NodeTonemap *ntm = MEM_cnew<NodeTonemap>(__func__); ntm->type = 1; ntm->key = 0.18; ntm->offset = 1; @@ -80,7 +80,7 @@ void register_node_type_cmp_tonemap() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_TONEMAP, "Tonemap", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_tonemap_declare; ntype.draw_buttons = node_composit_buts_tonemap; node_type_init(&ntype, node_composit_init_tonemap); diff --git a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc index 3be52820f15..cce3052ef22 100644 --- a/source/blender/nodes/composite/nodes/node_composite_trackpos.cc +++ b/source/blender/nodes/composite/nodes/node_composite_trackpos.cc @@ -41,8 +41,7 @@ static void cmp_node_trackpos_declare(NodeDeclarationBuilder &b) static void init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTrackPosData *data = (NodeTrackPosData *)MEM_callocN(sizeof(NodeTrackPosData), - "node track position data"); + NodeTrackPosData *data = MEM_cnew<NodeTrackPosData>(__func__); node->storage = data; } @@ -99,7 +98,7 @@ void register_node_type_cmp_trackpos() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_TRACKPOS, "Track Position", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_trackpos_declare; ntype.draw_buttons = node_composit_buts_trackpos; node_type_init(&ntype, init); diff --git a/source/blender/nodes/composite/nodes/node_composite_transform.cc b/source/blender/nodes/composite/nodes/node_composite_transform.cc index ad1cc4cd308..ee9f25531f6 100644 --- a/source/blender/nodes/composite/nodes/node_composite_transform.cc +++ b/source/blender/nodes/composite/nodes/node_composite_transform.cc @@ -55,7 +55,7 @@ void register_node_type_cmp_transform() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_TRANSFORM, "Transform", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_transform_declare; ntype.draw_buttons = node_composit_buts_transform; diff --git a/source/blender/nodes/composite/nodes/node_composite_translate.cc b/source/blender/nodes/composite/nodes/node_composite_translate.cc index ce29cc55ca2..96188b68496 100644 --- a/source/blender/nodes/composite/nodes/node_composite_translate.cc +++ b/source/blender/nodes/composite/nodes/node_composite_translate.cc @@ -42,8 +42,7 @@ static void cmp_node_translate_declare(NodeDeclarationBuilder &b) static void node_composit_init_translate(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTranslateData *data = (NodeTranslateData *)MEM_callocN(sizeof(NodeTranslateData), - "node translate data"); + NodeTranslateData *data = MEM_cnew<NodeTranslateData>(__func__); node->storage = data; } @@ -57,7 +56,7 @@ void register_node_type_cmp_translate() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0); + cmp_node_type_base(&ntype, CMP_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT); ntype.declare = blender::nodes::cmp_node_translate_declare; ntype.draw_buttons = node_composit_buts_translate; node_type_init(&ntype, node_composit_init_translate); diff --git a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc index dca6c9c141c..65e28751ce2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc +++ b/source/blender/nodes/composite/nodes/node_composite_valToRgb.cc @@ -45,7 +45,7 @@ void register_node_type_cmp_valtorgb() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_valtorgb_declare; node_type_size(&ntype, 240, 200, 320); node_type_init(&ntype, node_composit_init_valtorgb); @@ -70,7 +70,7 @@ void register_node_type_cmp_rgbtobw() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER); ntype.declare = blender::nodes::cmp_node_rgbtobw_declare; node_type_size_preset(&ntype, NODE_SIZE_SMALL); diff --git a/source/blender/nodes/composite/nodes/node_composite_value.cc b/source/blender/nodes/composite/nodes/node_composite_value.cc index d2274d2d82a..c78b0a454d9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_value.cc +++ b/source/blender/nodes/composite/nodes/node_composite_value.cc @@ -38,7 +38,7 @@ void register_node_type_cmp_value() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0); + cmp_node_type_base(&ntype, CMP_NODE_VALUE, "Value", NODE_CLASS_INPUT); ntype.declare = blender::nodes::cmp_node_value_declare; node_type_size_preset(&ntype, NODE_SIZE_SMALL); diff --git a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc index c4bea269670..cef787a23b2 100644 --- a/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc +++ b/source/blender/nodes/composite/nodes/node_composite_vecBlur.cc @@ -46,7 +46,7 @@ static void cmp_node_vec_blur_declare(NodeDeclarationBuilder &b) static void node_composit_init_vecblur(bNodeTree *UNUSED(ntree), bNode *node) { - NodeBlurData *nbd = (NodeBlurData *)MEM_callocN(sizeof(NodeBlurData), "node blur data"); + NodeBlurData *nbd = MEM_cnew<NodeBlurData>(__func__); node->storage = nbd; nbd->samples = 32; nbd->fac = 1.0f; @@ -73,7 +73,7 @@ void register_node_type_cmp_vecblur() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER, 0); + cmp_node_type_base(&ntype, CMP_NODE_VECBLUR, "Vector Blur", NODE_CLASS_OP_FILTER); ntype.declare = blender::nodes::cmp_node_vec_blur_declare; ntype.draw_buttons = node_composit_buts_vecblur; node_type_init(&ntype, node_composit_init_vecblur); diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index fcebda3b8a4..ba3d620a1aa 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -46,7 +46,7 @@ static void cmp_node_viewer_declare(NodeDeclarationBuilder &b) static void node_composit_init_viewer(bNodeTree *UNUSED(ntree), bNode *node) { - ImageUser *iuser = (ImageUser *)MEM_callocN(sizeof(ImageUser), "node image user"); + ImageUser *iuser = MEM_cnew<ImageUser>(__func__); node->storage = iuser; iuser->sfra = 1; node->custom3 = 0.5f; @@ -77,10 +77,11 @@ void register_node_type_cmp_viewer() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); + cmp_node_type_base(&ntype, CMP_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT); ntype.declare = blender::nodes::cmp_node_viewer_declare; ntype.draw_buttons = node_composit_buts_viewer; ntype.draw_buttons_ex = node_composit_buts_viewer_ex; + ntype.flag |= NODE_PREVIEW; node_type_init(&ntype, node_composit_init_viewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc index dd6872e4dd9..d79b7aa5c14 100644 --- a/source/blender/nodes/composite/nodes/node_composite_zcombine.cc +++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.cc @@ -55,7 +55,7 @@ void register_node_type_cmp_zcombine() { static bNodeType ntype; - cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR, 0); + cmp_node_type_base(&ntype, CMP_NODE_ZCOMBINE, "Z Combine", NODE_CLASS_OP_COLOR); ntype.declare = blender::nodes::cmp_node_zcombine_declare; ntype.draw_buttons = node_composit_buts_zcombine; diff --git a/source/blender/nodes/function/CMakeLists.txt b/source/blender/nodes/function/CMakeLists.txt new file mode 100644 index 00000000000..118a1fbffd1 --- /dev/null +++ b/source/blender/nodes/function/CMakeLists.txt @@ -0,0 +1,75 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# The Original Code is Copyright (C) 2021, Blender Foundation +# All rights reserved. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../editors/include + ../../functions + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/guardedalloc +) + + +set(SRC + nodes/legacy/node_fn_random_float.cc + + nodes/node_fn_align_euler_to_vector.cc + nodes/node_fn_boolean_math.cc + nodes/node_fn_compare.cc + nodes/node_fn_float_to_int.cc + nodes/node_fn_input_bool.cc + nodes/node_fn_input_color.cc + nodes/node_fn_input_int.cc + nodes/node_fn_input_special_characters.cc + nodes/node_fn_input_string.cc + nodes/node_fn_input_vector.cc + nodes/node_fn_random_value.cc + nodes/node_fn_replace_string.cc + nodes/node_fn_rotate_euler.cc + nodes/node_fn_slice_string.cc + nodes/node_fn_string_length.cc + nodes/node_fn_value_to_string.cc + + node_function_util.cc + + node_function_util.hh +) + +set(LIB + bf_functions +) + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +blender_add_lib(bf_nodes_function "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +if(WITH_UNITY_BUILD) + set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD ON) + set_target_properties(bf_nodes_function PROPERTIES UNITY_BUILD_BATCH_SIZE 10) +endif() diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc index 83f5b571695..0137b298f45 100644 --- a/source/blender/nodes/function/node_function_util.cc +++ b/source/blender/nodes/function/node_function_util.cc @@ -31,9 +31,9 @@ static bool fn_node_poll_default(bNodeType *UNUSED(ntype), return true; } -void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) +void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { - node_type_base(ntype, type, name, nclass, flag); + node_type_base(ntype, type, name, nclass); ntype->poll = fn_node_poll_default; ntype->insert_link = node_insert_link_default; ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; diff --git a/source/blender/nodes/function/node_function_util.hh b/source/blender/nodes/function/node_function_util.hh index 46b485298e3..acde9c4b55b 100644 --- a/source/blender/nodes/function/node_function_util.hh +++ b/source/blender/nodes/function/node_function_util.hh @@ -37,5 +37,4 @@ #include "FN_multi_function_builder.hh" -void fn_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); diff --git a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc index d98d49c7273..582e6748a1e 100644 --- a/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc +++ b/source/blender/nodes/function/nodes/legacy/node_fn_random_float.cc @@ -18,7 +18,7 @@ #include "BLI_hash.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_random_float_cc { static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b) { @@ -29,8 +29,6 @@ static void fn_node_legacy_random_float_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; -} // namespace blender::nodes - class RandomFloatFunction : public blender::fn::MultiFunction { public: RandomFloatFunction() @@ -75,12 +73,16 @@ static void fn_node_legacy_random_float_build_multi_function( builder.set_matching_fn(fn); } +} // namespace blender::nodes::node_fn_random_float_cc + void register_node_type_fn_legacy_random_float() { + namespace file_ns = blender::nodes::node_fn_random_float_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0, 0); - ntype.declare = blender::nodes::fn_node_legacy_random_float_declare; - ntype.build_multi_function = fn_node_legacy_random_float_build_multi_function; + fn_node_type_base(&ntype, FN_NODE_LEGACY_RANDOM_FLOAT, "Random Float", 0); + ntype.declare = file_ns::fn_node_legacy_random_float_declare; + ntype.build_multi_function = file_ns::fn_node_legacy_random_float_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc index 4088fa24ca7..f4ce8d2f35a 100644 --- a/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_align_euler_to_vector.cc @@ -23,7 +23,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_align_euler_to_vector_cc { static void fn_node_align_euler_to_vector_declare(NodeDeclarationBuilder &b) { @@ -207,16 +207,18 @@ static void fn_node_align_euler_to_vector_build_multi_function(NodeMultiFunction builder.construct_and_set_matching_fn<MF_AlignEulerToVector>(node.custom1, node.custom2); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_align_euler_to_vector_cc void register_node_type_fn_align_euler_to_vector() { + namespace file_ns = blender::nodes::node_fn_align_euler_to_vector_cc; + static bNodeType ntype; fn_node_type_base( - &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_align_euler_to_vector_declare; - ntype.draw_buttons = blender::nodes::fn_node_align_euler_to_vector_layout; - ntype.build_multi_function = blender::nodes::fn_node_align_euler_to_vector_build_multi_function; + &ntype, FN_NODE_ALIGN_EULER_TO_VECTOR, "Align Euler to Vector", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_align_euler_to_vector_declare; + ntype.draw_buttons = file_ns::fn_node_align_euler_to_vector_layout; + ntype.build_multi_function = file_ns::fn_node_align_euler_to_vector_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index 4b59b49c632..e8c05defe7c 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -24,7 +24,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_boolean_math_cc { static void fn_node_boolean_math_declare(NodeDeclarationBuilder &b) { @@ -87,17 +87,19 @@ static void fn_node_boolean_math_build_multi_function(NodeMultiFunctionBuilder & builder.set_matching_fn(fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_boolean_math_cc void register_node_type_fn_boolean_math() { + namespace file_ns = blender::nodes::node_fn_boolean_math_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_boolean_math_declare; - ntype.labelfunc = blender::nodes::node_boolean_math_label; - node_type_update(&ntype, blender::nodes::node_boolean_math_update); - ntype.build_multi_function = blender::nodes::fn_node_boolean_math_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_boolean_math_layout; + fn_node_type_base(&ntype, FN_NODE_BOOLEAN_MATH, "Boolean Math", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_boolean_math_declare; + ntype.labelfunc = file_ns::node_boolean_math_label; + node_type_update(&ntype, file_ns::node_boolean_math_update); + ntype.build_multi_function = file_ns::fn_node_boolean_math_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_boolean_math_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_compare.cc b/source/blender/nodes/function/nodes/node_fn_compare.cc index e773563ca5f..28a6093e849 100644 --- a/source/blender/nodes/function/nodes/node_fn_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_compare.cc @@ -97,8 +97,7 @@ static void node_compare_update(bNodeTree *ntree, bNode *node) static void node_compare_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeFunctionCompare *data = (NodeFunctionCompare *)MEM_callocN(sizeof(NodeFunctionCompare), - __func__); + NodeFunctionCompare *data = MEM_cnew<NodeFunctionCompare>(__func__); data->operation = NODE_COMPARE_GREATER_THAN; data->data_type = SOCK_FLOAT; data->mode = NODE_COMPARE_MODE_ELEMENT; @@ -131,21 +130,33 @@ static void node_compare_gather_link_searches(GatherLinkSearchOpParams ¶ms) const eNodeSocketDatatype type = static_cast<eNodeSocketDatatype>(params.other_socket().type); - if (ELEM(type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_RGBA, SOCK_VECTOR, SOCK_INT)) { - params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_GREATER_THAN}); - params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_GREATER_THAN}); - params.add_item( - IFACE_("C"), - SocketSearchOp{ - "C", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DOT_PRODUCT}); - params.add_item( - IFACE_("Angle"), - SocketSearchOp{ - "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION}); - } - else if (type == SOCK_STRING) { - params.add_item(IFACE_("A"), SocketSearchOp{"A", type, NODE_COMPARE_EQUAL}); - params.add_item(IFACE_("B"), SocketSearchOp{"B", type, NODE_COMPARE_EQUAL}); + if (ELEM(type, SOCK_BOOLEAN, SOCK_FLOAT, SOCK_RGBA, SOCK_VECTOR, SOCK_INT, SOCK_STRING)) { + const eNodeSocketDatatype mode_type = (type == SOCK_BOOLEAN) ? SOCK_FLOAT : type; + const bool string_type = (type == SOCK_STRING); + /* Add socket A compare operations. */ + for (const EnumPropertyItem *item = rna_enum_node_compare_operation_items; + item->identifier != nullptr; + item++) { + if (item->name != nullptr && item->identifier[0] != '\0') { + if (!string_type && + ELEM(item->value, NODE_COMPARE_COLOR_BRIGHTER, NODE_COMPARE_COLOR_DARKER)) { + params.add_item(IFACE_(item->name), + SocketSearchOp{"A", SOCK_RGBA, (NodeCompareOperation)item->value}); + } + else if ((!string_type) || + (string_type && ELEM(item->value, NODE_COMPARE_EQUAL, NODE_COMPARE_NOT_EQUAL))) { + params.add_item(IFACE_(item->name), + SocketSearchOp{"A", mode_type, (NodeCompareOperation)item->value}); + } + } + } + /* Add Angle socket. */ + if (!string_type) { + params.add_item( + IFACE_("Angle"), + SocketSearchOp{ + "Angle", SOCK_VECTOR, NODE_COMPARE_GREATER_THAN, NODE_COMPARE_MODE_DIRECTION}); + } } } @@ -526,7 +537,7 @@ void register_node_type_fn_compare() namespace file_ns = blender::nodes::node_fn_compare_cc; static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER, 0); + fn_node_type_base(&ntype, FN_NODE_COMPARE, "Compare", NODE_CLASS_CONVERTER); ntype.declare = file_ns::fn_node_compare_declare; ntype.labelfunc = file_ns::node_compare_label; node_type_update(&ntype, file_ns::node_compare_update); diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc index 21f6734e4aa..1a130e748d5 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc @@ -25,7 +25,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_float_to_int_cc { static void fn_node_float_to_int_declare(NodeDeclarationBuilder &b) { @@ -81,16 +81,18 @@ static void fn_node_float_to_int_build_multi_function(NodeMultiFunctionBuilder & builder.set_matching_fn(fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_float_to_int_cc void register_node_type_fn_float_to_int() { + namespace file_ns = blender::nodes::node_fn_float_to_int_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_float_to_int_declare; - ntype.labelfunc = blender::nodes::node_float_to_int_label; - ntype.build_multi_function = blender::nodes::fn_node_float_to_int_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_float_to_int_layout; + fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_float_to_int_declare; + ntype.labelfunc = file_ns::node_float_to_int_label; + ntype.build_multi_function = file_ns::fn_node_float_to_int_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_float_to_int_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_bool.cc b/source/blender/nodes/function/nodes/node_fn_input_bool.cc index 1358bf8a223..b6f7c802cc9 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_bool.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_bool.cc @@ -21,7 +21,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_bool_cc { static void fn_node_input_bool_declare(NodeDeclarationBuilder &b) { @@ -43,22 +43,24 @@ static void fn_node_input_bool_build_multi_function(NodeMultiFunctionBuilder &bu static void fn_node_input_bool_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeInputBool *data = (NodeInputBool *)MEM_callocN(sizeof(NodeInputBool), __func__); + NodeInputBool *data = MEM_cnew<NodeInputBool>(__func__); node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_bool_cc void register_node_type_fn_input_bool() { + namespace file_ns = blender::nodes::node_fn_input_bool_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0, 0); - ntype.declare = blender::nodes::fn_node_input_bool_declare; - node_type_init(&ntype, blender::nodes::fn_node_input_bool_init); + fn_node_type_base(&ntype, FN_NODE_INPUT_BOOL, "Boolean", 0); + ntype.declare = file_ns::fn_node_input_bool_declare; + node_type_init(&ntype, file_ns::fn_node_input_bool_init); node_type_storage( &ntype, "NodeInputBool", node_free_standard_storage, node_copy_standard_storage); - ntype.build_multi_function = blender::nodes::fn_node_input_bool_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_input_bool_layout; + ntype.build_multi_function = file_ns::fn_node_input_bool_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_input_bool_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_color.cc b/source/blender/nodes/function/nodes/node_fn_input_color.cc index 43bb654b776..5ace57810e1 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_color.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_color.cc @@ -19,7 +19,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_color_cc { static void fn_node_input_color_declare(NodeDeclarationBuilder &b) { @@ -43,23 +43,25 @@ static void fn_node_input_color_build_multi_function( static void fn_node_input_color_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeInputColor *data = (NodeInputColor *)MEM_callocN(sizeof(NodeInputColor), __func__); + NodeInputColor *data = MEM_cnew<NodeInputColor>(__func__); copy_v4_fl4(data->color, 0.5f, 0.5f, 0.5f, 1.0f); node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_color_cc void register_node_type_fn_input_color() { + namespace file_ns = blender::nodes::node_fn_input_color_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::fn_node_input_color_declare; - node_type_init(&ntype, blender::nodes::fn_node_input_color_init); + fn_node_type_base(&ntype, FN_NODE_INPUT_COLOR, "Color", NODE_CLASS_INPUT); + ntype.declare = file_ns::fn_node_input_color_declare; + node_type_init(&ntype, file_ns::fn_node_input_color_init); node_type_storage( &ntype, "NodeInputColor", node_free_standard_storage, node_copy_standard_storage); - ntype.build_multi_function = blender::nodes::fn_node_input_color_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_input_color_layout; + ntype.build_multi_function = file_ns::fn_node_input_color_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_input_color_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_int.cc b/source/blender/nodes/function/nodes/node_fn_input_int.cc index ddbb86e2661..d96339ae365 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_int.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_int.cc @@ -21,7 +21,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_int_cc { static void fn_node_input_int_declare(NodeDeclarationBuilder &b) { @@ -43,22 +43,24 @@ static void fn_node_input_int_build_multi_function(NodeMultiFunctionBuilder &bui static void fn_node_input_int_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeInputInt *data = (NodeInputInt *)MEM_callocN(sizeof(NodeInputInt), __func__); + NodeInputInt *data = MEM_cnew<NodeInputInt>(__func__); node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_int_cc void register_node_type_fn_input_int() { + namespace file_ns = blender::nodes::node_fn_input_int_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0, 0); - ntype.declare = blender::nodes::fn_node_input_int_declare; - node_type_init(&ntype, blender::nodes::fn_node_input_int_init); + fn_node_type_base(&ntype, FN_NODE_INPUT_INT, "Integer", 0); + ntype.declare = file_ns::fn_node_input_int_declare; + node_type_init(&ntype, file_ns::fn_node_input_int_init); node_type_storage( &ntype, "NodeInputInt", node_free_standard_storage, node_copy_standard_storage); - ntype.build_multi_function = blender::nodes::fn_node_input_int_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_input_int_layout; + ntype.build_multi_function = file_ns::fn_node_input_int_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_input_int_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc index c61af419e50..8137b424143 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_special_characters.cc @@ -16,7 +16,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_special_characters_cc { static void fn_node_input_special_characters_declare(NodeDeclarationBuilder &b) { @@ -59,16 +59,17 @@ static void fn_node_input_special_characters_build_multi_function( builder.set_matching_fn(special_characters_fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_special_characters_cc void register_node_type_fn_input_special_characters() { + namespace file_ns = blender::nodes::node_fn_input_special_characters_cc; + static bNodeType ntype; fn_node_type_base( - &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::fn_node_input_special_characters_declare; - ntype.build_multi_function = - blender::nodes::fn_node_input_special_characters_build_multi_function; + &ntype, FN_NODE_INPUT_SPECIAL_CHARACTERS, "Special Characters", NODE_CLASS_INPUT); + ntype.declare = file_ns::fn_node_input_special_characters_declare; + ntype.build_multi_function = file_ns::fn_node_input_special_characters_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_string.cc b/source/blender/nodes/function/nodes/node_fn_input_string.cc index dd2d1292601..a326caf50bd 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_string.cc @@ -19,7 +19,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_string_cc { static void fn_node_input_string_declare(NodeDeclarationBuilder &b) { @@ -71,20 +71,20 @@ static void fn_node_string_copy(bNodeTree *UNUSED(dest_ntree), dest_node->storage = destination_storage; } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_string_cc void register_node_type_fn_input_string() { + namespace file_ns = blender::nodes::node_fn_input_string_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::fn_node_input_string_declare; - node_type_init(&ntype, blender::nodes::fn_node_input_string_init); - node_type_storage(&ntype, - "NodeInputString", - blender::nodes::fn_node_input_string_free, - blender::nodes::fn_node_string_copy); - ntype.build_multi_function = blender::nodes::fn_node_input_string_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_input_string_layout; + fn_node_type_base(&ntype, FN_NODE_INPUT_STRING, "String", NODE_CLASS_INPUT); + ntype.declare = file_ns::fn_node_input_string_declare; + node_type_init(&ntype, file_ns::fn_node_input_string_init); + node_type_storage( + &ntype, "NodeInputString", file_ns::fn_node_input_string_free, file_ns::fn_node_string_copy); + ntype.build_multi_function = file_ns::fn_node_input_string_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_input_string_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_input_vector.cc b/source/blender/nodes/function/nodes/node_fn_input_vector.cc index 1e5fd186b5a..34515c4414c 100644 --- a/source/blender/nodes/function/nodes/node_fn_input_vector.cc +++ b/source/blender/nodes/function/nodes/node_fn_input_vector.cc @@ -21,7 +21,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_input_vector_cc { static void fn_node_input_vector_declare(NodeDeclarationBuilder &b) { @@ -44,23 +44,24 @@ static void fn_node_input_vector_build_multi_function(NodeMultiFunctionBuilder & static void fn_node_input_vector_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeInputVector *data = (NodeInputVector *)MEM_callocN(sizeof(NodeInputVector), - "input vector node"); + NodeInputVector *data = MEM_cnew<NodeInputVector>(__func__); node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_input_vector_cc void register_node_type_fn_input_vector() { + namespace file_ns = blender::nodes::node_fn_input_vector_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0, 0); - ntype.declare = blender::nodes::fn_node_input_vector_declare; - node_type_init(&ntype, blender::nodes::fn_node_input_vector_init); + fn_node_type_base(&ntype, FN_NODE_INPUT_VECTOR, "Vector", 0); + ntype.declare = file_ns::fn_node_input_vector_declare; + node_type_init(&ntype, file_ns::fn_node_input_vector_init); node_type_storage( &ntype, "NodeInputVector", node_free_standard_storage, node_copy_standard_storage); - ntype.build_multi_function = blender::nodes::fn_node_input_vector_build_multi_function; - ntype.draw_buttons = blender::nodes::fn_node_input_vector_layout; + ntype.build_multi_function = file_ns::fn_node_input_vector_build_multi_function; + ntype.draw_buttons = file_ns::fn_node_input_vector_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc index b053482c99d..ceea6246cb0 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -24,7 +24,7 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_fn_random_value_cc { NODE_STORAGE_FUNCS(NodeRandomValue) @@ -63,7 +63,7 @@ static void fn_node_random_value_layout(uiLayout *layout, bContext *UNUSED(C), P static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeRandomValue *data = (NodeRandomValue *)MEM_callocN(sizeof(NodeRandomValue), __func__); + NodeRandomValue *data = MEM_cnew<NodeRandomValue>(__func__); data->data_type = CD_PROP_FLOAT; node->storage = data; } @@ -110,9 +110,8 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock case SOCK_INT: return CD_PROP_INT32; case SOCK_VECTOR: - return CD_PROP_FLOAT3; case SOCK_RGBA: - return CD_PROP_COLOR; + return CD_PROP_FLOAT3; default: return {}; } @@ -338,18 +337,21 @@ static void fn_node_random_value_build_multi_function(NodeMultiFunctionBuilder & } } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_random_value_cc void register_node_type_fn_random_value() { + namespace file_ns = blender::nodes::node_fn_random_value_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER, 0); - node_type_init(&ntype, blender::nodes::fn_node_random_value_init); - node_type_update(&ntype, blender::nodes::fn_node_random_value_update); - ntype.draw_buttons = blender::nodes::fn_node_random_value_layout; - ntype.declare = blender::nodes::fn_node_random_value_declare; - ntype.build_multi_function = blender::nodes::fn_node_random_value_build_multi_function; - ntype.gather_link_search_ops = blender::nodes::fn_node_random_value_gather_link_search; + + fn_node_type_base(&ntype, FN_NODE_RANDOM_VALUE, "Random Value", NODE_CLASS_CONVERTER); + node_type_init(&ntype, file_ns::fn_node_random_value_init); + node_type_update(&ntype, file_ns::fn_node_random_value_update); + ntype.draw_buttons = file_ns::fn_node_random_value_layout; + ntype.declare = file_ns::fn_node_random_value_declare; + ntype.build_multi_function = file_ns::fn_node_random_value_build_multi_function; + ntype.gather_link_search_ops = file_ns::fn_node_random_value_gather_link_search; node_type_storage( &ntype, "NodeRandomValue", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/function/nodes/node_fn_replace_string.cc b/source/blender/nodes/function/nodes/node_fn_replace_string.cc index 881a3c68e7d..243cb63d713 100644 --- a/source/blender/nodes/function/nodes/node_fn_replace_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_replace_string.cc @@ -18,7 +18,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_replace_string_cc { static void fn_node_replace_string_declare(NodeDeclarationBuilder &b) { @@ -53,14 +53,16 @@ static void fn_node_replace_string_build_multi_function(NodeMultiFunctionBuilder builder.set_matching_fn(&substring_fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_replace_string_cc void register_node_type_fn_replace_string() { + namespace file_ns = blender::nodes::node_fn_replace_string_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_replace_string_declare; - ntype.build_multi_function = blender::nodes::fn_node_replace_string_build_multi_function; + fn_node_type_base(&ntype, FN_NODE_REPLACE_STRING, "Replace String", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_replace_string_declare; + ntype.build_multi_function = file_ns::fn_node_replace_string_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index 7dbc11fb161..582a9bb10a8 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -24,7 +24,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_rotate_euler_cc { static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b) { @@ -125,15 +125,18 @@ static void fn_node_rotate_euler_build_multi_function(NodeMultiFunctionBuilder & builder.set_matching_fn(fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_rotate_euler_cc void register_node_type_fn_rotate_euler() { + namespace file_ns = blender::nodes::node_fn_rotate_euler_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_rotate_euler_declare; - ntype.draw_buttons = blender::nodes::fn_node_rotate_euler_layout; - node_type_update(&ntype, blender::nodes::fn_node_rotate_euler_update); - ntype.build_multi_function = blender::nodes::fn_node_rotate_euler_build_multi_function; + + fn_node_type_base(&ntype, FN_NODE_ROTATE_EULER, "Rotate Euler", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_rotate_euler_declare; + ntype.draw_buttons = file_ns::fn_node_rotate_euler_layout; + node_type_update(&ntype, file_ns::fn_node_rotate_euler_update); + ntype.build_multi_function = file_ns::fn_node_rotate_euler_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_slice_string.cc b/source/blender/nodes/function/nodes/node_fn_slice_string.cc index 5cb753e8f34..f9d0af5ba9b 100644 --- a/source/blender/nodes/function/nodes/node_fn_slice_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_slice_string.cc @@ -18,7 +18,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_slice_string_cc { static void fn_node_slice_string_declare(NodeDeclarationBuilder &b) { @@ -40,14 +40,16 @@ static void fn_node_slice_string_build_multi_function(NodeMultiFunctionBuilder & builder.set_matching_fn(&slice_fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_slice_string_cc void register_node_type_fn_slice_string() { + namespace file_ns = blender::nodes::node_fn_slice_string_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_slice_string_declare; - ntype.build_multi_function = blender::nodes::fn_node_slice_string_build_multi_function; + fn_node_type_base(&ntype, FN_NODE_SLICE_STRING, "Slice String", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_slice_string_declare; + ntype.build_multi_function = file_ns::fn_node_slice_string_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_string_length.cc b/source/blender/nodes/function/nodes/node_fn_string_length.cc index 63429d35993..8ab56812125 100644 --- a/source/blender/nodes/function/nodes/node_fn_string_length.cc +++ b/source/blender/nodes/function/nodes/node_fn_string_length.cc @@ -20,7 +20,7 @@ #include "node_function_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_fn_string_length_cc { static void fn_node_string_length_declare(NodeDeclarationBuilder &b) { @@ -35,14 +35,16 @@ static void fn_node_string_length_build_multi_function(NodeMultiFunctionBuilder builder.set_matching_fn(&str_len_fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_string_length_cc void register_node_type_fn_string_length() { + namespace file_ns = blender::nodes::node_fn_string_length_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_string_length_declare; - ntype.build_multi_function = blender::nodes::fn_node_string_length_build_multi_function; + fn_node_type_base(&ntype, FN_NODE_STRING_LENGTH, "String Length", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_string_length_declare; + ntype.build_multi_function = file_ns::fn_node_string_length_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc index 96a56760664..235c612dc15 100644 --- a/source/blender/nodes/function/nodes/node_fn_value_to_string.cc +++ b/source/blender/nodes/function/nodes/node_fn_value_to_string.cc @@ -17,7 +17,7 @@ #include "node_function_util.hh" #include <iomanip> -namespace blender::nodes { +namespace blender::nodes::node_fn_value_to_string_cc { static void fn_node_value_to_string_declare(NodeDeclarationBuilder &b) { @@ -37,14 +37,16 @@ static void fn_node_value_to_string_build_multi_function(NodeMultiFunctionBuilde builder.set_matching_fn(&to_str_fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_fn_value_to_string_cc void register_node_type_fn_value_to_string() { + namespace file_ns = blender::nodes::node_fn_value_to_string_cc; + static bNodeType ntype; - fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::fn_node_value_to_string_declare; - ntype.build_multi_function = blender::nodes::fn_node_value_to_string_build_multi_function; + fn_node_type_base(&ntype, FN_NODE_VALUE_TO_STRING, "Value to String", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::fn_node_value_to_string_declare; + ntype.build_multi_function = file_ns::fn_node_value_to_string_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt index f9a64381981..e0c31fad97f 100644 --- a/source/blender/nodes/geometry/CMakeLists.txt +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -80,6 +80,7 @@ set(SRC nodes/legacy/node_geo_legacy_subdivision_surface.cc nodes/legacy/node_geo_legacy_volume_to_mesh.cc + nodes/node_geo_accumulate_field.cc nodes/node_geo_attribute_capture.cc nodes/node_geo_attribute_domain_size.cc nodes/node_geo_attribute_remove.cc @@ -105,8 +106,8 @@ set(SRC nodes/node_geo_curve_reverse.cc nodes/node_geo_curve_sample.cc nodes/node_geo_curve_set_handles.cc - nodes/node_geo_curve_spline_type.cc nodes/node_geo_curve_spline_parameter.cc + nodes/node_geo_curve_spline_type.cc nodes/node_geo_curve_subdivide.cc nodes/node_geo_curve_to_mesh.cc nodes/node_geo_curve_to_points.cc @@ -123,6 +124,7 @@ set(SRC nodes/node_geo_input_index.cc nodes/node_geo_input_material_index.cc nodes/node_geo_input_material.cc + nodes/node_geo_input_mesh_edge_angle.cc nodes/node_geo_input_mesh_edge_neighbors.cc nodes/node_geo_input_mesh_edge_vertices.cc nodes/node_geo_input_mesh_face_area.cc diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc index 89ab4d9961e..a6dec71ed06 100644 --- a/source/blender/nodes/geometry/node_geometry_tree.cc +++ b/source/blender/nodes/geometry/node_geometry_tree.cc @@ -32,6 +32,8 @@ #include "RNA_access.h" +#include "UI_resources.h" + #include "node_common.h" bNodeTreeType *ntreeType_Geometry; @@ -121,7 +123,7 @@ void register_node_tree_type_geo() tt->type = NTREE_GEOMETRY; strcpy(tt->idname, "GeometryNodeTree"); strcpy(tt->ui_name, N_("Geometry Node Editor")); - tt->ui_icon = 0; /* Defined in `drawnode.c`. */ + tt->ui_icon = ICON_NODETREE; strcpy(tt->ui_description, N_("Geometry nodes")); tt->rna_ext.srna = &RNA_GeometryNodeTree; tt->update = geometry_node_tree_update; diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 49991a40c1b..ceb9a7e1467 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -89,9 +89,9 @@ bool geo_node_poll_default(bNodeType *UNUSED(ntype), return true; } -void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) +void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { - node_type_base(ntype, type, name, nclass, flag); + node_type_base(ntype, type, name, nclass); ntype->poll = geo_node_poll_default; ntype->insert_link = node_insert_link_default; ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 3376b75d05b..3a6c5e38f82 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -36,8 +36,7 @@ #include "node_util.h" -void geo_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void geo_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc index 4366c6f9234..36ad4605a4b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc @@ -53,8 +53,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) - MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__); + NodeGeometryAlignRotationToVector *node_storage = MEM_cnew<NodeGeometryAlignRotationToVector>( + __func__); node_storage->axis = GEO_NODE_ALIGN_ROTATION_TO_VECTOR_AXIS_X; node_storage->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; @@ -228,8 +228,7 @@ void register_node_type_geo_align_rotation_to_vector() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ALIGN_ROTATION_TO_VECTOR, "Align Rotation to Vector", - NODE_CLASS_GEOMETRY, - 0); + NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc index 7435152a966..cac2a90a76c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc @@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), - __func__); + NodeAttributeClamp *data = MEM_cnew<NodeAttributeClamp>(__func__); data->data_type = CD_PROP_FLOAT; data->operation = NODE_CLAMP_MINMAX; node->storage = data; @@ -271,7 +270,7 @@ void register_node_type_geo_attribute_clamp() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc index 4efdf786e4e..672dbfdbf86 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc @@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( - sizeof(NodeAttributeColorRamp), __func__); + NodeAttributeColorRamp *node_storage = MEM_cnew<NodeAttributeColorRamp>(__func__); BKE_colorband_init(&node_storage->color_ramp, true); node->storage = node_storage; } @@ -125,11 +124,8 @@ void register_node_type_geo_attribute_color_ramp() static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, - "Attribute Color Ramp", - NODE_CLASS_ATTRIBUTE, - 0); + geo_node_type_base( + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COLOR_RAMP, "Attribute Color Ramp", NODE_CLASS_ATTRIBUTE); node_type_storage( &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc index 7ba64c8db2b..403b9446f75 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc @@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN( - sizeof(NodeAttributeCombineXYZ), __func__); + NodeAttributeCombineXYZ *data = MEM_cnew<NodeAttributeCombineXYZ>(__func__); data->input_type_x = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; data->input_type_y = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; @@ -139,8 +138,7 @@ void register_node_type_geo_attribute_combine_xyz() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMBINE_XYZ, "Attribute Combine XYZ", - NODE_CLASS_ATTRIBUTE, - 0); + NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc index 8aa1adb0cf3..6cec73d76a2 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc @@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare), - __func__); + NodeAttributeCompare *data = MEM_cnew<NodeAttributeCompare>(__func__); data->operation = NODE_COMPARE_GREATER_THAN; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; @@ -348,7 +347,7 @@ void register_node_type_geo_attribute_compare() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc index 28c133871f7..2b13f57e990 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc @@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert), - __func__); + NodeAttributeConvert *data = MEM_cnew<NodeAttributeConvert>(__func__); data->data_type = CD_AUTO_FROM_NAME; data->domain = ATTR_DOMAIN_AUTO; @@ -182,7 +181,7 @@ void register_node_type_geo_attribute_convert() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc index 0a7b5dd8463..8e1e763f1ad 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc @@ -75,8 +75,7 @@ static void node_copy_storage(bNodeTree *UNUSED(dest_ntree), static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap), - __func__); + NodeAttributeCurveMap *data = MEM_cnew<NodeAttributeCurveMap>(__func__); data->data_type = CD_PROP_FLOAT; data->curve_vec = BKE_curvemapping_add(4, -1.0f, -1.0f, 1.0f, 1.0f); @@ -210,7 +209,7 @@ void register_node_type_geo_attribute_curve_map() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE); node_type_update(&ntype, file_ns::node_update); node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc index a05bcf1bed8..a32e3b7412f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc @@ -155,7 +155,7 @@ void register_node_type_geo_attribute_fill() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc index 8ebcf34ad0b..398af087499 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc @@ -51,8 +51,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), - __func__); + NodeAttributeMapRange *data = MEM_cnew<NodeAttributeMapRange>(__func__); data->data_type = CD_PROP_FLOAT; data->interpolation_type = NODE_MAP_RANGE_LINEAR; @@ -425,7 +424,7 @@ void register_node_type_geo_attribute_map_range() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE); ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc index e0a829b4100..3257d2d7358 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc @@ -121,7 +121,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__); + NodeAttributeMath *data = MEM_cnew<NodeAttributeMath>(__func__); data->operation = NODE_MATH_ADD; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; @@ -309,7 +309,7 @@ void register_node_type_geo_attribute_math() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc index 4a110e9690a..c0c30898584 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc @@ -61,8 +61,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix), - "attribute mix node"); + NodeAttributeMix *data = MEM_cnew<NodeAttributeMix>("attribute mix node"); data->blend_type = MA_RAMP_BLEND; data->input_type_factor = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; @@ -248,8 +247,7 @@ void register_node_type_geo_attribute_mix() namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc index 080bf38a740..74dac73f255 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc @@ -44,8 +44,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN( - sizeof(NodeGeometryAttributeProximity), __func__); + NodeGeometryAttributeProximity *node_storage = MEM_cnew<NodeGeometryAttributeProximity>( + __func__); node_storage->target_geometry_element = GEO_NODE_PROXIMITY_TARGET_FACES; node->storage = node_storage; @@ -237,7 +237,7 @@ void register_node_type_geo_legacy_attribute_proximity() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeProximity", diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc index ab2bc7b379c..92a946b225b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc @@ -81,8 +81,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN( - sizeof(NodeAttributeRandomize), __func__); + NodeAttributeRandomize *data = MEM_cnew<NodeAttributeRandomize>(__func__); data->data_type = CD_PROP_FLOAT; data->domain = ATTR_DOMAIN_POINT; data->operation = GEO_NODE_ATTRIBUTE_RANDOMIZE_REPLACE_CREATE; @@ -335,7 +334,7 @@ void register_node_type_geo_legacy_attribute_randomize() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc index bc18cb32e73..ae034d152be 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc @@ -130,8 +130,7 @@ void register_node_type_geo_sample_texture() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE, "Attribute Sample Texture", - NODE_CLASS_ATTRIBUTE, - 0); + NODE_CLASS_ATTRIBUTE); node_type_size_preset(&ntype, NODE_SIZE_LARGE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc index c5aac118baf..960ec540556 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc @@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN( - sizeof(NodeAttributeSeparateXYZ), __func__); + NodeAttributeSeparateXYZ *data = MEM_cnew<NodeAttributeSeparateXYZ>(__func__); data->input_type = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; node->storage = data; } @@ -160,8 +159,7 @@ void register_node_type_geo_attribute_separate_xyz() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_SEPARATE_XYZ, "Attribute Separate XYZ", - NODE_CLASS_ATTRIBUTE, - 0); + NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc index 686edc80f62..b0210f2eb94 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN( - sizeof(NodeGeometryAttributeTransfer), __func__); + NodeGeometryAttributeTransfer *data = MEM_cnew<NodeGeometryAttributeTransfer>(__func__); data->domain = ATTR_DOMAIN_AUTO; node->storage = data; } @@ -517,7 +516,7 @@ void register_node_type_geo_legacy_attribute_transfer() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeTransfer", diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc index 68051e81f57..5b3c3c05a6a 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc @@ -103,8 +103,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN( - sizeof(NodeAttributeVectorMath), __func__); + NodeAttributeVectorMath *data = MEM_cnew<NodeAttributeVectorMath>(__func__); data->operation = NODE_VECTOR_MATH_ADD; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; @@ -560,8 +559,7 @@ void register_node_type_geo_attribute_vector_math() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_MATH, "Attribute Vector Math", - NODE_CLASS_ATTRIBUTE, - 0); + NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc index 1ef50e69775..3738c4ad14d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc @@ -112,8 +112,7 @@ static float3 vector_rotate_around_axis(const float3 vector, static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN( - sizeof(NodeAttributeVectorRotate), __func__); + NodeAttributeVectorRotate *node_storage = MEM_cnew<NodeAttributeVectorRotate>(__func__); node_storage->mode = GEO_NODE_VECTOR_ROTATE_TYPE_AXIS; node_storage->input_type_vector = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; @@ -337,8 +336,7 @@ void register_node_type_geo_attribute_vector_rotate() geo_node_type_base(&ntype, GEO_NODE_LEGACY_ATTRIBUTE_VECTOR_ROTATE, "Attribute Vector Rotate", - NODE_CLASS_ATTRIBUTE, - 0); + NODE_CLASS_ATTRIBUTE); node_type_update(&ntype, file_ns::node_update); node_type_init(&ntype, file_ns::node_init); node_type_size(&ntype, 165, 100, 600); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index e61dee4bee1..51564d8d200 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -213,7 +213,7 @@ void register_node_type_geo_legacy_curve_endpoints() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index 7c550495b41..844baa53962 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -65,8 +65,7 @@ void register_node_type_geo_legacy_curve_reverse() namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index c702e9ff686..780756bcbca 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc @@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( - sizeof(NodeGeometryCurveSelectHandles), __func__); + NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__); data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT; @@ -127,11 +126,8 @@ void register_node_type_geo_legacy_select_by_handle_type() static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, - "Select by Handle Type", - NODE_CLASS_GEOMETRY, - 0); + geo_node_type_base( + &ntype, GEO_NODE_LEGACY_CURVE_SELECT_HANDLES, "Select by Handle Type", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index 1e476d01148..a82b917e817 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( - sizeof(NodeGeometryCurveSetHandles), __func__); + NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__); data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT; @@ -130,7 +129,7 @@ void register_node_type_geo_legacy_curve_set_handles() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_decalre; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index f3599f4328f..6fd82e6a1bb 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -39,8 +39,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( - sizeof(NodeGeometryCurveSplineType), __func__); + NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__); data->spline_type = GEO_NODE_SPLINE_TYPE_POLY; node->storage = data; @@ -288,7 +287,7 @@ void register_node_type_geo_legacy_curve_spline_type() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index 9878402dd35..4621a1656aa 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN( - sizeof(NodeGeometryCurveSubdivide), __func__); + NodeGeometryCurveSubdivide *data = MEM_cnew<NodeGeometryCurveSubdivide>(__func__); data->cuts_type = GEO_NODE_ATTRIBUTE_INPUT_INTEGER; node->storage = data; @@ -379,7 +378,7 @@ void register_node_type_geo_legacy_curve_subdivide() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index 3bd03f3cee0..8555d7cc8a3 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -95,8 +95,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( - sizeof(NodeGeometryCurveToPoints), __func__); + NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__); data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT; node->storage = data; @@ -353,7 +352,7 @@ void register_node_type_geo_legacy_curve_to_points() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index abd75e710ae..0953d05bc36 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -671,7 +671,7 @@ void register_node_type_geo_legacy_delete_geometry() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc index c046fda4686..e628edb7e17 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc @@ -84,7 +84,7 @@ void register_node_type_geo_legacy_edge_split() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc index 88e8374f5d6..8fd6b1e299f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc @@ -90,7 +90,7 @@ void register_node_type_geo_legacy_material_assign() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index 2ff7410f3f6..d026fff003f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -73,8 +73,7 @@ void register_node_type_geo_legacy_mesh_to_curve() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc index 2451a7447ec..c712e82ca18 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc @@ -662,7 +662,7 @@ void register_node_type_geo_point_distribute() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY); node_type_update(&ntype, file_ns::node_point_distribute_update); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc index 8915a58feb1..faf0b1a5fe7 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc @@ -46,8 +46,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN( - sizeof(NodeGeometryPointInstance), __func__); + NodeGeometryPointInstance *data = MEM_cnew<NodeGeometryPointInstance>(__func__); data->instance_type = GEO_NODE_POINT_INSTANCE_TYPE_OBJECT; data->flag |= GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION; node->storage = data; @@ -271,7 +270,7 @@ void register_node_type_geo_point_instance() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc index a0a7674797a..ad87ec5541b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc @@ -59,8 +59,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN( - sizeof(NodeGeometryRotatePoints), __func__); + NodeGeometryRotatePoints *node_storage = MEM_cnew<NodeGeometryRotatePoints>(__func__); node_storage->type = GEO_NODE_POINT_ROTATE_TYPE_EULER; node_storage->space = GEO_NODE_POINT_ROTATE_SPACE_OBJECT; @@ -226,7 +225,7 @@ void register_node_type_geo_point_rotate() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc index d38df124979..69e69a24e29 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc @@ -43,8 +43,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN( - sizeof(NodeGeometryPointScale), __func__); + NodeGeometryPointScale *data = MEM_cnew<NodeGeometryPointScale>(__func__); data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; node->storage = data; @@ -128,7 +127,7 @@ void register_node_type_geo_point_scale() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc index 9260928b311..b9760587706 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc @@ -171,7 +171,7 @@ void register_node_type_geo_point_separate() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc index c70478182ec..385c3d9f22d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc @@ -74,8 +74,7 @@ static void node_geo_exec(GeoNodeExecParams params) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN( - sizeof(NodeGeometryPointTranslate), __func__); + NodeGeometryPointTranslate *data = MEM_cnew<NodeGeometryPointTranslate>(__func__); data->input_type = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; node->storage = data; @@ -98,7 +97,7 @@ void register_node_type_geo_point_translate() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc index ec1ab67b530..7b1bbed8ae4 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc @@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( - sizeof(NodeGeometryPointsToVolume), __func__); + NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__); data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT; data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; node->storage = data; @@ -266,7 +265,7 @@ void register_node_type_geo_legacy_points_to_volume() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY); node_type_storage(&ntype, "NodeGeometryPointsToVolume", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc index 599ffd617a5..dd03092a594 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc @@ -58,8 +58,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), - __func__); + NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__); data->input_type_ray_direction = GEO_NODE_ATTRIBUTE_INPUT_VECTOR; data->input_type_ray_length = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; node->storage = data; @@ -315,7 +314,7 @@ void register_node_type_geo_legacy_raycast() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc index b61ba5ff67e..59ac697b658 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc @@ -87,7 +87,7 @@ void register_node_type_geo_legacy_select_by_material() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc index 819ffb2c20c..7c5553cb5e4 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc @@ -47,8 +47,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( - sizeof(NodeGeometrySubdivisionSurface), __func__); + NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__); data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL; node->storage = data; @@ -133,7 +132,7 @@ void register_node_type_geo_legacy_subdivision_surface() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc index acff0be7126..42fbc49ed4b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc @@ -57,8 +57,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( - sizeof(NodeGeometryVolumeToMesh), __func__); + NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__); data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID; bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density"); @@ -164,7 +163,7 @@ void register_node_type_geo_legacy_volume_to_mesh() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc new file mode 100644 index 00000000000..6c2e72cf14f --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_accumulate_field.cc @@ -0,0 +1,430 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_attribute_math.hh" + +#include "NOD_socket_search_link.hh" + +#include "node_geometry_util.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +namespace blender::nodes::node_geo_accumulate_field_cc { + +NODE_STORAGE_FUNCS(NodeAccumulateField) + +static void node_declare(NodeDeclarationBuilder &b) +{ + std::string value_in_description = "The values to be accumulated"; + std::string leading_out_description = + "The running total of values in the corresponding group, starting at the first value"; + std::string trailing_out_description = + "The running total of values in the corresponding group, starting at zero"; + std::string total_out_description = "The total of all of the values in the corresponding group"; + + b.add_input<decl::Vector>(N_("Value"), "Value Vector") + .default_value({1.0f, 1.0f, 1.0f}) + .supports_field() + .description(N_(value_in_description)); + b.add_input<decl::Float>(N_("Value"), "Value Float") + .default_value(1.0f) + .supports_field() + .description(N_(value_in_description)); + b.add_input<decl::Int>(N_("Value"), "Value Int") + .default_value(1) + .supports_field() + .description(N_(value_in_description)); + b.add_input<decl::Int>(N_("Group Index")) + .supports_field() + .description( + N_("An index used to group values together for multiple separate accumulations")); + + b.add_output<decl::Vector>(N_("Leading"), "Leading Vector") + .field_source() + .description(N_(leading_out_description)); + b.add_output<decl::Float>(N_("Leading"), "Leading Float") + .field_source() + .description(N_(leading_out_description)); + b.add_output<decl::Int>(N_("Leading"), "Leading Int") + .field_source() + .description(N_(leading_out_description)); + + b.add_output<decl::Vector>(N_("Trailing"), "Trailing Vector") + .field_source() + .description(N_(trailing_out_description)); + b.add_output<decl::Float>(N_("Trailing"), "Trailing Float") + .field_source() + .description(N_(trailing_out_description)); + b.add_output<decl::Int>(N_("Trailing"), "Trailing Int") + .field_source() + .description(N_(trailing_out_description)); + + b.add_output<decl::Vector>(N_("Total"), "Total Vector") + .field_source() + .description(N_(total_out_description)); + b.add_output<decl::Float>(N_("Total"), "Total Float") + .field_source() + .description(N_(total_out_description)); + b.add_output<decl::Int>(N_("Total"), "Total Int") + .field_source() + .description(N_(total_out_description)); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAccumulateField *data = MEM_cnew<NodeAccumulateField>(__func__); + data->data_type = CD_PROP_FLOAT; + data->domain = ATTR_DOMAIN_POINT; + node->storage = data; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + const NodeAccumulateField &storage = node_storage(*node); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + + bNodeSocket *sock_in_vector = (bNodeSocket *)node->inputs.first; + bNodeSocket *sock_in_float = sock_in_vector->next; + bNodeSocket *sock_in_int = sock_in_float->next; + + bNodeSocket *sock_out_vector = (bNodeSocket *)node->outputs.first; + bNodeSocket *sock_out_float = sock_out_vector->next; + bNodeSocket *sock_out_int = sock_out_float->next; + + bNodeSocket *sock_out_first_vector = sock_out_int->next; + bNodeSocket *sock_out_first_float = sock_out_first_vector->next; + bNodeSocket *sock_out_first_int = sock_out_first_float->next; + bNodeSocket *sock_out_total_vector = sock_out_first_int->next; + bNodeSocket *sock_out_total_float = sock_out_total_vector->next; + bNodeSocket *sock_out_total_int = sock_out_total_float->next; + + nodeSetSocketAvailability(ntree, sock_in_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_in_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_in_int, data_type == CD_PROP_INT32); + + nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32); + + nodeSetSocketAvailability(ntree, sock_out_first_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_first_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_first_int, data_type == CD_PROP_INT32); + + nodeSetSocketAvailability(ntree, sock_out_total_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_total_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_total_int, data_type == CD_PROP_INT32); +} + +enum class AccumulationMode { Leading = 0, Trailing = 1 }; + +static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +{ + switch (socket.type) { + case SOCK_FLOAT: + return CD_PROP_FLOAT; + case SOCK_BOOLEAN: + case SOCK_INT: + return CD_PROP_INT32; + case SOCK_VECTOR: + case SOCK_RGBA: + return CD_PROP_FLOAT3; + default: + return {}; + } +} + +static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + if (!type) { + return; + } + if (params.in_out() == SOCK_OUT) { + params.add_item( + IFACE_("Leading"), + [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeAccumulateField"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Leading"); + }, + 0); + params.add_item( + IFACE_("Trailing"), + [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeAccumulateField"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Trailing"); + }, + -1); + params.add_item( + IFACE_("Total"), + [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeAccumulateField"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Total"); + }, + -2); + } + else { + params.add_item( + IFACE_("Value"), + [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeAccumulateField"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Value"); + }, + 0); + + params.add_item( + IFACE_("Group Index"), + [type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node("GeometryNodeAccumulateField"); + node_storage(node).data_type = *type; + params.update_and_connect_available_socket(node, "Group Index"); + }, + -1); + } +} + +template<typename T> class AccumulateFieldInput final : public GeometryFieldInput { + private: + Field<T> input_; + Field<int> group_index_; + AttributeDomain source_domain_; + AccumulationMode accumulation_mode_; + + public: + AccumulateFieldInput(const AttributeDomain source_domain, + Field<T> input, + Field<int> group_index, + AccumulationMode accumulation_mode) + : GeometryFieldInput(CPPType::get<T>(), "Accumulation"), + input_(input), + group_index_(group_index), + source_domain_(source_domain), + accumulation_mode_(accumulation_mode) + { + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + const GeometryComponentFieldContext field_context{component, source_domain_}; + const int domain_size = component.attribute_domain_size(field_context.domain()); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(input_); + evaluator.add(group_index_); + evaluator.evaluate(); + const VArray<T> &values = evaluator.get_evaluated<T>(0); + const VArray<int> &group_indices = evaluator.get_evaluated<int>(1); + + Array<T> accumulations_out(domain_size); + + if (group_indices.is_single()) { + T accumulation = T(); + if (accumulation_mode_ == AccumulationMode::Leading) { + for (const int i : values.index_range()) { + accumulation = values[i] + accumulation; + accumulations_out[i] = accumulation; + } + } + else { + for (const int i : values.index_range()) { + accumulations_out[i] = accumulation; + accumulation = values[i] + accumulation; + } + } + } + else { + Map<int, T> accumulations; + if (accumulation_mode_ == AccumulationMode::Leading) { + for (const int i : values.index_range()) { + T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]); + accumulation_value += values[i]; + accumulations_out[i] = accumulation_value; + } + } + else { + for (const int i : values.index_range()) { + T &accumulation_value = accumulations.lookup_or_add_default(group_indices[i]); + accumulations_out[i] = accumulation_value; + accumulation_value += values[i]; + } + } + } + + return component.attribute_try_adapt_domain<T>( + VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain); + } + + uint64_t hash() const override + { + return get_default_hash_4(input_, group_index_, source_domain_, accumulation_mode_); + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const AccumulateFieldInput *other_accumulate = dynamic_cast<const AccumulateFieldInput *>( + &other)) { + return input_ == other_accumulate->input_ && + group_index_ == other_accumulate->group_index_ && + source_domain_ == other_accumulate->source_domain_ && + accumulation_mode_ == other_accumulate->accumulation_mode_; + } + return false; + } +}; + +template<typename T> class TotalFieldInput final : public GeometryFieldInput { + private: + Field<T> input_; + Field<int> group_index_; + AttributeDomain source_domain_; + + public: + TotalFieldInput(const AttributeDomain source_domain, Field<T> input, Field<int> group_index) + : GeometryFieldInput(CPPType::get<T>(), "Total Value"), + input_(input), + group_index_(group_index), + source_domain_(source_domain) + { + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + const GeometryComponentFieldContext field_context{component, source_domain_}; + const int domain_size = component.attribute_domain_size(field_context.domain()); + + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(input_); + evaluator.add(group_index_); + evaluator.evaluate(); + const VArray<T> &values = evaluator.get_evaluated<T>(0); + const VArray<int> &group_indices = evaluator.get_evaluated<int>(1); + + if (group_indices.is_single()) { + T accumulation = T(); + for (const int i : values.index_range()) { + accumulation = values[i] + accumulation; + } + return VArray<T>::ForSingle(accumulation, domain_size); + } + + Array<T> accumulations_out(domain_size); + Map<int, T> accumulations; + for (const int i : values.index_range()) { + T &value = accumulations.lookup_or_add_default(group_indices[i]); + value = value + values[i]; + } + for (const int i : values.index_range()) { + accumulations_out[i] = accumulations.lookup(group_indices[i]); + } + + return component.attribute_try_adapt_domain<T>( + VArray<T>::ForContainer(std::move(accumulations_out)), source_domain_, domain); + } + + uint64_t hash() const override + { + return get_default_hash_3(input_, group_index_, source_domain_); + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + if (const TotalFieldInput *other_field = dynamic_cast<const TotalFieldInput *>(&other)) { + return input_ == other_field->input_ && group_index_ == other_field->group_index_ && + source_domain_ == other_field->source_domain_; + } + return false; + } +}; + +template<typename T> std::string identifier_suffix() +{ + if constexpr (std::is_same_v<T, int>) { + return "Int"; + } + if constexpr (std::is_same_v<T, float>) { + return "Float"; + } + if constexpr (std::is_same_v<T, float3>) { + return "Vector"; + } +} + +static void node_geo_exec(GeoNodeExecParams params) +{ + const NodeAccumulateField &storage = node_storage(params.node()); + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const AttributeDomain source_domain = static_cast<AttributeDomain>(storage.domain); + + Field<int> group_index_field = params.extract_input<Field<int>>("Group Index"); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (std::is_same_v<T, int> || std::is_same_v<T, float> || + std::is_same_v<T, float3>) { + const std::string suffix = " " + identifier_suffix<T>(); + Field<T> input_field = params.extract_input<Field<T>>("Value" + suffix); + if (params.output_is_required("Leading" + suffix)) { + params.set_output( + "Leading" + suffix, + Field<T>{std::make_shared<AccumulateFieldInput<T>>( + source_domain, input_field, group_index_field, AccumulationMode::Leading)}); + } + if (params.output_is_required("Trailing" + suffix)) { + params.set_output( + "Trailing" + suffix, + Field<T>{std::make_shared<AccumulateFieldInput<T>>( + source_domain, input_field, group_index_field, AccumulationMode::Trailing)}); + } + if (params.output_is_required("Total" + suffix)) { + params.set_output("Total" + suffix, + Field<T>{std::make_shared<TotalFieldInput<T>>( + source_domain, input_field, group_index_field)}); + } + } + }); +} +} // namespace blender::nodes::node_geo_accumulate_field_cc + +void register_node_type_geo_accumulate_field() +{ + namespace file_ns = blender::nodes::node_geo_accumulate_field_cc; + + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ACCUMULATE_FIELD, "Accumulate Field", NODE_CLASS_CONVERTER); + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; + ntype.gather_link_search_ops = file_ns::node_gather_link_searches; + node_type_storage( + &ntype, "NodeAccumulateField", node_free_standard_storage, node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index be0baa706af..9001cb2d1f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -54,8 +54,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN( - sizeof(NodeGeometryAttributeCapture), __func__); + NodeGeometryAttributeCapture *data = MEM_cnew<NodeGeometryAttributeCapture>(__func__); data->data_type = CD_PROP_FLOAT; data->domain = ATTR_DOMAIN_POINT; @@ -235,7 +234,7 @@ void register_node_type_geo_attribute_capture() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_CAPTURE_ATTRIBUTE, "Capture Attribute", NODE_CLASS_ATTRIBUTE); node_type_storage(&ntype, "NodeGeometryAttributeCapture", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc index d6662e4e637..609ef39eb3f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_domain_size.cc @@ -143,8 +143,7 @@ void register_node_type_geo_attribute_domain_size() namespace file_ns = blender::nodes::node_geo_attribute_domain_size_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE, 0); + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_DOMAIN_SIZE, "Domain Size", NODE_CLASS_ATTRIBUTE); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc index 6f26b2c756b..8ed50b2cc75 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc @@ -74,8 +74,7 @@ void register_node_type_geo_attribute_remove() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0); + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index b79125d43d1..7df032b150b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -132,27 +132,24 @@ static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSock static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms) { const bNodeType &node_type = params.node_type(); + const NodeDeclaration &declaration = *params.node_type().fixed_declaration; + search_link_ops_for_declarations(params, declaration.inputs().take_front(2)); + const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + if (!type) { + return; + } + if (params.in_out() == SOCK_IN) { - if (params.other_socket().type == SOCK_GEOMETRY) { - params.add_item(IFACE_("Geometry"), [node_type](LinkSearchOpParams ¶ms) { - bNode &node = params.add_node(node_type); - params.connect_available_socket(node, "Geometry"); - }); - } - if (type) { - params.add_item(IFACE_("Attribute"), [&](LinkSearchOpParams ¶ms) { - bNode &node = params.add_node(node_type); - node.custom1 = *type; - params.update_and_connect_available_socket(node, "Attribute"); - }); - } + params.add_item(IFACE_("Attribute"), [node_type, type](LinkSearchOpParams ¶ms) { + bNode &node = params.add_node(node_type); + node.custom1 = *type; + params.update_and_connect_available_socket(node, "Attribute"); + }); } - else if (type) { - /* Only use the first 8 declarations since we set the type automatically. */ - const NodeDeclaration &declaration = *params.node_type().fixed_declaration; - for (const SocketDeclarationPtr &socket_decl : declaration.outputs().take_front(8)) { - StringRefNull name = socket_decl->name(); + else { + for (const StringRefNull name : + {"Mean", "Median", "Sum", "Min", "Max", "Range", "Standard Deviation", "Variance"}) { params.add_item(IFACE_(name.c_str()), [node_type, name, type](LinkSearchOpParams ¶ms) { bNode &node = params.add_node(node_type); node.custom1 = *type; @@ -402,7 +399,7 @@ void register_node_type_geo_attribute_statistic() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 0947632cc09..a9158e0ef7a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -127,7 +127,7 @@ void register_node_type_geo_boolean() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; ntype.updatefunc = file_ns::node_update; diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index da1f9a00c69..465bd72b57a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -86,7 +86,7 @@ void register_node_type_geo_bounding_box() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index 6b8c895879d..43816b8d8dc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -51,8 +51,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN( - sizeof(NodeGeometryCollectionInfo), __func__); + NodeGeometryCollectionInfo *data = MEM_cnew<NodeGeometryCollectionInfo>(__func__); data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL; node->storage = data; } @@ -163,7 +162,7 @@ void register_node_type_geo_collection_info() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_node_init); node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index 64b7a80bdb4..1e00ea3d896 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -26,7 +26,7 @@ void register_node_type_geo_group() { static bNodeType ntype; - node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP, 0); + node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", NODE_CLASS_GROUP); ntype.type = NODE_GROUP; ntype.poll = geo_node_poll_default; ntype.poll_instance = node_group_poll_instance; diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 56c1e95bd70..11bb8a61df5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -324,7 +324,7 @@ void register_node_type_geo_convex_hull() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index fc407414667..13a3d6534a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -139,7 +139,7 @@ void register_node_type_geo_curve_endpoint_selection() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 3aabf8e21eb..7e09721273a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill), - __func__); + NodeGeometryCurveFill *data = MEM_cnew<NodeGeometryCurveFill>(__func__); data->mode = GEO_NODE_CURVE_FILL_MODE_TRIANGULATED; node->storage = data; @@ -170,7 +169,7 @@ void register_node_type_geo_curve_fill() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index a438c1d6086..1a44fce86a6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN( - sizeof(NodeGeometryCurveFillet), __func__); + NodeGeometryCurveFillet *data = MEM_cnew<NodeGeometryCurveFillet>(__func__); data->mode = GEO_NODE_CURVE_FILLET_BEZIER; node->storage = data; @@ -647,7 +646,7 @@ void register_node_type_geo_curve_fillet() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY); ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index 381bb0fc1d0..e4e87e519f7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -38,8 +38,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( - sizeof(NodeGeometryCurveSelectHandles), __func__); + NodeGeometryCurveSelectHandles *data = MEM_cnew<NodeGeometryCurveSelectHandles>(__func__); data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; data->mode = GEO_NODE_CURVE_HANDLE_LEFT | GEO_NODE_CURVE_HANDLE_RIGHT; @@ -156,7 +155,7 @@ void register_node_type_geo_curve_handle_type_selection() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc index 73ad8a8cf65..21ae88a6852 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc @@ -48,7 +48,7 @@ void register_node_type_geo_curve_length() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index 4299b5cc022..7d84ddf9917 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -62,8 +62,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *) - MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__); + NodeGeometryCurvePrimitiveBezierSegment *data = + MEM_cnew<NodeGeometryCurvePrimitiveBezierSegment>(__func__); data->mode = GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION; node->storage = data; @@ -79,44 +79,29 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( { std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); std::unique_ptr<BezierSpline> spline = std::make_unique<BezierSpline>(); + spline->set_resolution(resolution); + + spline->resize(2); + MutableSpan<float3> positions = spline->positions(); + spline->handle_types_left().fill(BezierSpline::HandleType::Align); + spline->handle_types_right().fill(BezierSpline::HandleType::Align); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); + + positions.first() = start; + positions.last() = end; if (mode == GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT_POSITION) { - spline->add_point(start, - BezierSpline::HandleType::Align, - 2.0f * start - start_handle_right, - BezierSpline::HandleType::Align, - start_handle_right, - 1.0f, - 0.0f); - spline->add_point(end, - BezierSpline::HandleType::Align, - end_handle_left, - BezierSpline::HandleType::Align, - 2.0f * end - end_handle_left, - 1.0f, - 0.0f); + spline->set_handle_position_right(0, start_handle_right); + spline->set_handle_position_left(1, end_handle_left); } else { - spline->add_point(start, - BezierSpline::HandleType::Align, - start - start_handle_right, - BezierSpline::HandleType::Align, - start + start_handle_right, - 1.0f, - 0.0f); - spline->add_point(end, - BezierSpline::HandleType::Align, - end + end_handle_left, - BezierSpline::HandleType::Align, - end - end_handle_left, - 1.0f, - 0.0f); + spline->set_handle_position_right(0, start + start_handle_right); + spline->set_handle_position_left(1, end + end_handle_left); } - spline->set_resolution(resolution); - spline->attributes.reallocate(spline->size()); curve->add_spline(std::move(spline)); - curve->attributes.reallocate(curve->splines().size()); + curve->attributes.reallocate(1); return curve; } @@ -144,7 +129,7 @@ void register_node_type_geo_curve_primitive_bezier_segment() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveBezierSegment", diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index 70abf4c64a7..a7fb493c7d7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -68,8 +68,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN( - sizeof(NodeGeometryCurvePrimitiveCircle), __func__); + NodeGeometryCurvePrimitiveCircle *data = MEM_cnew<NodeGeometryCurvePrimitiveCircle>(__func__); data->mode = GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS; node->storage = data; @@ -232,8 +231,7 @@ void register_node_type_geo_curve_primitive_circle() namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 6d71c97b15a..ff9218b1ac2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN( - sizeof(NodeGeometryCurvePrimitiveLine), __func__); + NodeGeometryCurvePrimitiveLine *data = MEM_cnew<NodeGeometryCurvePrimitiveLine>(__func__); data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS; node->storage = data; @@ -136,7 +135,7 @@ void register_node_type_geo_curve_primitive_line() namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc index 92a9b1b4966..084d27e9d24 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc @@ -50,15 +50,19 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1, std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); + spline->resize(resolution + 1); + MutableSpan<float3> positions = spline->positions(); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); + const float step = 1.0f / resolution; - for (int i : IndexRange(resolution + 1)) { + for (const int i : IndexRange(resolution + 1)) { const float factor = step * i; const float3 q1 = float3::interpolate(p1, p2, factor); const float3 q2 = float3::interpolate(p2, p3, factor); - const float3 out = float3::interpolate(q1, q2, factor); - spline->add_point(out, 1.0f, 0.0f); + positions[i] = float3::interpolate(q1, q2, factor); } - spline->attributes.reallocate(spline->size()); + curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); return curve; @@ -81,11 +85,8 @@ void register_node_type_geo_curve_primitive_quadratic_bezier() namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc; static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, - "Quadratic Bezier", - NODE_CLASS_GEOMETRY, - 0); + geo_node_type_base( + &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index ff6294b9b6b..02e7247fe59 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -89,8 +89,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( - sizeof(NodeGeometryCurvePrimitiveQuad), __func__); + NodeGeometryCurvePrimitiveQuad *data = MEM_cnew<NodeGeometryCurvePrimitiveQuad>(__func__); data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE; node->storage = data; } @@ -113,35 +112,26 @@ static void node_update(bNodeTree *ntree, bNode *node) bNodeSocket *p3 = p2->next; bNodeSocket *p4 = p3->next; - LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - nodeSetSocketAvailability(ntree, sock, false); - } + Vector<bNodeSocket *> available_sockets; if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { - nodeSetSocketAvailability(ntree, width, true); - nodeSetSocketAvailability(ntree, height, true); + available_sockets.extend({width, height}); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { - nodeSetSocketAvailability(ntree, width, true); - nodeSetSocketAvailability(ntree, height, true); - nodeSetSocketAvailability(ntree, offset, true); + available_sockets.extend({width, height, offset}); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { - nodeSetSocketAvailability(ntree, bottom, true); - nodeSetSocketAvailability(ntree, top, true); - nodeSetSocketAvailability(ntree, offset, true); - nodeSetSocketAvailability(ntree, height, true); + available_sockets.extend({bottom, top, offset, height}); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { - nodeSetSocketAvailability(ntree, width, true); - nodeSetSocketAvailability(ntree, bottom_height, true); - nodeSetSocketAvailability(ntree, top_height, true); + available_sockets.extend({width, bottom_height, top_height}); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { - nodeSetSocketAvailability(ntree, p1, true); - nodeSetSocketAvailability(ntree, p2, true); - nodeSetSocketAvailability(ntree, p3, true); - nodeSetSocketAvailability(ntree, p4, true); + available_sockets.extend({p1, p2, p3, p4}); + } + + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { + nodeSetSocketAvailability(ntree, sock, available_sockets.contains(sock)); } } @@ -299,7 +289,7 @@ void register_node_type_geo_curve_primitive_quadrilateral() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc index d5ae3551904..6aba65b5638 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc @@ -65,6 +65,11 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations, const float delta_theta = (M_PI * 2 * rotations) / (float)totalpoints * (direction ? 1.0f : -1.0f); + spline->resize(totalpoints + 1); + MutableSpan<float3> positions = spline->positions(); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); + for (const int i : IndexRange(totalpoints + 1)) { const float theta = i * delta_theta; const float radius = start_radius + i * delta_radius; @@ -72,10 +77,9 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations, const float y = radius * sin(theta); const float z = delta_height * i; - spline->add_point(float3(x, y, z), 1.0f, 0.0f); + positions[i] = {x, y, z}; } - spline->attributes.reallocate(spline->size()); curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); return curve; @@ -107,7 +111,7 @@ void register_node_type_geo_curve_primitive_spiral() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index 731be0f0f49..14517a79037 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -54,19 +54,24 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, { std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>(); std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>(); + spline->set_cyclic(true); + + spline->resize(points * 2); + MutableSpan<float3> positions = spline->positions(); + spline->radii().fill(1.0f); + spline->tilts().fill(0.0f); const float theta_step = (2.0f * M_PI) / float(points); - for (int i : IndexRange(points)) { + for (const int i : IndexRange(points)) { const float x = outer_radius * cos(theta_step * i); const float y = outer_radius * sin(theta_step * i); - spline->add_point(float3(x, y, 0.0f), 1.0f, 0.0f); + positions[i * 2] = {x, y, 0.0f}; const float inner_x = inner_radius * cos(theta_step * i + theta_step * 0.5f + twist); const float inner_y = inner_radius * sin(theta_step * i + theta_step * 0.5f + twist); - spline->add_point(float3(inner_x, inner_y, 0.0f), 1.0f, 0.0f); + positions[i * 2 + 1] = {inner_x, inner_y, 0.0f}; } - spline->set_cyclic(true); - spline->attributes.reallocate(spline->size()); + curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); @@ -110,7 +115,7 @@ void register_node_type_geo_curve_primitive_star() namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index 7e465714265..8494b4868e8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN( - sizeof(NodeGeometryCurveResample), __func__); + NodeGeometryCurveResample *data = MEM_cnew<NodeGeometryCurveResample>(__func__); data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT; node->storage = data; @@ -82,8 +81,11 @@ static SplinePtr resample_spline(const Spline &src, const int count) Spline::copy_base_settings(src, *dst); if (src.evaluated_edges_size() < 1 || count == 1) { - dst->add_point(src.positions().first(), src.radii().first(), src.tilts().first()); - dst->attributes.reallocate(1); + dst->resize(1); + dst->positions().first() = src.positions().first(); + dst->radii().first() = src.radii().first(); + dst->tilts().first() = src.tilts().first(); + src.attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { std::optional<GSpan> src_attribute = src.attributes.get_for_read(attribute_id); @@ -295,7 +297,7 @@ void register_node_type_geo_curve_resample() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index d07e89ec7f2..38974fafce7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -67,7 +67,7 @@ void register_node_type_geo_curve_reverse() namespace file_ns = blender::nodes::node_geo_curve_reverse_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index eff760266f5..038f7625825 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_type_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN( - sizeof(NodeGeometryCurveSample), __func__); + NodeGeometryCurveSample *data = MEM_cnew<NodeGeometryCurveSample>(__func__); data->mode = GEO_NODE_CURVE_SAMPLE_LENGTH; node->storage = data; } @@ -287,7 +286,7 @@ void register_node_type_geo_curve_sample() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, "Sample Curve", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_type_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index 8c0827570c6..b4ca51d0fa7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -40,8 +40,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( - sizeof(NodeGeometryCurveSetHandles), __func__); + NodeGeometryCurveSetHandles *data = MEM_cnew<NodeGeometryCurveSetHandles>(__func__); data->handle_type = GEO_NODE_CURVE_HANDLE_AUTO; data->mode = GEO_NODE_CURVE_HANDLE_LEFT; @@ -136,8 +135,7 @@ void register_node_type_geo_curve_set_handles() namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc index de352d217ed..40dde645756 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_parameter.cc @@ -319,7 +319,7 @@ void register_node_type_geo_curve_spline_parameter() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_CURVE_SPLINE_PARAMETER, "Spline Parameter", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index eef8c1b0db5..5745eb86949 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -41,8 +41,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( - sizeof(NodeGeometryCurveSplineType), __func__); + NodeGeometryCurveSplineType *data = MEM_cnew<NodeGeometryCurveSplineType>(__func__); data->spline_type = GEO_NODE_SPLINE_TYPE_POLY; node->storage = data; @@ -298,8 +297,7 @@ void register_node_type_geo_curve_spline_type() namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index 6de188fc1c4..ae282017e0c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -359,7 +359,7 @@ void register_node_type_geo_curve_subdivide() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index ff3e85cb6b7..ef4fc51d1b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -80,7 +80,7 @@ void register_node_type_geo_curve_to_mesh() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 0e9425246cb..a8553b636a4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -72,8 +72,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( - sizeof(NodeGeometryCurveToPoints), __func__); + NodeGeometryCurveToPoints *data = MEM_cnew<NodeGeometryCurveToPoints>(__func__); data->mode = GEO_NODE_CURVE_RESAMPLE_COUNT; node->storage = data; @@ -403,7 +402,7 @@ void register_node_type_geo_curve_to_points() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 746392a66cc..359863d39e0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim), - __func__); + NodeGeometryCurveTrim *data = MEM_cnew<NodeGeometryCurveTrim>(__func__); data->mode = GEO_NODE_CURVE_SAMPLE_FACTOR; node->storage = data; @@ -608,7 +607,7 @@ void register_node_type_geo_curve_trim() namespace file_ns = blender::nodes::node_geo_curve_trim_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index 1de809b30e4..5ea8034c437 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -529,6 +529,30 @@ static void separate_point_cloud_selection(GeometrySet &geometry_set, geometry_set.replace_pointcloud(pointcloud); } +static void separate_instance_selection(GeometrySet &geometry_set, + const Field<bool> &selection_field, + const bool invert) +{ + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(selection_field); + evaluator.evaluate(); + const VArray_Span<bool> &selection = evaluator.get_evaluated<bool>(0); + + Vector<int64_t> indices; + const IndexMask mask = index_mask_indices(selection, invert, indices); + + if (mask.is_empty()) { + geometry_set.remove<InstancesComponent>(); + return; + } + + instances.remove_instances(mask); +} + static void compute_selected_vertices_from_vertex_selection(const Span<bool> vertex_selection, const bool invert, MutableSpan<int> r_vertex_map, @@ -979,8 +1003,8 @@ static void do_mesh_separation(GeometrySet &geometry_set, /* Needed in all cases. */ Vector<int> selected_poly_indices; Vector<int> new_loop_starts; - int num_selected_polys; - int num_selected_loops; + int num_selected_polys = 0; + int num_selected_loops = 0; const Mesh &mesh_in = *in_component.get_for_read(); Mesh *mesh_out; @@ -1261,7 +1285,7 @@ void separate_geometry(GeometrySet &geometry_set, } } if (geometry_set.has_mesh()) { - if (domain != ATTR_DOMAIN_CURVE) { + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER)) { separate_mesh_selection(geometry_set, selection_field, domain, mode, invert); some_valid_domain = true; } @@ -1272,6 +1296,12 @@ void separate_geometry(GeometrySet &geometry_set, some_valid_domain = true; } } + if (geometry_set.has_instances()) { + if (domain == ATTR_DOMAIN_INSTANCE) { + separate_instance_selection(geometry_set, selection_field, invert); + some_valid_domain = true; + } + } r_is_error = !some_valid_domain && geometry_set.has_realized_data(); } @@ -1307,8 +1337,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( - sizeof(NodeGeometryDeleteGeometry), __func__); + NodeGeometryDeleteGeometry *data = MEM_cnew<NodeGeometryDeleteGeometry>(__func__); data->domain = ATTR_DOMAIN_POINT; data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; @@ -1348,7 +1377,7 @@ void register_node_type_geo_delete_geometry() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY); node_type_storage(&ntype, "NodeGeometryDeleteGeometry", diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 3537b62c76e..a257af4391c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -573,8 +573,7 @@ void register_node_type_geo_distribute_points_on_faces() geo_node_type_base(&ntype, GEO_NODE_DISTRIBUTE_POINTS_ON_FACES, "Distribute Points on Faces", - NODE_CLASS_GEOMETRY, - 0); + NODE_CLASS_GEOMETRY); node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update); node_type_size(&ntype, 170, 100, 320); ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc index a3bbeca7af3..ed4def0cf68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_dual_mesh.cc @@ -537,6 +537,77 @@ static void add_edge(const Mesh &mesh, loop_edges.append(new_edge_i); } +/* Returns true if the vertex is connected only to the two polygons and is not on the boundary. */ +static bool vertex_needs_dissolving(const int vertex, + const int first_poly_index, + const int second_poly_index, + const Span<VertexType> vertex_types, + const Span<Vector<int>> vertex_poly_indices) +{ + /* Order is guaranteed to be the same because 2poly verts that are not on the boundary are + * ignored in `sort_vertex_polys`. */ + return (vertex_types[vertex] != VertexType::Boundary && + vertex_poly_indices[vertex].size() == 2 && + vertex_poly_indices[vertex][0] == first_poly_index && + vertex_poly_indices[vertex][1] == second_poly_index); +} + +/** + * Finds 'normal' vertices which are connected to only two polygons and marks them to not be + * used in the datastructures derived from the mesh. For each pair of polygons which has such a + * vertex, an edge is created for the dual mesh between the centers of those two polygons. All + * edges in the input mesh which contain such a vertex are marked as 'done' to prevent duplicate + * edges being created. (See T94144) + */ +static void dissolve_redundant_verts(const Mesh &mesh, + const Span<Vector<int>> vertex_poly_indices, + MutableSpan<VertexType> vertex_types, + MutableSpan<int> old_to_new_edges_map, + Vector<MEdge> &new_edges, + Vector<int> &new_to_old_edges_map) +{ + for (const int vert_i : IndexRange(mesh.totvert)) { + if (vertex_poly_indices[vert_i].size() != 2 || vertex_types[vert_i] != VertexType::Normal) { + continue; + } + const int first_poly_index = vertex_poly_indices[vert_i][0]; + const int second_poly_index = vertex_poly_indices[vert_i][1]; + const int new_edge_index = new_edges.size(); + bool edge_created = false; + const MPoly &poly = mesh.mpoly[first_poly_index]; + for (const MLoop &loop : Span<MLoop>(&mesh.mloop[poly.loopstart], poly.totloop)) { + const MEdge &edge = mesh.medge[loop.e]; + const int v1 = edge.v1; + const int v2 = edge.v2; + bool mark_edge = false; + if (vertex_needs_dissolving( + v1, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) { + /* This vertex is now 'removed' and should be ignored elsewhere. */ + vertex_types[v1] = VertexType::Loose; + mark_edge = true; + } + if (vertex_needs_dissolving( + v2, first_poly_index, second_poly_index, vertex_types, vertex_poly_indices)) { + /* This vertex is now 'removed' and should be ignored elsewhere. */ + vertex_types[v2] = VertexType::Loose; + mark_edge = true; + } + if (mark_edge) { + if (!edge_created) { + MEdge new_edge = MEdge(edge); + /* The vertex indices in the dual mesh are the polygon indices of the input mesh. */ + new_edge.v1 = first_poly_index; + new_edge.v2 = second_poly_index; + new_to_old_edges_map.append(loop.e); + new_edges.append(new_edge); + edge_created = true; + } + old_to_new_edges_map[loop.e] = new_edge_index; + } + } + } +} + /** * Calculate the barycentric dual of a mesh. The dual is only "dual" in terms of connectivity, * i.e. applying the function twice will give the same vertices, edges, and faces, but not the @@ -564,6 +635,9 @@ static void calc_dual_mesh(GeometrySet &geometry_set, Array<VertexType> vertex_types(mesh_in.totvert); Array<EdgeType> edge_types(mesh_in.totedge); calc_boundaries(mesh_in, vertex_types, edge_types); + /* Stores the indices of the polygons connected to the vertex. Because the polygons are looped + * over in order of their indices, the polygon's indices will be sorted in ascending order. + (This can change once they are sorted using `sort_vertex_polys`). */ Array<Vector<int>> vertex_poly_indices(mesh_in.totvert); Array<Array<int>> vertex_shared_edges(mesh_in.totvert); Array<Array<int>> vertex_corners(mesh_in.totvert); @@ -632,6 +706,16 @@ static void calc_dual_mesh(GeometrySet &geometry_set, * don't need a hashmap for that. */ Array<int> old_to_new_edges_map(mesh_in.totedge); old_to_new_edges_map.fill(-1); + + /* This is necessary to prevent duplicate edges from being created, but will likely not do + * anything for most meshes. */ + dissolve_redundant_verts(mesh_in, + vertex_poly_indices, + vertex_types, + old_to_new_edges_map, + new_edges, + new_to_old_edges_map); + for (const int i : IndexRange(mesh_in.totvert)) { if (vertex_types[i] == VertexType::Loose || vertex_types[i] >= VertexType::NonManifold || (!keep_boundaries && vertex_types[i] == VertexType::Boundary)) { @@ -840,7 +924,7 @@ void register_node_type_geo_dual_mesh() namespace file_ns = blender::nodes::node_geo_dual_mesh_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_DUAL_MESH, "Dual Mesh", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index d23a18ba37b..9376789cf2c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -90,7 +90,7 @@ void register_node_type_geo_edge_split() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc index 7faf104737f..f65af5b6737 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_geometry_to_instance.cc @@ -47,7 +47,7 @@ void register_node_type_geo_geometry_to_instance() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_GEOMETRY_TO_INSTANCE, "Geometry to Instance", NODE_CLASS_GEOMETRY); node_type_size(&ntype, 160, 100, 300); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc index 0003f15854d..28a8fb80294 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc @@ -55,8 +55,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN( - sizeof(NodeGeometryImageTexture), __func__); + NodeGeometryImageTexture *tex = MEM_cnew<NodeGeometryImageTexture>(__func__); node->storage = tex; } @@ -416,7 +415,7 @@ void register_node_type_geo_image_texture() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0); + geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE); ntype.declare = file_ns::node_declare; ntype.draw_buttons = file_ns::node_layout; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index dae8fda2099..c3c26736e88 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -40,7 +40,7 @@ void register_node_type_geo_input_curve_handles() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc index 5ba85b6f34e..61b4b6bb9e9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_curve_tilt() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc index d2e103a093a..3fe0588a46d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_id() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc index 74cddfc6a4a..98c2c9d58f0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_index() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc index 1b6e3c8fc68..a1c905fccaa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc @@ -45,7 +45,7 @@ void register_node_type_geo_input_material() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT); ntype.draw_buttons = file_ns::node_layout; ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc index 4df218eb669..fca29feb73c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_material_index() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc new file mode 100644 index 00000000000..2d16c60ba86 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_angle.cc @@ -0,0 +1,128 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_input_mesh_edge_angle_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Float>(N_("Angle")) + .field_source() + .description( + "The angle in radians between two faces where they meet at an edge. Flat edges and " + "Non-manifold edges have an angle of zero"); +} + +struct EdgeMapEntry { + int face_count; + int face_index_1; + int face_index_2; +}; + +class AngleFieldInput final : public GeometryFieldInput { + public: + AngleFieldInput() : GeometryFieldInput(CPPType::get<float>(), "Angle Field") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const GeometryComponent &component, + const AttributeDomain domain, + IndexMask UNUSED(mask)) const final + { + if (component.type() != GEO_COMPONENT_TYPE_MESH) { + return {}; + } + + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + if (mesh == nullptr) { + return {}; + } + + Span<MPoly> polys{mesh->mpoly, mesh->totpoly}; + Span<MLoop> loops{mesh->mloop, mesh->totloop}; + Array<EdgeMapEntry> edge_map(mesh->totedge, {0, 0, 0}); + + for (const int i_poly : polys.index_range()) { + const MPoly &mpoly = polys[i_poly]; + for (const MLoop &loop : loops.slice(mpoly.loopstart, mpoly.totloop)) { + EdgeMapEntry &entry = edge_map[loop.e]; + if (entry.face_count == 0) { + entry.face_index_1 = i_poly; + } + else if (entry.face_count == 1) { + entry.face_index_2 = i_poly; + } + entry.face_count++; + } + } + + auto angle_fn = [edge_map, polys, loops, mesh](const int i) -> float { + if (edge_map[i].face_count == 2) { + const MPoly &mpoly_1 = polys[edge_map[i].face_index_1]; + const MPoly &mpoly_2 = polys[edge_map[i].face_index_2]; + float3 normal_1, normal_2; + BKE_mesh_calc_poly_normal(&mpoly_1, &loops[mpoly_1.loopstart], mesh->mvert, normal_1); + BKE_mesh_calc_poly_normal(&mpoly_2, &loops[mpoly_2.loopstart], mesh->mvert, normal_2); + return angle_normalized_v3v3(normal_1, normal_2); + } + else { + return 0.0f; + } + }; + + VArray<float> angles = VArray<float>::ForFunc(mesh->totedge, angle_fn); + return component.attribute_try_adapt_domain<float>( + std::move(angles), ATTR_DOMAIN_EDGE, domain); + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 32426725235; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const AngleFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + Field<float> angle_field{std::make_shared<AngleFieldInput>()}; + params.set_output("Angle", std::move(angle_field)); +} + +} // namespace blender::nodes::node_geo_input_mesh_edge_angle_cc + +void register_node_type_geo_input_mesh_edge_angle() +{ + namespace file_ns = blender::nodes::node_geo_input_mesh_edge_angle_cc; + + static bNodeType ntype; + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_ANGLE, "Edge Angle", NODE_CLASS_INPUT); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc index ede87252312..ddeb3ded511 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_neighbors.cc @@ -86,7 +86,7 @@ void register_node_type_geo_input_mesh_edge_neighbors() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_INPUT_MESH_EDGE_NEIGHBORS, "Edge Neighbors", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc index 473bef63e92..f54c92fea7b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_edge_vertices.cc @@ -50,12 +50,11 @@ static VArray<int> construct_edge_vertices_gvarray(const MeshComponent &componen return {}; } if (domain == ATTR_DOMAIN_EDGE) { - if (vertex == VERTEX_ONE) { - return VArray<int>::ForFunc(mesh->totpoly, + return VArray<int>::ForFunc(mesh->totedge, [mesh](const int i) -> int { return mesh->medge[i].v1; }); } - return VArray<int>::ForFunc(mesh->totpoly, + return VArray<int>::ForFunc(mesh->totedge, [mesh](const int i) -> int { return mesh->medge[i].v2; }); } return {}; @@ -180,8 +179,7 @@ void register_node_type_geo_input_mesh_edge_vertices() namespace file_ns = blender::nodes::node_geo_input_mesh_edge_vertices_cc; static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_EDGE_VERTICES, "Edge Vertices", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc index 538b9e9682d..ef8adff48f1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_area.cc @@ -89,7 +89,7 @@ void register_node_type_geo_input_mesh_face_area() namespace file_ns = blender::nodes::node_geo_input_mesh_face_area_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_FACE_AREA, "Face Area", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc index 80bb25dc7ca..8d196e5f8dd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_face_neighbors.cc @@ -150,7 +150,7 @@ void register_node_type_geo_input_mesh_face_neighbors() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_INPUT_MESH_FACE_NEIGHBORS, "Face Neighbors", NODE_CLASS_INPUT); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc index 3c713ef6ca9..629279a44e9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_island.cc @@ -94,7 +94,7 @@ void register_node_type_geo_input_mesh_island() namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc index 05140c92205..7d79164634d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_mesh_vertex_neighbors.cc @@ -148,7 +148,7 @@ void register_node_type_geo_input_mesh_vertex_neighbors() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_INPUT_MESH_VERTEX_NEIGHBORS, "Vertex Neighbors", NODE_CLASS_INPUT); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 1cc508d9d9d..86c2b0e4543 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -282,7 +282,7 @@ void register_node_type_geo_input_normal() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc index 8322831a871..beb528d2fd8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_position() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc index 26fb74f5a5b..c7777da08c6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_radius() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc index cfc1a81f7b9..4ed65e99a1c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_scene_time.cc @@ -43,7 +43,7 @@ void register_node_type_geo_input_scene_time() { static bNodeType ntype; namespace file_ns = blender::nodes::node_geo_input_scene_time_cc; - geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_SCENE_TIME, "Scene Time", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index 3efe8577e51..b27ab097223 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -37,7 +37,7 @@ void register_node_type_geo_input_shade_smooth() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc index 5f833445a76..2db00a1ae68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc @@ -37,8 +37,7 @@ void register_node_type_geo_input_spline_cyclic() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 810d6e2fddd..b8c8ce840eb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -156,7 +156,7 @@ void register_node_type_geo_input_spline_length() namespace file_ns = blender::nodes::node_geo_input_spline_length_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc index 77b6e27e6a2..d79f2ffd64d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc @@ -38,7 +38,7 @@ void register_node_type_geo_input_spline_resolution() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0); + &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 86f882df3cd..f80fdfbf334 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -161,7 +161,7 @@ void register_node_type_geo_input_tangent() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index 486f90760f5..66ac618be5f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -259,7 +259,7 @@ void register_node_type_geo_instance_on_points() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index 9942e388ba5..f9beed956bb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -130,7 +130,7 @@ void register_node_type_geo_instances_to_points() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc index 5925d440317..c97bbad4665 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc @@ -42,7 +42,7 @@ void register_node_type_geo_is_viewport() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index bf7a9f49829..1e521af6b13 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -180,8 +180,7 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet InstancesComponent &instances = instances_geometry_set.get_component_for_write<InstancesComponent>(); - if constexpr (std::is_same_v<Component, InstancesComponent> || - std::is_same_v<Component, VolumeComponent>) { + if constexpr (is_same_any_v<Component, InstancesComponent, VolumeComponent>) { join_components(components, result); } else { @@ -221,7 +220,7 @@ void register_node_type_geo_join_geometry() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc index 5a334126350..0309121db74 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc @@ -63,8 +63,7 @@ void register_node_type_geo_material_replace() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 2aad68e7c25..0b5f0bf34c5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -122,7 +122,7 @@ void register_node_type_geo_material_selection() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 7a1cb8a62a3..b07d809a091 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN( - sizeof(NodeGeometryMeshCircle), __func__); + NodeGeometryMeshCircle *node_storage = MEM_cnew<NodeGeometryMeshCircle>(__func__); node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NONE; @@ -214,8 +213,6 @@ static void node_geo_exec(GeoNodeExecParams params) Mesh *mesh = create_circle_mesh(radius, verts_num, fill); - BLI_assert(BKE_mesh_is_valid(mesh)); - params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } @@ -227,8 +224,7 @@ void register_node_type_geo_mesh_primitive_circle() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 70b093798f8..2aa9522cf56 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -770,8 +770,7 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( - sizeof(NodeGeometryMeshCone), __func__); + NodeGeometryMeshCone *node_storage = MEM_cnew<NodeGeometryMeshCone>(__func__); node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; @@ -879,7 +878,7 @@ void register_node_type_geo_mesh_primitive_cone() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index 2542542c919..e90a9eb393b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -527,7 +527,7 @@ void register_node_type_geo_mesh_primitive_cube() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index b8d2ed3be92..73f21cf31fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -71,8 +71,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN( - sizeof(NodeGeometryMeshCylinder), __func__); + NodeGeometryMeshCylinder *node_storage = MEM_cnew<NodeGeometryMeshCylinder>(__func__); node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; @@ -168,7 +167,7 @@ void register_node_type_geo_mesh_primitive_cylinder() namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc; static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage( diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index 77634a03af6..2c4b5df6030 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BLI_task.hh" + #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" @@ -38,11 +40,13 @@ static void calculate_uvs( const float dx = (size_x == 0.0f) ? 0.0f : 1.0f / size_x; const float dy = (size_y == 0.0f) ? 0.0f : 1.0f / size_y; - for (const int i : loops.index_range()) { - const float3 &co = verts[loops[i].v].co; - uvs[i].x = (co.x + size_x * 0.5f) * dx; - uvs[i].y = (co.y + size_y * 0.5f) * dy; - } + threading::parallel_for(loops.index_range(), 1024, [&](IndexRange range) { + for (const int i : range) { + const float3 &co = verts[loops[i].v].co; + uvs[i].x = (co.x + size_x * 0.5f) * dx; + uvs[i].y = (co.y + size_y * 0.5f) * dy; + } + }); uv_attribute.save(); } @@ -70,72 +74,95 @@ Mesh *create_grid_mesh(const int verts_x, const float dy = edges_y == 0 ? 0.0f : size_y / edges_y; const float x_shift = edges_x / 2.0f; const float y_shift = edges_y / 2.0f; - for (const int x_index : IndexRange(verts_x)) { - for (const int y_index : IndexRange(verts_y)) { - const int vert_index = x_index * verts_y + y_index; - verts[vert_index].co[0] = (x_index - x_shift) * dx; - verts[vert_index].co[1] = (y_index - y_shift) * dy; - verts[vert_index].co[2] = 0.0f; + threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) { + for (const int x : x_range) { + const int y_offset = x * verts_y; + threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) { + for (const int y : y_range) { + const int vert_index = y_offset + y; + verts[vert_index].co[0] = (x - x_shift) * dx; + verts[vert_index].co[1] = (y - y_shift) * dy; + verts[vert_index].co[2] = 0.0f; + } + }); } - } + }); } /* Point all vertex normals in the up direction. */ - const short up_normal[3] = {0, 0, SHRT_MAX}; - for (MVert &vert : verts) { - copy_v3_v3_short(vert.no, up_normal); + { + const short up_normal[3] = {0, 0, SHRT_MAX}; + for (MVert &vert : verts) { + copy_v3_v3_short(vert.no, up_normal); + } } - /* Build the horizontal edges in the X direction. */ const int y_edges_start = 0; + const int x_edges_start = verts_x * edges_y; const short edge_flag = (edges_x == 0 || edges_y == 0) ? ME_LOOSEEDGE : ME_EDGEDRAW | ME_EDGERENDER; - int edge_index = 0; - for (const int x : IndexRange(verts_x)) { - for (const int y : IndexRange(edges_y)) { - const int vert_index = x * verts_y + y; - MEdge &edge = edges[edge_index++]; - edge.v1 = vert_index; - edge.v2 = vert_index + 1; - edge.flag = edge_flag; + + /* Build the horizontal edges in the X direction. */ + threading::parallel_for(IndexRange(verts_x), 512, [&](IndexRange x_range) { + for (const int x : x_range) { + const int y_vert_offset = x * verts_y; + const int y_edge_offset = y_edges_start + x * edges_y; + threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) { + for (const int y : y_range) { + const int vert_index = y_vert_offset + y; + MEdge &edge = edges[y_edge_offset + y]; + edge.v1 = vert_index; + edge.v2 = vert_index + 1; + edge.flag = edge_flag; + } + }); } - } + }); /* Build the vertical edges in the Y direction. */ - const int x_edges_start = edge_index; - for (const int y : IndexRange(verts_y)) { - for (const int x : IndexRange(edges_x)) { - const int vert_index = x * verts_y + y; - MEdge &edge = edges[edge_index++]; - edge.v1 = vert_index; - edge.v2 = vert_index + verts_y; - edge.flag = edge_flag; + threading::parallel_for(IndexRange(verts_y), 512, [&](IndexRange y_range) { + for (const int y : y_range) { + const int x_edge_offset = x_edges_start + y * edges_x; + threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) { + for (const int x : x_range) { + const int vert_index = x * verts_y + y; + MEdge &edge = edges[x_edge_offset + x]; + edge.v1 = vert_index; + edge.v2 = vert_index + verts_y; + edge.flag = edge_flag; + } + }); } - } - - int loop_index = 0; - int poly_index = 0; - for (const int x : IndexRange(edges_x)) { - for (const int y : IndexRange(edges_y)) { - MPoly &poly = polys[poly_index++]; - poly.loopstart = loop_index; - poly.totloop = 4; - const int vert_index = x * verts_y + y; - - MLoop &loop_a = loops[loop_index++]; - loop_a.v = vert_index; - loop_a.e = x_edges_start + edges_x * y + x; - MLoop &loop_b = loops[loop_index++]; - loop_b.v = vert_index + verts_y; - loop_b.e = y_edges_start + edges_y * (x + 1) + y; - MLoop &loop_c = loops[loop_index++]; - loop_c.v = vert_index + verts_y + 1; - loop_c.e = x_edges_start + edges_x * (y + 1) + x; - MLoop &loop_d = loops[loop_index++]; - loop_d.v = vert_index + 1; - loop_d.e = y_edges_start + edges_y * x + y; + }); + + threading::parallel_for(IndexRange(edges_x), 512, [&](IndexRange x_range) { + for (const int x : x_range) { + const int y_offset = x * edges_y; + threading::parallel_for(IndexRange(edges_y), 512, [&](IndexRange y_range) { + for (const int y : y_range) { + const int poly_index = y_offset + y; + const int loop_index = poly_index * 4; + MPoly &poly = polys[poly_index]; + poly.loopstart = loop_index; + poly.totloop = 4; + const int vert_index = x * verts_y + y; + + MLoop &loop_a = loops[loop_index]; + loop_a.v = vert_index; + loop_a.e = x_edges_start + edges_x * y + x; + MLoop &loop_b = loops[loop_index + 1]; + loop_b.v = vert_index + verts_y; + loop_b.e = y_edges_start + edges_y * (x + 1) + y; + MLoop &loop_c = loops[loop_index + 2]; + loop_c.v = vert_index + verts_y + 1; + loop_c.e = x_edges_start + edges_x * (y + 1) + x; + MLoop &loop_d = loops[loop_index + 3]; + loop_d.v = vert_index + 1; + loop_d.e = y_edges_start + edges_y * x + y; + } + }); } - } + }); if (mesh->totpoly != 0) { calculate_uvs(mesh, verts, loops, size_x, size_y); @@ -185,7 +212,6 @@ static void node_geo_exec(GeoNodeExecParams params) } Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y); - BLI_assert(BKE_mesh_is_valid(mesh)); BKE_id_material_eval_ensure_default_slot(&mesh->id); params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); @@ -199,7 +225,7 @@ void register_node_type_geo_mesh_primitive_grid() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index 5f483a95063..28a505c5bb8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -87,7 +87,7 @@ void register_node_type_geo_mesh_primitive_ico_sphere() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index 9a87c040bdf..5116e78fdda 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -67,8 +67,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN( - sizeof(NodeGeometryMeshLine), __func__); + NodeGeometryMeshLine *node_storage = MEM_cnew<NodeGeometryMeshLine>(__func__); node_storage->mode = GEO_NODE_MESH_LINE_MODE_OFFSET; node_storage->count_mode = GEO_NODE_MESH_LINE_COUNT_TOTAL; @@ -225,7 +224,7 @@ void register_node_type_geo_mesh_primitive_line() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index ce2e0923a30..373e6bfdd18 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -287,8 +287,6 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const calculate_sphere_uvs(mesh, segments, rings); - BLI_assert(BKE_mesh_is_valid(mesh)); - return mesh; } @@ -321,8 +319,7 @@ void register_node_type_geo_mesh_primitive_uv_sphere() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index 1ec9808044f..6d8a2fac8ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -105,7 +105,7 @@ void register_node_type_geo_mesh_subdivide() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index 90f0af75788..0f0fb3c230a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -64,7 +64,7 @@ void register_node_type_geo_mesh_to_curve() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 77314341fec..d0546cd2583 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -50,8 +50,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN( - sizeof(NodeGeometryMeshToPoints), __func__); + NodeGeometryMeshToPoints *data = MEM_cnew<NodeGeometryMeshToPoints>(__func__); data->mode = GEO_NODE_MESH_TO_POINTS_VERTICES; node->storage = data; } @@ -179,7 +178,7 @@ void register_node_type_geo_mesh_to_points() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index 38c3b9cbcd9..d32875d2627 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -102,8 +102,7 @@ static void node_geo_exec(GeoNodeExecParams params) static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN( - sizeof(NodeGeometryObjectInfo), __func__); + NodeGeometryObjectInfo *data = MEM_cnew<NodeGeometryObjectInfo>(__func__); data->transform_space = GEO_NODE_TRANSFORM_SPACE_ORIGINAL; node->storage = data; } @@ -116,7 +115,7 @@ void register_node_type_geo_object_info() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT); node_type_init(&ntype, file_ns::node_node_init); node_type_storage( &ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 5510773eabd..f3da591f684 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -113,7 +113,7 @@ void register_node_type_geo_points_to_vertices() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 744cce6d445..dda4543d5e1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -66,8 +66,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( - sizeof(NodeGeometryPointsToVolume), __func__); + NodeGeometryPointsToVolume *data = MEM_cnew<NodeGeometryPointsToVolume>(__func__); data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT; node->storage = data; } @@ -270,8 +269,7 @@ void register_node_type_geo_points_to_volume() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY); node_type_storage(&ntype, "NodeGeometryPointsToVolume", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc index aa3383e68be..e0117c4726d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc @@ -48,8 +48,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void geo_proximity_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryProximity *node_storage = (NodeGeometryProximity *)MEM_callocN( - sizeof(NodeGeometryProximity), __func__); + NodeGeometryProximity *node_storage = MEM_cnew<NodeGeometryProximity>(__func__); node_storage->target_element = GEO_NODE_PROX_TARGET_FACES; node->storage = node_storage; } @@ -178,7 +177,7 @@ class ProximityFunction : public fn::MultiFunction { * comparison per vertex, so it's likely not worth it. */ MutableSpan<float> distances = params.uninitialized_single_output<float>(2, "Distance"); - distances.fill(FLT_MAX); + distances.fill_indices(mask, FLT_MAX); bool success = false; if (target_.has_mesh()) { @@ -192,8 +191,8 @@ class ProximityFunction : public fn::MultiFunction { } if (!success) { - positions.fill(float3(0)); - distances.fill(0.0f); + positions.fill_indices(mask, float3(0)); + distances.fill_indices(mask, 0.0f); return; } @@ -239,7 +238,7 @@ void register_node_type_geo_proximity() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY); node_type_init(&ntype, file_ns::geo_proximity_init); node_type_storage( &ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index d255fe482f6..2c35ca0afc9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -75,8 +75,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), - __func__); + NodeGeometryRaycast *data = MEM_cnew<NodeGeometryRaycast>(__func__); data->mapping = GEO_NODE_RAYCAST_INTERPOLATED; data->data_type = CD_PROP_FLOAT; node->storage = data; @@ -449,7 +448,7 @@ void register_node_type_geo_raycast() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc index fad35389823..48b88705ed2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc @@ -54,8 +54,7 @@ void register_node_type_geo_realize_instances() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.draw_buttons_ex = file_ns::node_layout; ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index 335484c62b0..5a088e16221 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -112,8 +112,7 @@ void register_node_type_geo_rotate_instances() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index 1779ac8bff7..04c4e097f8d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -91,7 +91,7 @@ void register_node_type_geo_scale_instances() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc index e4adfe6587d..3e34378d3e0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc @@ -70,7 +70,7 @@ void register_node_type_geo_separate_components() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index 7f1cc1be421..63da7399c3e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -44,8 +44,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN( - sizeof(NodeGeometrySeparateGeometry), __func__); + NodeGeometrySeparateGeometry *data = MEM_cnew<NodeGeometrySeparateGeometry>(__func__); data->domain = ATTR_DOMAIN_POINT; node->storage = data; @@ -60,38 +59,38 @@ static void node_geo_exec(GeoNodeExecParams params) const NodeGeometrySeparateGeometry &storage = node_storage(params.node()); const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - bool all_is_error = false; - GeometrySet second_set(geometry_set); - if (params.output_is_required("Selection")) { - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - bool this_is_error = false; + auto separate_geometry_maybe_recursively = [&](bool invert) { + bool is_error; + if (domain == ATTR_DOMAIN_INSTANCE) { + /* Only delete top level instances. */ separate_geometry(geometry_set, domain, GEO_NODE_DELETE_GEOMETRY_MODE_ALL, selection_field, - false, - this_is_error); - all_is_error &= this_is_error; - }); + invert, + is_error); + } + else { + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + separate_geometry(geometry_set, + domain, + GEO_NODE_DELETE_GEOMETRY_MODE_ALL, + selection_field, + invert, + is_error); + }); + } + }; + + GeometrySet second_set(geometry_set); + if (params.output_is_required("Selection")) { + separate_geometry_maybe_recursively(false); params.set_output("Selection", std::move(geometry_set)); } if (params.output_is_required("Inverted")) { - second_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - bool this_is_error = false; - separate_geometry(geometry_set, - domain, - GEO_NODE_DELETE_GEOMETRY_MODE_ALL, - selection_field, - true, - this_is_error); - all_is_error &= this_is_error; - }); + separate_geometry_maybe_recursively(true); params.set_output("Inverted", std::move(second_set)); } - if (all_is_error) { - /* Only show this if none of the instances/components actually changed. */ - params.error_message_add(NodeWarningType::Info, TIP_("No geometry with given domain")); - } } } // namespace blender::nodes::node_geo_separate_geometry_cc @@ -102,8 +101,7 @@ void register_node_type_geo_separate_geometry() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SEPARATE_GEOMETRY, "Separate Geometry", NODE_CLASS_GEOMETRY); node_type_storage(&ntype, "NodeGeometrySeparateGeometry", diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index 30a61574e19..feab0a6743f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -41,8 +41,8 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN( - sizeof(NodeGeometrySetCurveHandlePositions), __func__); + NodeGeometrySetCurveHandlePositions *data = MEM_cnew<NodeGeometrySetCurveHandlePositions>( + __func__); data->mode = GEO_NODE_CURVE_HANDLE_LEFT; node->storage = data; @@ -65,7 +65,7 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, evaluator.add(position_field); evaluator.add(offset_field); evaluator.evaluate(); - const IndexMask selection = evaluator.get_evaluated_as_mask(0); + const IndexMask selection = evaluator.get_evaluated_selection_as_mask(); CurveComponent *curve_component = static_cast<CurveComponent *>(&component); CurveEval *curve = curve_component->get_for_write(); @@ -167,7 +167,7 @@ void register_node_type_geo_set_curve_handles() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; ntype.minwidth = 100.0f; diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index 7d99f42c487..06fe4427520 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -75,8 +75,7 @@ void register_node_type_geo_set_curve_radius() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index 447310e1ad7..0854d0a4549 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -71,7 +71,7 @@ void register_node_type_geo_set_curve_tilt() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index db4083acd4b..110b8206944 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -87,7 +87,7 @@ void register_node_type_geo_set_id() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index 30510c3570c..ab2c778d6fc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -40,6 +40,12 @@ static void node_declare(NodeDeclarationBuilder &b) static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Material *material) { + if (selection.size() != mesh.totpoly) { + /* If the entire mesh isn't selected, and there is no material slot yet, add an empty + * slot so that the faces that aren't selected can still refer to the default material. */ + BKE_id_material_eval_ensure_default_slot(&mesh.id); + } + int new_material_index = -1; for (const int i : IndexRange(mesh.totcol)) { Material *other_material = mesh.mat[i]; @@ -121,7 +127,7 @@ void register_node_type_geo_set_material() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index 4451907132a..ca6d78adc80 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -70,7 +70,7 @@ void register_node_type_geo_set_material_index() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index 98adff7c939..b7dd091da44 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -76,8 +76,7 @@ void register_node_type_geo_set_point_radius() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 93073c2436d..4a8e4e6eab8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -159,7 +159,7 @@ void register_node_type_geo_set_position() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 879a868cc0e..d442cd37e81 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -70,8 +70,7 @@ void register_node_type_geo_set_shade_smooth() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index 694491d7e6d..13230e185a3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -71,8 +71,7 @@ void register_node_type_geo_set_spline_cyclic() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index 0f93db5e6f6..e472e14671c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -88,7 +88,7 @@ void register_node_type_geo_set_spline_resolution() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc index 5308b43afb2..0fbe9a41ca5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc @@ -48,7 +48,7 @@ void register_node_type_geo_string_join() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0); + geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 33614eb3c46..68d62a842e6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN( - sizeof(NodeGeometryStringToCurves), __func__); + NodeGeometryStringToCurves *data = MEM_cnew<NodeGeometryStringToCurves>(__func__); data->overflow = GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW; data->align_x = GEO_NODE_STRING_TO_CURVES_ALIGN_X_LEFT; @@ -311,8 +310,7 @@ void register_node_type_geo_string_to_curves() static bNodeType ntype; - geo_node_type_base( - &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; node_type_init(&ntype, file_ns::node_init); diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 74e0560b32f..eb1a5496845 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -52,8 +52,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( - sizeof(NodeGeometrySubdivisionSurface), __func__); + NodeGeometrySubdivisionSurface *data = MEM_cnew<NodeGeometrySubdivisionSurface>(__func__); data->uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; data->boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL; node->storage = data; @@ -153,7 +152,7 @@ void register_node_type_geo_subdivision_surface() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.draw_buttons = file_ns::node_layout; diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index d22522fe087..a2f05677310 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -94,7 +94,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__); + NodeSwitch *data = MEM_cnew<NodeSwitch>(__func__); data->input_type = SOCK_GEOMETRY; node->storage = data; } @@ -327,7 +327,7 @@ void register_node_type_geo_switch() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0); + geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index 1f099dcd04d..331460296a6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -88,8 +88,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN( - sizeof(NodeGeometryTransferAttribute), __func__); + NodeGeometryTransferAttribute *data = MEM_cnew<NodeGeometryTransferAttribute>(__func__); data->data_type = CD_PROP_FLOAT; data->mode = GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED; node->storage = data; @@ -828,7 +827,7 @@ void register_node_type_geo_transfer_attribute() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0); + &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE); node_type_init(&ntype, file_ns::node_init); node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 8322de20d20..7f866ea6f4a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -226,7 +226,7 @@ void register_node_type_geo_transform() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index 59049ecf0ed..1061ece49a9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -77,7 +77,7 @@ void register_node_type_geo_translate_instances() static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0); + &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY); ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index f8deaaa4a14..998e4d58bf3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -77,7 +77,7 @@ void register_node_type_geo_triangulate() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; node_type_init(&ntype, file_ns::geo_triangulate_init); ntype.geometry_node_execute = file_ns::node_geo_exec; diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 18f2fa4cd36..c717d90f7cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -42,8 +42,7 @@ static void node_declare(NodeDeclarationBuilder &b) static void node_init(bNodeTree *UNUSED(tree), bNode *node) { - NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer), - __func__); + NodeGeometryViewer *data = MEM_cnew<NodeGeometryViewer>(__func__); data->data_type = CD_PROP_FLOAT; node->storage = data; @@ -141,7 +140,7 @@ void register_node_type_geo_viewer() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0); + geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT); node_type_storage( &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage); node_type_update(&ntype, file_ns::node_update); diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 0819b401941..c7dc73f8a91 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -69,8 +69,7 @@ static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( - sizeof(NodeGeometryVolumeToMesh), __func__); + NodeGeometryVolumeToMesh *data = MEM_cnew<NodeGeometryVolumeToMesh>(__func__); data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID; node->storage = data; } @@ -215,7 +214,7 @@ void register_node_type_geo_volume_to_mesh() static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY); ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index dc223f07a26..449c6598307 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -270,6 +270,9 @@ void DOutputSocket::foreach_target_socket(ForeachTargetSocketFn target_fn, } } else if (linked_node->is_group_output_node()) { + if (linked_node.node_ref() != context_->tree().group_output_node()) { + continue; + } if (context_->is_root()) { /* This is a group output in the root node group. */ path_info.sockets.append(linked_socket); diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index c302b1081af..1c9a1730635 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -38,6 +38,7 @@ #include "BLT_translation.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "RNA_types.h" @@ -153,8 +154,6 @@ static void update_socket_to_match_interface(bNodeTree &node_tree, /* Update socket type if necessary */ if (socket_to_update.typeinfo != interface_socket.typeinfo) { nodeModifySocketType(&node_tree, &node, &socket_to_update, interface_socket.idname); - /* Flag the tree to make sure link validity is updated after type changes. */ - node_tree.update |= NTREE_UPDATE_LINKS; } if (interface_socket.typeinfo->interface_verify_socket) { @@ -225,7 +224,7 @@ void node_group_update(struct bNodeTree *ntree, struct bNode *node) static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeFrame *data = (NodeFrame *)MEM_callocN(sizeof(NodeFrame), "frame node storage"); + NodeFrame *data = MEM_cnew<NodeFrame>("frame node storage"); node->storage = data; data->flag |= NODE_FRAME_SHRINK; @@ -233,16 +232,17 @@ static void node_frame_init(bNodeTree *UNUSED(ntree), bNode *node) data->label_size = 20; } -void register_node_type_frame(void) +void register_node_type_frame() { /* frame type is used for all tree types, needs dynamic allocation */ - bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type"); + bNodeType *ntype = MEM_cnew<bNodeType>("frame node type"); ntype->free_self = (void (*)(bNodeType *))MEM_freeN; - node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT, NODE_BACKGROUND); + node_type_base(ntype, NODE_FRAME, "Frame", NODE_CLASS_LAYOUT); node_type_init(ntype, node_frame_init); node_type_storage(ntype, "NodeFrame", node_free_standard_storage, node_copy_standard_storage); node_type_size(ntype, 150, 100, 0); + ntype->flag |= NODE_BACKGROUND; nodeRegisterType(ntype); } @@ -262,13 +262,13 @@ static void node_reroute_init(bNodeTree *ntree, bNode *node) nodeAddStaticSocket(ntree, node, SOCK_OUT, SOCK_RGBA, PROP_NONE, "Output", "Output"); } -void register_node_type_reroute(void) +void register_node_type_reroute() { /* frame type is used for all tree types, needs dynamic allocation */ - bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "frame node type"); + bNodeType *ntype = MEM_cnew<bNodeType>("frame node type"); ntype->free_self = (void (*)(bNodeType *))MEM_freeN; - node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0); + node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT); node_type_init(ntype, node_reroute_init); nodeRegisterType(ntype); @@ -455,7 +455,7 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) } if (link->fromsock == extsock) { - bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link"); + bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link"); *tlink = *link; BLI_addtail(&tmplinks, tlink); @@ -503,13 +503,13 @@ void node_group_input_update(bNodeTree *ntree, bNode *node) } } -void register_node_type_group_input(void) +void register_node_type_group_input() { /* used for all tree types, needs dynamic allocation */ - bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type"); + bNodeType *ntype = MEM_cnew<bNodeType>("node type"); ntype->free_self = (void (*)(bNodeType *))MEM_freeN; - node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE, 0); + node_type_base(ntype, NODE_GROUP_INPUT, "Group Input", NODE_CLASS_INTERFACE); node_type_size(ntype, 140, 80, 400); node_type_init(ntype, node_group_input_init); node_type_update(ntype, node_group_input_update); @@ -552,7 +552,7 @@ void node_group_output_update(bNodeTree *ntree, bNode *node) } if (link->tosock == extsock) { - bNodeLink *tlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "temporary link"); + bNodeLink *tlink = MEM_cnew<bNodeLink>("temporary link"); *tlink = *link; BLI_addtail(&tmplinks, tlink); @@ -601,13 +601,13 @@ void node_group_output_update(bNodeTree *ntree, bNode *node) } } -void register_node_type_group_output(void) +void register_node_type_group_output() { /* used for all tree types, needs dynamic allocation */ - bNodeType *ntype = (bNodeType *)MEM_callocN(sizeof(bNodeType), "node type"); + bNodeType *ntype = MEM_cnew<bNodeType>("node type"); ntype->free_self = (void (*)(bNodeType *))MEM_freeN; - node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE, 0); + node_type_base(ntype, NODE_GROUP_OUTPUT, "Group Output", NODE_CLASS_INTERFACE); node_type_size(ntype, 140, 80, 400); node_type_init(ntype, node_group_output_init); node_type_update(ntype, node_group_output_update); diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index 75d47cfd386..28e8bf5a4b7 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -63,6 +63,7 @@ void SocketDeclaration::set_common_flags(bNodeSocket &socket) const SET_FLAG_FROM_TEST(socket.flag, hide_label_, SOCK_HIDE_LABEL); SET_FLAG_FROM_TEST(socket.flag, is_multi_input_, SOCK_MULTI_INPUT); SET_FLAG_FROM_TEST(socket.flag, no_mute_links_, SOCK_NO_INTERNAL_LINK); + SET_FLAG_FROM_TEST(socket.flag, is_unavailable_, SOCK_UNAVAIL); } bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const @@ -88,6 +89,9 @@ bool SocketDeclaration::matches_common_data(const bNodeSocket &socket) const if (((socket.flag & SOCK_NO_INTERNAL_LINK) != 0) != no_mute_links_) { return false; } + if (((socket.flag & SOCK_UNAVAIL) != 0) != is_unavailable_) { + return false; + } return true; } diff --git a/source/blender/nodes/intern/node_exec.cc b/source/blender/nodes/intern/node_exec.cc index 95070bf735e..4ff662036c3 100644 --- a/source/blender/nodes/intern/node_exec.cc +++ b/source/blender/nodes/intern/node_exec.cc @@ -28,6 +28,7 @@ #include "BKE_global.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "MEM_guardedalloc.h" @@ -170,13 +171,13 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* Using global main here is likely totally wrong, not sure what to do about that one though... * We cannot even check ntree is in global main, * since most of the time it won't be (thanks to ntree design)!!! */ - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); /* get a dependency-sorted list of nodes */ ntreeGetDependencyList(ntree, &nodelist, &totnodes); /* XXX could let callbacks do this for specialized data */ - exec = (bNodeTreeExec *)MEM_callocN(sizeof(bNodeTreeExec), "node tree execution data"); + exec = MEM_cnew<bNodeTreeExec>("node tree execution data"); /* backpointer to node tree */ exec->nodetree = ntree; @@ -291,7 +292,7 @@ bNodeThreadStack *ntreeGetThreadStack(bNodeTreeExec *exec, int thread) } if (!nts) { - nts = (bNodeThreadStack *)MEM_callocN(sizeof(bNodeThreadStack), "bNodeThreadStack"); + nts = MEM_cnew<bNodeThreadStack>("bNodeThreadStack"); nts->stack = (bNodeStack *)MEM_dupallocN(exec->stack); nts->used = true; BLI_addtail(lb, nts); diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index d83c05b38a1..6a6b6e3d3cc 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -236,6 +236,14 @@ static void refresh_socket_list(bNodeTree &ntree, link->tosock = new_socket; } } + LISTBASE_FOREACH (bNodeLink *, internal_link, &node.internal_links) { + if (internal_link->fromsock == old_socket_with_same_identifier) { + internal_link->fromsock = new_socket; + } + else if (internal_link->tosock == old_socket_with_same_identifier) { + internal_link->tosock = new_socket; + } + } } } } @@ -301,8 +309,7 @@ void node_socket_init_default_value(bNodeSocket *sock) switch (type) { case SOCK_FLOAT: { - bNodeSocketValueFloat *dval = (bNodeSocketValueFloat *)MEM_callocN( - sizeof(bNodeSocketValueFloat), "node socket value float"); + bNodeSocketValueFloat *dval = MEM_cnew<bNodeSocketValueFloat>("node socket value float"); dval->subtype = subtype; dval->value = 0.0f; dval->min = -FLT_MAX; @@ -312,8 +319,7 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_INT: { - bNodeSocketValueInt *dval = (bNodeSocketValueInt *)MEM_callocN(sizeof(bNodeSocketValueInt), - "node socket value int"); + bNodeSocketValueInt *dval = MEM_cnew<bNodeSocketValueInt>("node socket value int"); dval->subtype = subtype; dval->value = 0; dval->min = INT_MIN; @@ -323,8 +329,7 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_BOOLEAN: { - bNodeSocketValueBoolean *dval = (bNodeSocketValueBoolean *)MEM_callocN( - sizeof(bNodeSocketValueBoolean), "node socket value bool"); + bNodeSocketValueBoolean *dval = MEM_cnew<bNodeSocketValueBoolean>("node socket value bool"); dval->value = false; sock->default_value = dval; @@ -332,8 +337,7 @@ void node_socket_init_default_value(bNodeSocket *sock) } case SOCK_VECTOR: { static float default_value[] = {0.0f, 0.0f, 0.0f}; - bNodeSocketValueVector *dval = (bNodeSocketValueVector *)MEM_callocN( - sizeof(bNodeSocketValueVector), "node socket value vector"); + bNodeSocketValueVector *dval = MEM_cnew<bNodeSocketValueVector>("node socket value vector"); dval->subtype = subtype; copy_v3_v3(dval->value, default_value); dval->min = -FLT_MAX; @@ -344,16 +348,14 @@ void node_socket_init_default_value(bNodeSocket *sock) } case SOCK_RGBA: { static float default_value[] = {0.0f, 0.0f, 0.0f, 1.0f}; - bNodeSocketValueRGBA *dval = (bNodeSocketValueRGBA *)MEM_callocN( - sizeof(bNodeSocketValueRGBA), "node socket value color"); + bNodeSocketValueRGBA *dval = MEM_cnew<bNodeSocketValueRGBA>("node socket value color"); copy_v4_v4(dval->value, default_value); sock->default_value = dval; break; } case SOCK_STRING: { - bNodeSocketValueString *dval = (bNodeSocketValueString *)MEM_callocN( - sizeof(bNodeSocketValueString), "node socket value string"); + bNodeSocketValueString *dval = MEM_cnew<bNodeSocketValueString>("node socket value string"); dval->subtype = subtype; dval->value[0] = '\0'; @@ -361,40 +363,38 @@ void node_socket_init_default_value(bNodeSocket *sock) break; } case SOCK_OBJECT: { - bNodeSocketValueObject *dval = (bNodeSocketValueObject *)MEM_callocN( - sizeof(bNodeSocketValueObject), "node socket value object"); + bNodeSocketValueObject *dval = MEM_cnew<bNodeSocketValueObject>("node socket value object"); dval->value = nullptr; sock->default_value = dval; break; } case SOCK_IMAGE: { - bNodeSocketValueImage *dval = (bNodeSocketValueImage *)MEM_callocN( - sizeof(bNodeSocketValueImage), "node socket value image"); + bNodeSocketValueImage *dval = MEM_cnew<bNodeSocketValueImage>("node socket value image"); dval->value = nullptr; sock->default_value = dval; break; } case SOCK_COLLECTION: { - bNodeSocketValueCollection *dval = (bNodeSocketValueCollection *)MEM_callocN( - sizeof(bNodeSocketValueCollection), "node socket value object"); + bNodeSocketValueCollection *dval = MEM_cnew<bNodeSocketValueCollection>( + "node socket value object"); dval->value = nullptr; sock->default_value = dval; break; } case SOCK_TEXTURE: { - bNodeSocketValueTexture *dval = (bNodeSocketValueTexture *)MEM_callocN( - sizeof(bNodeSocketValueTexture), "node socket value texture"); + bNodeSocketValueTexture *dval = MEM_cnew<bNodeSocketValueTexture>( + "node socket value texture"); dval->value = nullptr; sock->default_value = dval; break; } case SOCK_MATERIAL: { - bNodeSocketValueMaterial *dval = (bNodeSocketValueMaterial *)MEM_callocN( - sizeof(bNodeSocketValueMaterial), "node socket value material"); + bNodeSocketValueMaterial *dval = MEM_cnew<bNodeSocketValueMaterial>( + "node socket value material"); dval->value = nullptr; sock->default_value = dval; @@ -629,7 +629,7 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype) bNodeSocketType *stype; StructRNA *srna; - stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); + stype = MEM_cnew<bNodeSocketType>("node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); BLI_strncpy(stype->label, socket_label, sizeof(stype->label)); @@ -673,7 +673,7 @@ static bNodeSocketType *make_socket_type_virtual() bNodeSocketType *stype; StructRNA *srna; - stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type"); + stype = MEM_cnew<bNodeSocketType>("node socket C type"); stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN; BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname)); @@ -872,7 +872,7 @@ static bNodeSocketType *make_socket_type_material() return socktype; } -void register_standard_node_socket_types(void) +void register_standard_node_socket_types() { /* Draw callbacks are set in `drawnode.c` to avoid bad-level calls. */ diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 912d5e5322c..bc78533d45c 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -70,6 +70,8 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) break; } } + BLI_assert(internal_link.from_ != nullptr); + BLI_assert(internal_link.to_ != nullptr); node.internal_links_.append(&internal_link); } @@ -115,6 +117,22 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) const bNodeType *nodetype = node->bnode_->typeinfo; nodes_by_type_.add(nodetype, node); } + + const Span<const NodeRef *> group_output_nodes = this->nodes_by_type("NodeGroupOutput"); + if (group_output_nodes.is_empty()) { + group_output_node_ = nullptr; + } + else if (group_output_nodes.size() == 1) { + group_output_node_ = group_output_nodes.first(); + } + else { + for (const NodeRef *group_output : group_output_nodes) { + if (group_output->bnode_->flag & NODE_DO_OUTPUT) { + group_output_node_ = group_output; + break; + } + } + } } NodeTreeRef::~NodeTreeRef() diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index 7620c8fa1a8..5c2d84cf605 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -35,6 +35,7 @@ #include "BKE_colortools.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "RNA_access.h" #include "RNA_enum_types.h" @@ -340,188 +341,6 @@ void node_insert_link_default(bNodeTree *ntree, bNode *node, bNodeLink *link) /** \} */ /* -------------------------------------------------------------------- */ -/** \name Internal Links (mute and disconnect) - * \{ */ - -/** - * Common datatype priorities, works for compositor, shader and texture nodes alike - * defines priority of datatype connection based on output type (to): - * `< 0`: never connect these types. - * `>= 0`: priority of connection (higher values chosen first). - */ -static int node_datatype_priority(const bNodeSocketType *from, const bNodeSocketType *to) -{ - switch (to->type) { - case SOCK_RGBA: - switch (from->type) { - case SOCK_RGBA: - return 4; - case SOCK_FLOAT: - return 3; - case SOCK_INT: - return 2; - case SOCK_BOOLEAN: - return 1; - } - return -1; - case SOCK_VECTOR: - switch (from->type) { - case SOCK_VECTOR: - return 4; - case SOCK_FLOAT: - return 3; - case SOCK_INT: - return 2; - case SOCK_BOOLEAN: - return 1; - } - return -1; - case SOCK_FLOAT: - switch (from->type) { - case SOCK_FLOAT: - return 5; - case SOCK_INT: - return 4; - case SOCK_BOOLEAN: - return 3; - case SOCK_RGBA: - return 2; - case SOCK_VECTOR: - return 1; - } - return -1; - case SOCK_INT: - switch (from->type) { - case SOCK_INT: - return 5; - case SOCK_FLOAT: - return 4; - case SOCK_BOOLEAN: - return 3; - case SOCK_RGBA: - return 2; - case SOCK_VECTOR: - return 1; - } - return -1; - case SOCK_BOOLEAN: - switch (from->type) { - case SOCK_BOOLEAN: - return 5; - case SOCK_INT: - return 4; - case SOCK_FLOAT: - return 3; - case SOCK_RGBA: - return 2; - case SOCK_VECTOR: - return 1; - } - return -1; - } - - /* The rest of the socket types only allow an internal link if both the input and output socket - * have the same type. If the sockets are custom, we check the idname instead. */ - if (to->type == from->type && (to->type != SOCK_CUSTOM || STREQ(to->idname, from->idname))) { - return 1; - } - - return -1; -} - -/* select a suitable input socket for an output */ -static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) -{ - if (node->type == NODE_REROUTE) { - return node->inputs.first; - } - - bNodeSocket *selected = NULL, *input; - int i; - int sel_priority = -1; - bool sel_is_linked = false; - - for (input = node->inputs.first, i = 0; input; input = input->next, i++) { - int priority = node_datatype_priority(input->typeinfo, output->typeinfo); - bool is_linked = (input->link != NULL); - bool preferred; - - if (nodeSocketIsHidden(input) || /* ignore hidden sockets */ - input->flag & - SOCK_NO_INTERNAL_LINK || /* ignore if input is not allowed for internal connections */ - priority < 0 || /* ignore incompatible types */ - priority < sel_priority) /* ignore if we already found a higher priority input */ - { - continue; - } - - /* determine if this input is preferred over the currently selected */ - preferred = (priority > sel_priority) || /* prefer higher datatype priority */ - (is_linked && !sel_is_linked); /* prefer linked over unlinked */ - - if (preferred) { - selected = input; - sel_is_linked = is_linked; - sel_priority = priority; - } - } - - return selected; -} - -void node_internal_links_create(bNodeTree *ntree, bNode *node) -{ - bNodeLink *link; - bNodeSocket *output, *input; - - /* sanity check */ - if (!ntree) { - return; - } - - /* use link pointer as a tag for handled sockets (for outputs is unused anyway) */ - for (output = node->outputs.first; output; output = output->next) { - output->link = NULL; - } - - for (link = ntree->links.first; link; link = link->next) { - if (nodeLinkIsHidden(link)) { - continue; - } - - output = link->fromsock; - if (link->fromnode != node || output->link) { - continue; - } - if (nodeSocketIsHidden(output) || output->flag & SOCK_NO_INTERNAL_LINK) { - continue; - } - output->link = link; /* not really used, just for tagging handled sockets */ - - /* look for suitable input */ - input = select_internal_link_input(node, output); - - if (input) { - bNodeLink *ilink = MEM_callocN(sizeof(bNodeLink), "internal node link"); - ilink->fromnode = node; - ilink->fromsock = input; - ilink->tonode = node; - ilink->tosock = output; - /* internal link is always valid */ - ilink->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, ilink); - } - } - - /* clean up */ - for (output = node->outputs.first; output; output = output->next) { - output->link = NULL; - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name Default value RNA access * \{ */ diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 7d99c233197..9878ebe3162 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../blenlib ../../blentranslation ../../depsgraph + ../../editors/include ../../functions ../../gpu ../../imbuf @@ -39,101 +40,102 @@ set(INC set(SRC - nodes/node_shader_add_shader.c - nodes/node_shader_ambient_occlusion.c - nodes/node_shader_attribute.c - nodes/node_shader_background.c - nodes/node_shader_bevel.c - nodes/node_shader_blackbody.c - nodes/node_shader_brightness.c - nodes/node_shader_bsdf_anisotropic.c - nodes/node_shader_bsdf_diffuse.c - nodes/node_shader_bsdf_glass.c - nodes/node_shader_bsdf_glossy.c - nodes/node_shader_bsdf_hair.c - nodes/node_shader_bsdf_hair_principled.c - nodes/node_shader_bsdf_principled.c - nodes/node_shader_bsdf_refraction.c - nodes/node_shader_bsdf_toon.c - nodes/node_shader_bsdf_translucent.c - nodes/node_shader_bsdf_transparent.c - nodes/node_shader_bsdf_velvet.c - nodes/node_shader_bump.c - nodes/node_shader_camera.c + nodes/node_shader_add_shader.cc + nodes/node_shader_ambient_occlusion.cc + nodes/node_shader_attribute.cc + nodes/node_shader_background.cc + nodes/node_shader_bevel.cc + nodes/node_shader_blackbody.cc + nodes/node_shader_brightness.cc + nodes/node_shader_bsdf_anisotropic.cc + nodes/node_shader_bsdf_diffuse.cc + nodes/node_shader_bsdf_glass.cc + nodes/node_shader_bsdf_glossy.cc + nodes/node_shader_bsdf_hair.cc + nodes/node_shader_bsdf_hair_principled.cc + nodes/node_shader_bsdf_principled.cc + nodes/node_shader_bsdf_refraction.cc + nodes/node_shader_bsdf_toon.cc + nodes/node_shader_bsdf_translucent.cc + nodes/node_shader_bsdf_transparent.cc + nodes/node_shader_bsdf_velvet.cc + nodes/node_shader_bump.cc + nodes/node_shader_camera.cc nodes/node_shader_clamp.cc - nodes/node_shader_common.c + nodes/node_shader_color_ramp.cc + nodes/node_shader_common.cc nodes/node_shader_curves.cc - nodes/node_shader_displacement.c - nodes/node_shader_eevee_specular.c - nodes/node_shader_emission.c - nodes/node_shader_fresnel.c - nodes/node_shader_gamma.c - nodes/node_shader_geometry.c - nodes/node_shader_hair_info.c - nodes/node_shader_holdout.c - nodes/node_shader_hueSatVal.c - nodes/node_shader_ies_light.c - nodes/node_shader_invert.c - nodes/node_shader_layer_weight.c - nodes/node_shader_light_falloff.c - nodes/node_shader_light_path.c + nodes/node_shader_displacement.cc + nodes/node_shader_eevee_specular.cc + nodes/node_shader_emission.cc + nodes/node_shader_fresnel.cc + nodes/node_shader_gamma.cc + nodes/node_shader_geometry.cc + nodes/node_shader_hair_info.cc + nodes/node_shader_holdout.cc + nodes/node_shader_hueSatVal.cc + nodes/node_shader_ies_light.cc + nodes/node_shader_invert.cc + nodes/node_shader_layer_weight.cc + nodes/node_shader_light_falloff.cc + nodes/node_shader_light_path.cc nodes/node_shader_map_range.cc - nodes/node_shader_mapping.c + nodes/node_shader_mapping.cc nodes/node_shader_math.cc nodes/node_shader_mix_rgb.cc - nodes/node_shader_mix_shader.c - nodes/node_shader_normal.c - nodes/node_shader_normal_map.c - nodes/node_shader_object_info.c - nodes/node_shader_output_aov.c - nodes/node_shader_output_light.c - nodes/node_shader_output_linestyle.c - nodes/node_shader_output_material.c - nodes/node_shader_output_world.c - nodes/node_shader_particle_info.c + nodes/node_shader_mix_shader.cc + nodes/node_shader_normal.cc + nodes/node_shader_normal_map.cc + nodes/node_shader_object_info.cc + nodes/node_shader_output_aov.cc + nodes/node_shader_output_light.cc + nodes/node_shader_output_linestyle.cc + nodes/node_shader_output_material.cc + nodes/node_shader_output_world.cc + nodes/node_shader_particle_info.cc nodes/node_shader_rgb_to_bw.cc - nodes/node_shader_rgb.c - nodes/node_shader_script.c - nodes/node_shader_sepcomb_hsv.c + nodes/node_shader_rgb.cc + nodes/node_shader_script.cc + nodes/node_shader_sepcomb_hsv.cc nodes/node_shader_sepcomb_rgb.cc nodes/node_shader_sepcomb_xyz.cc - nodes/node_shader_shader_to_rgb.c - nodes/node_shader_squeeze.c - nodes/node_shader_subsurface_scattering.c - nodes/node_shader_tangent.c + nodes/node_shader_shader_to_rgb.cc + nodes/node_shader_squeeze.cc + nodes/node_shader_subsurface_scattering.cc + nodes/node_shader_tangent.cc nodes/node_shader_tex_brick.cc nodes/node_shader_tex_checker.cc - nodes/node_shader_tex_coord.c - nodes/node_shader_tex_environment.c + nodes/node_shader_tex_coord.cc + nodes/node_shader_tex_environment.cc nodes/node_shader_tex_gradient.cc nodes/node_shader_tex_image.cc nodes/node_shader_tex_magic.cc nodes/node_shader_tex_musgrave.cc nodes/node_shader_tex_noise.cc - nodes/node_shader_tex_pointdensity.c - nodes/node_shader_tex_sky.c + nodes/node_shader_tex_pointdensity.cc + nodes/node_shader_tex_sky.cc nodes/node_shader_tex_voronoi.cc nodes/node_shader_tex_wave.cc nodes/node_shader_tex_white_noise.cc - nodes/node_shader_uv_along_stroke.c - nodes/node_shader_uvmap.c + nodes/node_shader_uv_along_stroke.cc + nodes/node_shader_uvmap.cc nodes/node_shader_value.cc - nodes/node_shader_vector_displacement.c + nodes/node_shader_vector_displacement.cc nodes/node_shader_vector_math.cc nodes/node_shader_vector_rotate.cc - nodes/node_shader_vector_transform.c - nodes/node_shader_vertex_color.c - nodes/node_shader_volume_absorption.c - nodes/node_shader_volume_info.c - nodes/node_shader_volume_principled.c - nodes/node_shader_volume_scatter.c - nodes/node_shader_wavelength.c - nodes/node_shader_wireframe.c + nodes/node_shader_vector_transform.cc + nodes/node_shader_vertex_color.cc + nodes/node_shader_volume_absorption.cc + nodes/node_shader_volume_info.cc + nodes/node_shader_volume_principled.cc + nodes/node_shader_volume_scatter.cc + nodes/node_shader_wavelength.cc + nodes/node_shader_wireframe.cc - node_shader_tree.c + node_shader_tree.cc node_shader_util.cc - node_shader_util.h + node_shader_util.hh ) set(LIB @@ -164,3 +166,8 @@ if(WITH_FREESTYLE) endif() blender_add_lib(bf_nodes_shader "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +if(WITH_UNITY_BUILD) + set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD ON) + set_target_properties(bf_nodes_shader PROPERTIES UNITY_BUILD_BATCH_SIZE 10) +endif() diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.cc index c3b5236373c..1552ed9f19c 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.cc @@ -21,7 +21,7 @@ * \ingroup nodes */ -#include <string.h> +#include <cstring> #include "DNA_light_types.h" #include "DNA_linestyle_types.h" @@ -44,6 +44,7 @@ #include "BKE_lib_id.h" #include "BKE_linestyle.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_scene.h" #include "RNA_access.h" @@ -52,16 +53,18 @@ #include "RE_texture.h" +#include "UI_resources.h" + #include "NOD_common.h" #include "node_common.h" #include "node_exec.h" -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "node_util.h" -typedef struct nTreeTags { +struct nTreeTags { float ssr_id, sss_id; -} nTreeTags; +}; static void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags); @@ -91,7 +94,7 @@ static void shader_get_from_context(const bContext *C, if (ob) { *r_from = &ob->id; if (ob->type == OB_LAMP) { - *r_id = ob->data; + *r_id = static_cast<ID *>(ob->data); *r_ntree = ((Light *)ob->data)->nodetree; } else { @@ -107,7 +110,7 @@ static void shader_get_from_context(const bContext *C, else if (snode->shaderfrom == SNODE_SHADER_LINESTYLE) { FreestyleLineStyle *linestyle = BKE_linestyle_active_from_view_layer(view_layer); if (linestyle) { - *r_from = NULL; + *r_from = nullptr; *r_id = &linestyle->id; *r_ntree = linestyle->nodetree; } @@ -115,7 +118,7 @@ static void shader_get_from_context(const bContext *C, #endif else { /* SNODE_SHADER_WORLD */ if (scene->world) { - *r_from = NULL; + *r_from = nullptr; *r_id = &scene->world->id; *r_ntree = scene->world->nodetree; } @@ -148,26 +151,11 @@ static void localize(bNodeTree *localtree, bNodeTree *UNUSED(ntree)) } } -static void local_sync(bNodeTree *localtree, bNodeTree *ntree) -{ - BKE_node_preview_sync_tree(ntree, localtree); -} - -static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree) -{ - BKE_node_preview_merge_tree(ntree, localtree, true); -} - static void update(bNodeTree *ntree) { ntreeSetOutput(ntree); ntree_update_reroute_nodes(ntree); - - if (ntree->update & NTREE_UPDATE_NODES) { - /* clean up preview cache, in case nodes have been removed */ - BKE_node_preview_remove_unused(ntree); - } } static bool shader_validate_link(eNodeSocketDatatype from, eNodeSocketDatatype to) @@ -189,21 +177,18 @@ static bool shader_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype), bNodeTreeType *ntreeType_Shader; -void register_node_tree_type_sh(void) +void register_node_tree_type_sh() { - bNodeTreeType *tt = ntreeType_Shader = MEM_callocN(sizeof(bNodeTreeType), - "shader node tree type"); + bNodeTreeType *tt = ntreeType_Shader = MEM_cnew<bNodeTreeType>("shader node tree type"); tt->type = NTREE_SHADER; strcpy(tt->idname, "ShaderNodeTree"); strcpy(tt->ui_name, N_("Shader Editor")); - tt->ui_icon = 0; /* Defined in `drawnode.c`. */ + tt->ui_icon = ICON_NODE_MATERIAL; strcpy(tt->ui_description, N_("Shader nodes")); tt->foreach_nodeclass = foreach_nodeclass; tt->localize = localize; - tt->local_sync = local_sync; - tt->local_merge = local_merge; tt->update = update; tt->poll = shader_tree_poll; tt->get_from_context = shader_get_from_context; @@ -224,7 +209,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) /* Find output node that matches type and target. If there are * multiple, we prefer exact target match and active nodes. */ - bNode *output_node = NULL; + bNode *output_node = nullptr; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (!ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, SH_NODE_OUTPUT_LIGHT)) { @@ -232,7 +217,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) } if (node->custom1 == SHD_OUTPUT_ALL) { - if (output_node == NULL) { + if (output_node == nullptr) { output_node = node; } else if (output_node->custom1 == SHD_OUTPUT_ALL) { @@ -242,7 +227,7 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) } } else if (node->custom1 == target) { - if (output_node == NULL) { + if (output_node == nullptr) { output_node = node; } else if (output_node->custom1 == SHD_OUTPUT_ALL) { @@ -260,12 +245,12 @@ bNode *ntreeShaderOutputNode(bNodeTree *ntree, int target) /* Find socket with a specified identifier. */ static bNodeSocket *ntree_shader_node_find_socket(ListBase *sockets, const char *identifier) { - for (bNodeSocket *sock = sockets->first; sock != NULL; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, sockets) { if (STREQ(sock->identifier, identifier)) { return sock; } } - return NULL; + return nullptr; } /* Find input socket with a specified identifier. */ @@ -294,37 +279,37 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree, switch (socket->type) { case SOCK_VECTOR: - value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB); + value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB); value_socket = ntree_shader_node_find_output(value_node, "Color"); - BLI_assert(value_socket != NULL); - src_vector = socket->default_value; - dst_rgba = value_socket->default_value; + BLI_assert(value_socket != nullptr); + src_vector = static_cast<bNodeSocketValueVector *>(socket->default_value); + dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value); copy_v3_v3(dst_rgba->value, src_vector->value); dst_rgba->value[3] = 1.0f; /* should never be read */ break; case SOCK_RGBA: - value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_RGB); + value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGB); value_socket = ntree_shader_node_find_output(value_node, "Color"); - BLI_assert(value_socket != NULL); - src_rgba = socket->default_value; - dst_rgba = value_socket->default_value; + BLI_assert(value_socket != nullptr); + src_rgba = static_cast<bNodeSocketValueRGBA *>(socket->default_value); + dst_rgba = static_cast<bNodeSocketValueRGBA *>(value_socket->default_value); copy_v4_v4(dst_rgba->value, src_rgba->value); break; case SOCK_INT: /* HACK: Support as float. */ - value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE); + value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE); value_socket = ntree_shader_node_find_output(value_node, "Value"); - BLI_assert(value_socket != NULL); - src_int = socket->default_value; - dst_float = value_socket->default_value; + BLI_assert(value_socket != nullptr); + src_int = static_cast<bNodeSocketValueInt *>(socket->default_value); + dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value); dst_float->value = (float)(src_int->value); break; case SOCK_FLOAT: - value_node = nodeAddStaticNode(NULL, localtree, SH_NODE_VALUE); + value_node = nodeAddStaticNode(nullptr, localtree, SH_NODE_VALUE); value_socket = ntree_shader_node_find_output(value_node, "Value"); - BLI_assert(value_socket != NULL); - src_float = socket->default_value; - dst_float = value_socket->default_value; + BLI_assert(value_socket != nullptr); + src_float = static_cast<bNodeSocketValueFloat *>(socket->default_value); + dst_float = static_cast<bNodeSocketValueFloat *>(value_socket->default_value); dst_float->value = src_float->value; break; default: @@ -337,11 +322,10 @@ static bool ntree_shader_expand_socket_default(bNodeTree *localtree, static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSocket *isock) { bNodeTree *group_ntree = (bNodeTree *)group_node->id; - bNode *node; bool removed_link = false; - for (node = group_ntree->nodes.first; node; node = node->next) { - const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL); + LISTBASE_FOREACH (bNode *, node, &group_ntree->nodes) { + const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (!is_group && (sock->flag & SOCK_HIDE_VALUE) == 0) { @@ -364,7 +348,7 @@ static void ntree_shader_unlink_hidden_value_sockets(bNode *group_node, bNodeSoc } if (removed_link) { - ntreeUpdateTree(G.main, group_ntree); + BKE_ntree_update_main_tree(G.main, group_ntree, nullptr); } } @@ -375,7 +359,7 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree) bool link_added = false; LISTBASE_FOREACH (bNode *, node, &localtree->nodes) { - const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != NULL); + const bool is_group = ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && (node->id != nullptr); const bool is_group_output = node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT); if (is_group) { @@ -385,25 +369,32 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree) if (is_group || is_group_output) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - if (socket->link != NULL && !(socket->link->flag & NODE_LINK_MUTED)) { + if (socket->link != nullptr && !(socket->link->flag & NODE_LINK_MUTED)) { bNodeLink *link = socket->link; /* Fix the case where the socket is actually converting the data. (see T71374) * We only do the case of lossy conversion to float. */ if ((socket->type == SOCK_FLOAT) && (link->fromsock->type != link->tosock->type)) { if (link->fromsock->type == SOCK_RGBA) { - bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_RGBTOBW); - nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, tmp->inputs.first); - nodeAddLink(localtree, tmp, tmp->outputs.first, node, socket); + bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_RGBTOBW); + nodeAddLink(localtree, + link->fromnode, + link->fromsock, + tmp, + static_cast<bNodeSocket *>(tmp->inputs.first)); + nodeAddLink( + localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.first), node, socket); } else if (link->fromsock->type == SOCK_VECTOR) { - bNode *tmp = nodeAddStaticNode(NULL, localtree, SH_NODE_VECTOR_MATH); + bNode *tmp = nodeAddStaticNode(nullptr, localtree, SH_NODE_VECTOR_MATH); tmp->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT; - bNodeSocket *dot_input1 = tmp->inputs.first; - bNodeSocket *dot_input2 = dot_input1->next; - bNodeSocketValueVector *input2_socket_value = dot_input2->default_value; + bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(tmp->inputs.first); + bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next); + bNodeSocketValueVector *input2_socket_value = static_cast<bNodeSocketValueVector *>( + dot_input2->default_value); copy_v3_fl(input2_socket_value->value, 1.0f / 3.0f); nodeAddLink(localtree, link->fromnode, link->fromsock, tmp, dot_input1); - nodeAddLink(localtree, tmp, tmp->outputs.last, node, socket); + nodeAddLink( + localtree, tmp, static_cast<bNodeSocket *>(tmp->outputs.last), node, socket); } } continue; @@ -423,22 +414,17 @@ static void ntree_shader_groups_expand_inputs(bNodeTree *localtree) } if (link_added) { - ntreeUpdateTree(G.main, localtree); + BKE_ntree_update_main_tree(G.main, localtree, nullptr); } } static void flatten_group_do(bNodeTree *ntree, bNode *gnode) { - bNodeLink *link, *linkn, *tlink; - bNode *node, *nextnode; - bNodeTree *ngroup; - LinkNode *group_interface_nodes = NULL; - - ngroup = (bNodeTree *)gnode->id; + LinkNode *group_interface_nodes = nullptr; + bNodeTree *ngroup = (bNodeTree *)gnode->id; /* Add the nodes into the ntree */ - for (node = ngroup->nodes.first; node; node = nextnode) { - nextnode = node->next; + LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup->nodes) { /* Remove interface nodes. * This also removes remaining links to and from interface nodes. * We must delay removal since sockets will reference this node. see: T52092 */ @@ -454,25 +440,26 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode) } /* Save first and last link to iterate over flattened group links. */ - bNodeLink *glinks_first = ntree->links.last; + bNodeLink *glinks_first = static_cast<bNodeLink *>(ntree->links.last); /* Add internal links to the ntree */ - for (link = ngroup->links.first; link; link = linkn) { - linkn = link->next; + LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ngroup->links) { BLI_remlink(&ngroup->links, link); BLI_addtail(&ntree->links, link); } - bNodeLink *glinks_last = ntree->links.last; + bNodeLink *glinks_last = static_cast<bNodeLink *>(ntree->links.last); /* restore external links to and from the gnode */ - if (glinks_first != NULL) { + if (glinks_first != nullptr) { /* input links */ - for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) { if (link->fromnode->type == NODE_GROUP_INPUT) { const char *identifier = link->fromsock->identifier; /* find external links to this input */ - for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first); + tlink != glinks_first->next; + tlink = tlink->next) { if (tlink->tonode == gnode && STREQ(tlink->tosock->identifier, identifier)) { nodeAddLink(ntree, tlink->fromnode, tlink->fromsock, link->tonode, link->tosock); } @@ -480,13 +467,15 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode) } } /* Also iterate over the new links to cover passthrough links. */ - glinks_last = ntree->links.last; + glinks_last = static_cast<bNodeLink *>(ntree->links.last); /* output links */ - for (tlink = ntree->links.first; tlink != glinks_first->next; tlink = tlink->next) { + for (bNodeLink *tlink = static_cast<bNodeLink *>(ntree->links.first); + tlink != glinks_first->next; + tlink = tlink->next) { if (tlink->fromnode == gnode) { const char *identifier = tlink->fromsock->identifier; /* find internal links to this output */ - for (link = glinks_first->next; link != glinks_last->next; link = link->next) { + for (bNodeLink *link = glinks_first->next; link != glinks_last->next; link = link->next) { /* only use active output node */ if (link->tonode->type == NODE_GROUP_OUTPUT && (link->tonode->flag & NODE_DO_OUTPUT)) { if (STREQ(link->tosock->identifier, identifier)) { @@ -499,11 +488,11 @@ static void flatten_group_do(bNodeTree *ntree, bNode *gnode) } while (group_interface_nodes) { - node = BLI_linklist_pop(&group_interface_nodes); + bNode *node = static_cast<bNode *>(BLI_linklist_pop(&group_interface_nodes)); ntreeFreeLocalNode(ntree, node); } - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_all(ntree); } /* Flatten group to only have a simple single tree */ @@ -511,8 +500,9 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree) { /* This is effectively recursive as the flattened groups will add * nodes at the end of the list, which will also get evaluated. */ - for (bNode *node = localtree->nodes.first, *node_next; node; node = node_next) { - if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != NULL) { + for (bNode *node = static_cast<bNode *>(localtree->nodes.first), *node_next; node; + node = node_next) { + if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP) && node->id != nullptr) { flatten_group_do(localtree, node); /* Continue even on new flattened nodes. */ node_next = node->next; @@ -528,7 +518,7 @@ static void ntree_shader_groups_flatten(bNodeTree *localtree) } } - ntreeUpdateTree(G.main, localtree); + BKE_ntree_update_main_tree(G.main, localtree, nullptr); } /* Check whether shader has a displacement. @@ -543,20 +533,20 @@ static bool ntree_shader_has_displacement(bNodeTree *ntree, bNodeSocket **r_socket, bNodeLink **r_link) { - if (output_node == NULL) { + if (output_node == nullptr) { /* We can't have displacement without output node, apparently. */ return false; } /* Make sure sockets links pointers are correct. */ - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); bNodeSocket *displacement = ntree_shader_node_find_input(output_node, "Displacement"); - if (displacement == NULL) { + if (displacement == nullptr) { /* Non-cycles node is used as an output. */ return false; } - if ((displacement->link != NULL) && !(displacement->link->flag & NODE_LINK_MUTED)) { + if ((displacement->link != nullptr) && !(displacement->link->flag & NODE_LINK_MUTED)) { *r_node = displacement->link->fromnode; *r_socket = displacement->link->fromsock; *r_link = displacement->link; @@ -574,7 +564,7 @@ static void ntree_shader_relink_node_normal(bNodeTree *ntree, * matching? */ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - if (STREQ(sock->identifier, "Normal") && sock->link == NULL) { + if (STREQ(sock->identifier, "Normal") && sock->link == nullptr) { /* It's a normal input and nothing is connected to it. */ nodeAddLink(ntree, node_from, socket_from, node, sock); } @@ -594,7 +584,7 @@ static void ntree_shader_link_builtin_normal(bNodeTree *ntree, bNode *node_from, bNodeSocket *socket_from) { - for (bNode *node = ntree->nodes.first; node != NULL; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node == node_from) { /* Don't connect node itself! */ continue; @@ -619,7 +609,7 @@ static void ntree_shader_bypass_bump_link(bNodeTree *ntree, bNode *bump_node, bN fromnode = bump_normal_input->link->fromnode; } else { - fromnode = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY); + fromnode = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY); fromsock = ntree_shader_node_find_output(fromnode, "Normal"); } /* Bypass the bump node by creating a link between the previous and next node. */ @@ -637,7 +627,7 @@ static void ntree_shader_bypass_tagged_bump_nodes(bNodeTree *ntree) ntree_shader_bypass_bump_link(ntree, node, link); } } - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); } static bool ntree_branch_count_and_tag_nodes(bNode *fromnode, bNode *tonode, void *userdata) @@ -671,19 +661,19 @@ static bNode *ntree_shader_copy_branch(bNodeTree *ntree, int node_count = 1; nodeChainIterBackwards(ntree, start_node, ntree_branch_count_and_tag_nodes, &node_count, 1); /* Make a full copy of the branch */ - bNode **nodes_copy = MEM_mallocN(sizeof(bNode *) * node_count, __func__); + bNode **nodes_copy = static_cast<bNode **>(MEM_mallocN(sizeof(bNode *) * node_count, __func__)); LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->tmp_flag >= 0) { int id = node->tmp_flag; - nodes_copy[id] = BKE_node_copy_ex( + nodes_copy[id] = BKE_node_copy( ntree, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN, false); nodes_copy[id]->tmp_flag = -2; /* Copy */ /* Make sure to clear all sockets links as they are invalid. */ LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->inputs) { - sock->link = NULL; + sock->link = nullptr; } LISTBASE_FOREACH (bNodeSocket *, sock, &nodes_copy[id]->outputs) { - sock->link = NULL; + sock->link = nullptr; } } } @@ -716,13 +706,13 @@ static void ntree_shader_copy_branch_displacement(bNodeTree *ntree, /* Replace displacement socket/node/link. */ bNode *tonode = displacement_link->tonode; bNodeSocket *tosock = displacement_link->tosock; - displacement_node = ntree_shader_copy_branch(ntree, displacement_node, NULL, 0); + displacement_node = ntree_shader_copy_branch(ntree, displacement_node, nullptr, 0); displacement_socket = ntree_shader_node_find_output(displacement_node, displacement_socket->identifier); nodeRemLink(ntree, displacement_link); nodeAddLink(ntree, displacement_node, displacement_socket, tonode, tosock); - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); } /* Re-link displacement output to unconnected normal sockets via bump node. @@ -756,11 +746,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod nodeRemLink(ntree, displacement_link); /* Convert displacement vector to bump height. */ - bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH); - bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY); + bNode *dot_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_VECTOR_MATH); + bNode *geo_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_NEW_GEOMETRY); bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal"); - bNodeSocket *dot_input1 = dot_node->inputs.first; - bNodeSocket *dot_input2 = dot_input1->next; + bNodeSocket *dot_input1 = static_cast<bNodeSocket *>(dot_node->inputs.first); + bNodeSocket *dot_input2 = static_cast<bNodeSocket *>(dot_input1->next); dot_node->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT; nodeAddLink(ntree, displacement_node, displacement_socket, dot_node, dot_input1); @@ -771,11 +761,11 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod /* We can't connect displacement to normal directly, use bump node for that * and hope that it gives good enough approximation. */ - bNode *bump_node = nodeAddStaticNode(NULL, ntree, SH_NODE_BUMP); + bNode *bump_node = nodeAddStaticNode(nullptr, ntree, SH_NODE_BUMP); bNodeSocket *bump_input_socket = ntree_shader_node_find_input(bump_node, "Height"); bNodeSocket *bump_output_socket = ntree_shader_node_find_output(bump_node, "Normal"); - BLI_assert(bump_input_socket != NULL); - BLI_assert(bump_output_socket != NULL); + BLI_assert(bump_input_socket != nullptr); + BLI_assert(bump_output_socket != nullptr); /* Connect bump node to where displacement output was originally * connected to. */ @@ -786,12 +776,12 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod geo_node->tmp_flag = -2; bump_node->tmp_flag = -2; - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); /* Connect all free-standing Normal inputs and relink geometry/coordinate nodes. */ ntree_shader_link_builtin_normal(ntree, bump_node, bump_output_socket); /* We modified the tree, it needs to be updated now. */ - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); } static void node_tag_branch_as_derivative(bNode *node, int dx) @@ -867,11 +857,11 @@ static bool ntree_tag_bsdf_cb(bNode *fromnode, bNode *UNUSED(tonode), void *user */ void ntree_shader_tag_nodes(bNodeTree *ntree, bNode *output_node, nTreeTags *tags) { - if (output_node == NULL) { + if (output_node == nullptr) { return; } /* Make sure sockets links pointers are correct. */ - ntreeUpdateTree(G.main, ntree); + BKE_ntree_update_main_tree(G.main, ntree, nullptr); nodeChainIterBackwards(ntree, output_node, ntree_tag_bsdf_cb, tags, 0); } @@ -889,7 +879,7 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, ntree_shader_groups_flatten(localtree); - if (output == NULL) { + if (output == nullptr) { /* Search again, now including flattened nodes. */ output = ntreeShaderOutputNode(localtree, SHD_OUTPUT_EEVEE); } @@ -905,19 +895,17 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, LISTBASE_FOREACH (bNode *, node, &localtree->nodes) { if (node->type == SH_NODE_OUTPUT_AOV) { nodeChainIterBackwards(localtree, node, ntree_shader_bump_branches, localtree, 0); - nTreeTags tags = { - .ssr_id = 1.0, - .sss_id = 1.0, - }; + nTreeTags tags = {}; + tags.ssr_id = 1.0; + tags.sss_id = 1.0; ntree_shader_tag_nodes(localtree, node, &tags); } } /* TODO(fclem): consider moving this to the gpu shader tree evaluation. */ - nTreeTags tags = { - .ssr_id = 1.0, - .sss_id = 1.0, - }; + nTreeTags tags = {}; + tags.ssr_id = 1.0; + tags.sss_id = 1.0; ntree_shader_tag_nodes(localtree, output, &tags); exec = ntreeShaderBeginExecTree(localtree); @@ -933,15 +921,15 @@ void ntreeGPUMaterialNodes(bNodeTree *localtree, *has_surface_output = false; *has_volume_output = false; - if (output != NULL) { + if (output != nullptr) { bNodeSocket *surface_sock = ntree_shader_node_find_input(output, "Surface"); bNodeSocket *volume_sock = ntree_shader_node_find_input(output, "Volume"); - if (surface_sock != NULL) { + if (surface_sock != nullptr) { *has_surface_output = (nodeCountSocketLinks(localtree, surface_sock) > 0); } - if (volume_sock != NULL) { + if (volume_sock != nullptr) { *has_volume_output = (nodeCountSocketLinks(localtree, volume_sock) > 0); } } @@ -951,19 +939,17 @@ bNodeTreeExec *ntreeShaderBeginExecTree_internal(bNodeExecContext *context, bNodeTree *ntree, bNodeInstanceKey parent_key) { - bNodeTreeExec *exec; - bNode *node; - /* ensures only a single output node is enabled */ ntreeSetOutput(ntree); /* common base initialization */ - exec = ntree_exec_begin(context, ntree, parent_key); + bNodeTreeExec *exec = ntree_exec_begin(context, ntree, parent_key); /* allocate the thread stack listbase array */ - exec->threadstack = MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array"); + exec->threadstack = static_cast<ListBase *>( + MEM_callocN(BLENDER_MAX_THREADS * sizeof(ListBase), "thread stack array")); - for (node = exec->nodetree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &exec->nodetree->nodes) { node->need_exec = 1; } @@ -996,12 +982,9 @@ bNodeTreeExec *ntreeShaderBeginExecTree(bNodeTree *ntree) void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec) { - bNodeThreadStack *nts; - int a; - if (exec->threadstack) { - for (a = 0; a < BLENDER_MAX_THREADS; a++) { - for (nts = exec->threadstack[a].first; nts; nts = nts->next) { + for (int a = 0; a < BLENDER_MAX_THREADS; a++) { + LISTBASE_FOREACH (bNodeThreadStack *, nts, &exec->threadstack[a]) { if (nts->stack) { MEM_freeN(nts->stack); } @@ -1010,7 +993,7 @@ void ntreeShaderEndExecTree_internal(bNodeTreeExec *exec) } MEM_freeN(exec->threadstack); - exec->threadstack = NULL; + exec->threadstack = nullptr; } ntree_exec_end(exec); @@ -1024,6 +1007,6 @@ void ntreeShaderEndExecTree(bNodeTreeExec *exec) ntreeShaderEndExecTree_internal(exec); /* XXX clear nodetree backpointer to exec data, same problem as noted in ntreeBeginExecTree */ - ntree->execdata = NULL; + ntree->execdata = nullptr; } } diff --git a/source/blender/nodes/shader/node_shader_util.cc b/source/blender/nodes/shader/node_shader_util.cc index f2464d4c1b4..722daa1e4f9 100644 --- a/source/blender/nodes/shader/node_shader_util.cc +++ b/source/blender/nodes/shader/node_shader_util.cc @@ -23,7 +23,7 @@ #include "DNA_node_types.h" -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "NOD_socket_search_link.hh" @@ -49,19 +49,18 @@ static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), return true; } -void sh_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag) +void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass) { - node_type_base(ntype, type, name, nclass, flag); + node_type_base(ntype, type, name, nclass); ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } -void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) +void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass) { - sh_node_type_base(ntype, type, name, nclass, flag); + sh_node_type_base(ntype, type, name, nclass); ntype->poll = sh_fn_poll_default; ntype->gather_link_search_ops = blender::nodes::search_link_ops_for_basic_node; } diff --git a/source/blender/nodes/shader/node_shader_util.h b/source/blender/nodes/shader/node_shader_util.hh index c647b86a19a..e66ab9c285b 100644 --- a/source/blender/nodes/shader/node_shader_util.h +++ b/source/blender/nodes/shader/node_shader_util.hh @@ -23,29 +23,21 @@ #pragma once -#include <float.h> -#include <math.h> -#include <string.h> - -#include "MEM_guardedalloc.h" - -#include "DNA_ID.h" -#include "DNA_color_types.h" -#include "DNA_customdata_types.h" -#include "DNA_image_types.h" -#include "DNA_material_types.h" -#include "DNA_node_types.h" -#include "DNA_object_types.h" -#include "DNA_scene_types.h" -#include "DNA_texture_types.h" +#include <cfloat> +#include <cmath> +#include <cstring> #include "BLI_blenlib.h" +#include "BLI_color.hh" +#include "BLI_float3.hh" #include "BLI_math.h" #include "BLI_math_base_safe.h" #include "BLI_rand.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLT_translation.h" + #include "BKE_colorband.h" #include "BKE_colortools.h" #include "BKE_global.h" @@ -55,51 +47,51 @@ #include "BKE_node.h" #include "BKE_texture.h" -#include "NOD_shader.h" -#include "node_util.h" - -#include "BLT_translation.h" - -#include "IMB_colormanagement.h" +#include "DNA_ID.h" +#include "DNA_color_types.h" +#include "DNA_customdata_types.h" +#include "DNA_image_types.h" +#include "DNA_material_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" -#include "RE_pipeline.h" -#include "RE_texture.h" +#include "FN_multi_function_builder.hh" #include "GPU_material.h" #include "GPU_texture.h" #include "GPU_uniform_buffer.h" -#ifdef __cplusplus -# include "FN_multi_function_builder.hh" +#include "IMB_colormanagement.h" -# include "NOD_multi_function.hh" -# include "NOD_socket_declarations.hh" +#include "MEM_guardedalloc.h" -# include "BLI_color.hh" -# include "BLI_float3.hh" +#include "NOD_multi_function.hh" +#include "NOD_shader.h" +#include "NOD_socket_declarations.hh" +#include "node_util.h" -extern "C" { -#endif +#include "RE_pipeline.h" +#include "RE_texture.h" bool sh_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); -void sh_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); -void sh_fn_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void sh_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); +void sh_fn_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); /* ********* exec data struct, remains internal *********** */ -typedef struct ShaderCallData { +struct ShaderCallData { /* Empty for now, may be reused if we convert shader to texture nodes. */ int dummy; -} ShaderCallData; +}; -typedef struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */ +struct XYZ_to_RGB /* Transposed #imbuf_xyz_to_rgb, passed as 3x vec3. */ { float r[3], g[3], b[3]; -} XYZ_to_RGB; +}; void nodestack_get_vec(float *in, short type_in, bNodeStack *ns); @@ -120,7 +112,3 @@ void ntreeExecGPUNodes(struct bNodeTreeExec *exec, struct GPUMaterial *mat, struct bNode *output_node); void get_XYZ_to_RGB_for_gpu(XYZ_to_RGB *data); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/nodes/shader/nodes/node_shader_add_shader.c b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc index 12c138ac9d5..73d5c12ce96 100644 --- a/source/blender/nodes/shader/nodes/node_shader_add_shader.c +++ b/source/blender/nodes/shader/nodes/node_shader_add_shader.cc @@ -17,20 +17,16 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -/* **************** OUTPUT ******************** */ +namespace blender::nodes::node_shader_add_shader_cc { -static bNodeSocketTemplate sh_node_add_shader_in[] = { - {SOCK_SHADER, N_("Shader")}, - {SOCK_SHADER, N_("Shader")}, - {-1, ""}, -}; - -static bNodeSocketTemplate sh_node_add_shader_out[] = { - {SOCK_SHADER, N_("Shader")}, - {-1, ""}, -}; +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Shader>(N_("Shader")); + b.add_input<decl::Shader>(N_("Shader"), "Shader_001"); + b.add_output<decl::Shader>(N_("Shader")); +} static int node_shader_gpu_add_shader(GPUMaterial *mat, bNode *node, @@ -41,16 +37,18 @@ static int node_shader_gpu_add_shader(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_add_shader", in, out); } +} // namespace blender::nodes::node_shader_add_shader_cc + /* node type definition */ -void register_node_type_sh_add_shader(void) +void register_node_type_sh_add_shader() { + namespace file_ns = blender::nodes::node_shader_add_shader_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_add_shader_in, sh_node_add_shader_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_add_shader); + sh_node_type_base(&ntype, SH_NODE_ADD_SHADER, "Add Shader", NODE_CLASS_SHADER); + ntype.declare = file_ns::node_declare; + node_type_gpu(&ntype, file_ns::node_shader_gpu_add_shader); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc index abe80ebcefb..73f0e515a46 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.cc @@ -17,22 +17,18 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -/* **************** OUTPUT ******************** */ +namespace blender::nodes::node_shader_ambient_occlusion_cc { -static bNodeSocketTemplate sh_node_ambient_occlusion_in[] = { - {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {-1, ""}, -}; - -static bNodeSocketTemplate sh_node_ambient_occlusion_out[] = { - {SOCK_RGBA, N_("Color"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 1.0f}, - {SOCK_FLOAT, N_("AO"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, - {-1, ""}, -}; +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Color>(N_("Color")).default_value({1.0f, 1.0f, 1.0f, 1.0f}); + b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f); + b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value(); + b.add_output<decl::Color>(N_("Color")); + b.add_output<decl::Float>(N_("AO")); +} static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, bNode *node, @@ -64,16 +60,19 @@ static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode * node->custom2 = 0; } +} // namespace blender::nodes::node_shader_ambient_occlusion_cc + /* node type definition */ -void register_node_type_sh_ambient_occlusion(void) +void register_node_type_sh_ambient_occlusion() { + namespace file_ns = blender::nodes::node_shader_ambient_occlusion_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, sh_node_ambient_occlusion_in, sh_node_ambient_occlusion_out); - node_type_init(&ntype, node_shader_init_ambient_occlusion); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_ambient_occlusion); + sh_node_type_base(&ntype, SH_NODE_AMBIENT_OCCLUSION, "Ambient Occlusion", NODE_CLASS_INPUT); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_shader_init_ambient_occlusion); + node_type_gpu(&ntype, file_ns::node_shader_gpu_ambient_occlusion); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.cc index 9b3122e38e0..780d0a72ef8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.c +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_attribute_cc { /* **************** OUTPUT ******************** */ @@ -31,7 +33,7 @@ static bNodeSocketTemplate sh_node_attribute_out[] = { static void node_shader_init_attribute(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderAttribute *attr = MEM_callocN(sizeof(NodeShaderAttribute), "NodeShaderAttribute"); + NodeShaderAttribute *attr = MEM_cnew<NodeShaderAttribute>("NodeShaderAttribute"); node->storage = attr; } @@ -41,7 +43,7 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - NodeShaderAttribute *attr = node->storage; + NodeShaderAttribute *attr = static_cast<NodeShaderAttribute *>(node->storage); bool is_varying = attr->type == SHD_ATTRIBUTE_GEOMETRY; if (GPU_material_is_volume_shader(mat) && is_varying) { @@ -81,17 +83,21 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, return 1; } +} // namespace blender::nodes::node_shader_attribute_cc + /* node type definition */ -void register_node_type_sh_attribute(void) +void register_node_type_sh_attribute() { + namespace file_ns = blender::nodes::node_shader_attribute_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_attribute_out); - node_type_init(&ntype, node_shader_init_attribute); + sh_node_type_base(&ntype, SH_NODE_ATTRIBUTE, "Attribute", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_attribute_out); + node_type_init(&ntype, file_ns::node_shader_init_attribute); node_type_storage( &ntype, "NodeShaderAttribute", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_attribute); + node_type_gpu(&ntype, file_ns::node_shader_gpu_attribute); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_background.c b/source/blender/nodes/shader/nodes/node_shader_background.cc index 5281a9fecb1..39858e36fd1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_background.c +++ b/source/blender/nodes/shader/nodes/node_shader_background.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_background_cc { /* **************** OUTPUT ******************** */ @@ -41,16 +43,19 @@ static int node_shader_gpu_background(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_background", in, out); } +} // namespace blender::nodes::node_shader_background_cc + /* node type definition */ -void register_node_type_sh_background(void) +void register_node_type_sh_background() { + namespace file_ns = blender::nodes::node_shader_background_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_background_in, sh_node_background_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_background); + sh_node_type_base(&ntype, SH_NODE_BACKGROUND, "Background", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_background_in, file_ns::sh_node_background_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_background); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bevel.c b/source/blender/nodes/shader/nodes/node_shader_bevel.cc index 347d82c5506..a3063358556 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bevel.c +++ b/source/blender/nodes/shader/nodes/node_shader_bevel.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bevel_cc { /* **************** OUTPUT ******************** */ @@ -54,16 +56,19 @@ static int gpu_shader_bevel(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bevel", in, out); } +} // namespace blender::nodes::node_shader_bevel_cc + /* node type definition */ -void register_node_type_sh_bevel(void) +void register_node_type_sh_bevel() { + namespace file_ns = blender::nodes::node_shader_bevel_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, sh_node_bevel_in, sh_node_bevel_out); - node_type_init(&ntype, node_shader_init_bevel); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, gpu_shader_bevel); + sh_node_type_base(&ntype, SH_NODE_BEVEL, "Bevel", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_bevel_in, file_ns::sh_node_bevel_out); + node_type_init(&ntype, file_ns::node_shader_init_bevel); + node_type_gpu(&ntype, file_ns::gpu_shader_bevel); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_blackbody.c b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc index 95c35affc27..85e2ed08403 100644 --- a/source/blender/nodes/shader/nodes/node_shader_blackbody.c +++ b/source/blender/nodes/shader/nodes/node_shader_blackbody.cc @@ -17,18 +17,15 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -/* **************** Blackbody ******************** */ -static bNodeSocketTemplate sh_node_blackbody_in[] = { - {SOCK_FLOAT, N_("Temperature"), 1500.0f, 0.0f, 0.0f, 0.0f, 800.0f, 12000.0f}, - {-1, ""}, -}; +namespace blender::nodes::node_shader_blackbody_cc { -static bNodeSocketTemplate sh_node_blackbody_out[] = { - {SOCK_RGBA, N_("Color")}, - {-1, ""}, -}; +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Temperature")).default_value(1500.0f).min(800.0f).max(12000.0f); + b.add_output<decl::Color>(N_("Color")); +} static int node_shader_gpu_blackbody(GPUMaterial *mat, bNode *node, @@ -37,7 +34,7 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat, GPUNodeStack *out) { const int size = CM_TABLE + 1; - float *data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"); + float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "blackbody texture")); blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f); @@ -47,17 +44,19 @@ static int node_shader_gpu_blackbody(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_blackbody", in, out, ramp_texture, GPU_constant(&layer)); } +} // namespace blender::nodes::node_shader_blackbody_cc + /* node type definition */ -void register_node_type_sh_blackbody(void) +void register_node_type_sh_blackbody() { + namespace file_ns = blender::nodes::node_shader_blackbody_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER, 0); + sh_node_type_base(&ntype, SH_NODE_BLACKBODY, "Blackbody", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::node_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_socket_templates(&ntype, sh_node_blackbody_in, sh_node_blackbody_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_blackbody); + node_type_gpu(&ntype, file_ns::node_shader_gpu_blackbody); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.cc index 4f375c666de..e6328c4972a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.c +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_brightness_cc { /* **************** Bright and contrast ******************** */ @@ -42,15 +44,18 @@ static int gpu_shader_brightcontrast(GPUMaterial *mat, return GPU_stack_link(mat, node, "brightness_contrast", in, out); } -void register_node_type_sh_brightcontrast(void) +} // namespace blender::nodes::node_shader_brightness_cc + +void register_node_type_sh_brightcontrast() { + namespace file_ns = blender::nodes::node_shader_brightness_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, sh_node_brightcontrast_in, sh_node_brightcontrast_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, gpu_shader_brightcontrast); + sh_node_type_base(&ntype, SH_NODE_BRIGHTCONTRAST, "Bright/Contrast", NODE_CLASS_OP_COLOR); + node_type_socket_templates( + &ntype, file_ns::sh_node_brightcontrast_in, file_ns::sh_node_brightcontrast_out); + node_type_gpu(&ntype, file_ns::gpu_shader_brightcontrast); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc index 499f62da683..2e698aeb4d7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_anisotropic.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_anisotropic_cc { /* **************** OUTPUT ******************** */ @@ -64,17 +66,21 @@ static int node_shader_gpu_bsdf_anisotropic(GPUMaterial *mat, GPU_constant(&node->ssr_id)); } +} // namespace blender::nodes::node_shader_bsdf_anisotropic_cc + /* node type definition */ -void register_node_type_sh_bsdf_anisotropic(void) +void register_node_type_sh_bsdf_anisotropic() { + namespace file_ns = blender::nodes::node_shader_bsdf_anisotropic_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_anisotropic_in, sh_node_bsdf_anisotropic_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_ANISOTROPIC, "Anisotropic BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_anisotropic_in, file_ns::sh_node_bsdf_anisotropic_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_anisotropic); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_anisotropic); + node_type_init(&ntype, file_ns::node_shader_init_anisotropic); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_anisotropic); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc index f4f1d274826..3719227f46c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_diffuse.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_diffuse_cc { /* **************** OUTPUT ******************** */ @@ -48,17 +50,20 @@ static int node_shader_gpu_bsdf_diffuse(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_diffuse", in, out); } +} // namespace blender::nodes::node_shader_bsdf_diffuse_cc + /* node type definition */ -void register_node_type_sh_bsdf_diffuse(void) +void register_node_type_sh_bsdf_diffuse() { + namespace file_ns = blender::nodes::node_shader_bsdf_diffuse_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_diffuse_in, sh_node_bsdf_diffuse_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_DIFFUSE, "Diffuse BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_diffuse_in, file_ns::sh_node_bsdf_diffuse_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_diffuse); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_diffuse); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc index 5fc946e3509..2cea42146fd 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glass.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_glass_cc { /* **************** OUTPUT ******************** */ @@ -53,7 +55,7 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, GPU_link(mat, "set_value_zero", &in[1].link); } - GPU_material_flag_set(mat, GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT); + GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_GLOSSY | GPU_MATFLAG_REFRACT)); float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; @@ -66,17 +68,21 @@ static int node_shader_gpu_bsdf_glass(GPUMaterial *mat, GPU_constant(&node->ssr_id)); } +} // namespace blender::nodes::node_shader_bsdf_glass_cc + /* node type definition */ -void register_node_type_sh_bsdf_glass(void) +void register_node_type_sh_bsdf_glass() { + namespace file_ns = blender::nodes::node_shader_bsdf_glass_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_glass_in, sh_node_bsdf_glass_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_GLASS, "Glass BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_glass_in, file_ns::sh_node_bsdf_glass_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_glass); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_glass); + node_type_init(&ntype, file_ns::node_shader_init_glass); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glass); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc index 13b1b21c7fc..1227d79af93 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_glossy.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_glossy_cc { /* **************** OUTPUT ******************** */ @@ -65,17 +67,21 @@ static int node_shader_gpu_bsdf_glossy(GPUMaterial *mat, GPU_constant(&node->ssr_id)); } +} // namespace blender::nodes::node_shader_bsdf_glossy_cc + /* node type definition */ -void register_node_type_sh_bsdf_glossy(void) +void register_node_type_sh_bsdf_glossy() { + namespace file_ns = blender::nodes::node_shader_bsdf_glossy_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_glossy_in, sh_node_bsdf_glossy_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_GLOSSY, "Glossy BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_glossy_in, file_ns::sh_node_bsdf_glossy_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_glossy); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_glossy); + node_type_init(&ntype, file_ns::node_shader_init_glossy); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_glossy); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc index fb2decec5f4..56282d1c991 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_hair_cc { /* **************** OUTPUT ******************** */ @@ -44,17 +46,20 @@ static int node_shader_gpu_bsdf_hair(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_hair", in, out); } +} // namespace blender::nodes::node_shader_bsdf_hair_cc + /* node type definition */ -void register_node_type_sh_bsdf_hair(void) +void register_node_type_sh_bsdf_hair() { + namespace file_ns = blender::nodes::node_shader_bsdf_hair_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_hair_in, sh_node_bsdf_hair_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_HAIR, "Hair BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_hair_in, file_ns::sh_node_bsdf_hair_out); node_type_size(&ntype, 150, 60, 200); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_hair); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_hair); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc index d2b40a7ec39..16d48144578 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_hair_principled_cc { /* **************** OUTPUT ******************** */ @@ -61,10 +63,9 @@ static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *no /* Triggers (in)visibility of some sockets when changing Parametrization. */ static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) { - bNodeSocket *sock; int parametrization = node->custom1; - for (sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (STREQ(sock->name, "Color")) { nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE); } @@ -91,19 +92,22 @@ static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) } } +} // namespace blender::nodes::node_shader_bsdf_hair_principled_cc + /* node type definition */ -void register_node_type_sh_bsdf_hair_principled(void) +void register_node_type_sh_bsdf_hair_principled() { + namespace file_ns = blender::nodes::node_shader_bsdf_hair_principled_cc; + static bNodeType ntype; sh_node_type_base( - &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER, 0); + &ntype, SH_NODE_BSDF_HAIR_PRINCIPLED, "Principled Hair BSDF", NODE_CLASS_SHADER); node_type_socket_templates( - &ntype, sh_node_bsdf_hair_principled_in, sh_node_bsdf_hair_principled_out); + &ntype, file_ns::sh_node_bsdf_hair_principled_in, file_ns::sh_node_bsdf_hair_principled_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, node_shader_init_hair_principled); - node_type_storage(&ntype, "", NULL, NULL); - node_type_update(&ntype, node_shader_update_hair_principled); + node_type_init(&ntype, file_ns::node_shader_init_hair_principled); + node_type_update(&ntype, file_ns::node_shader_update_hair_principled); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc index b9f4106c79a..72b2c278635 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_principled_cc { /* **************** OUTPUT ******************** */ @@ -122,8 +124,8 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, /* SSS Profile */ if (use_subsurf) { - bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2); - bNodeSocketValueRGBA *socket_data = socket->default_value; + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); + bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; /* For some reason it seems that the socket value is in ARGB format. */ GPU_material_sss_profile_create(mat, &socket_data->value[1]); } @@ -151,7 +153,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, float f_use_refraction = use_refract ? 1.0f : 0.0f; float use_multi_scatter = (node->custom1 == SHD_GLOSSY_MULTI_GGX) ? 1.0f : 0.0f; - GPU_material_flag_set(mat, flag); + GPU_material_flag_set(mat, (eGPUMatFlag)flag); return GPU_stack_link(mat, node, @@ -172,7 +174,7 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) const int distribution = node->custom1; const int sss_method = node->custom2; - for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (STREQ(sock->name, "Transmission Roughness")) { nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); } @@ -183,18 +185,22 @@ static void node_shader_update_principled(bNodeTree *ntree, bNode *node) } } +} // namespace blender::nodes::node_shader_bsdf_principled_cc + /* node type definition */ -void register_node_type_sh_bsdf_principled(void) +void register_node_type_sh_bsdf_principled() { + namespace file_ns = blender::nodes::node_shader_bsdf_principled_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_principled_in, sh_node_bsdf_principled_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_PRINCIPLED, "Principled BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_principled_in, file_ns::sh_node_bsdf_principled_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, node_shader_init_principled); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_principled); - node_type_update(&ntype, node_shader_update_principled); + node_type_init(&ntype, file_ns::node_shader_init_principled); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_principled); + node_type_update(&ntype, file_ns::node_shader_update_principled); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc index ff33b3456db..63bca201898 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_refraction.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_refraction_cc { /* **************** OUTPUT ******************** */ @@ -58,17 +60,21 @@ static int node_shader_gpu_bsdf_refraction(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_refraction", in, out); } +} // namespace blender::nodes::node_shader_bsdf_refraction_cc + /* node type definition */ -void register_node_type_sh_bsdf_refraction(void) +void register_node_type_sh_bsdf_refraction() { + namespace file_ns = blender::nodes::node_shader_bsdf_refraction_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_refraction_in, sh_node_bsdf_refraction_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_REFRACTION, "Refraction BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_refraction_in, file_ns::sh_node_bsdf_refraction_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_refraction); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_refraction); + node_type_init(&ntype, file_ns::node_shader_init_refraction); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_refraction); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc index 2d04fcee40c..270288c3ce0 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_toon.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_toon_cc { /* **************** OUTPUT ******************** */ @@ -49,17 +51,20 @@ static int node_shader_gpu_bsdf_toon(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_toon", in, out); } +} // namespace blender::nodes::node_shader_bsdf_toon_cc + /* node type definition */ -void register_node_type_sh_bsdf_toon(void) +void register_node_type_sh_bsdf_toon() { + namespace file_ns = blender::nodes::node_shader_bsdf_toon_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_toon_in, sh_node_bsdf_toon_out); + sh_node_type_base(&ntype, SH_NODE_BSDF_TOON, "Toon BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_toon_in, file_ns::sh_node_bsdf_toon_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_toon); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_toon); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc index d2e1a276645..421c7c16032 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_translucent.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_translucent_cc { /* **************** OUTPUT ******************** */ @@ -47,16 +49,19 @@ static int node_shader_gpu_bsdf_translucent(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_translucent", in, out); } +} // namespace blender::nodes::node_shader_bsdf_translucent_cc + /* node type definition */ -void register_node_type_sh_bsdf_translucent(void) +void register_node_type_sh_bsdf_translucent() { + namespace file_ns = blender::nodes::node_shader_bsdf_translucent_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_translucent_in, sh_node_bsdf_translucent_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_translucent); + sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSLUCENT, "Translucent BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_translucent_in, file_ns::sh_node_bsdf_translucent_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_translucent); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc index 45f8ebf1d52..d1dc1856863 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_transparent.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_transparent_cc { /* **************** OUTPUT ******************** */ @@ -40,16 +42,19 @@ static int node_shader_gpu_bsdf_transparent(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_transparent", in, out); } +} // namespace blender::nodes::node_shader_bsdf_transparent_cc + /* node type definition */ -void register_node_type_sh_bsdf_transparent(void) +void register_node_type_sh_bsdf_transparent() { + namespace file_ns = blender::nodes::node_shader_bsdf_transparent_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_transparent_in, sh_node_bsdf_transparent_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_transparent); + sh_node_type_base(&ntype, SH_NODE_BSDF_TRANSPARENT, "Transparent BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_transparent_in, file_ns::sh_node_bsdf_transparent_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_transparent); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc index 59e8bbd3c63..6293f38d792 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_velvet.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_bsdf_velvet_cc { /* **************** OUTPUT ******************** */ @@ -48,16 +50,19 @@ static int node_shader_gpu_bsdf_velvet(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_bsdf_velvet", in, out); } +} // namespace blender::nodes::node_shader_bsdf_velvet_cc + /* node type definition */ -void register_node_type_sh_bsdf_velvet(void) +void register_node_type_sh_bsdf_velvet() { + namespace file_ns = blender::nodes::node_shader_bsdf_velvet_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_bsdf_velvet_in, sh_node_bsdf_velvet_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_bsdf_velvet); + sh_node_type_base(&ntype, SH_NODE_BSDF_VELVET, "Velvet BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_bsdf_velvet_in, file_ns::sh_node_bsdf_velvet_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_bsdf_velvet); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_bump.c b/source/blender/nodes/shader/nodes/node_shader_bump.cc index 7444ea3952a..7718b21af52 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bump.c +++ b/source/blender/nodes/shader/nodes/node_shader_bump.cc @@ -21,22 +21,30 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" /* **************** BUMP ******************** */ -/* clang-format off */ -static bNodeSocketTemplate sh_node_bump_in[] = { - {SOCK_FLOAT, N_("Strength"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_FACTOR}, - {SOCK_FLOAT, N_("Distance"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1000.0f}, - {SOCK_FLOAT, N_("Height"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {SOCK_FLOAT, N_("Height_dx"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL}, - {SOCK_FLOAT, N_("Height_dy"), 1.0f, 1.0f, 1.0f, 1.0f, -1000.0f, 1000.0f, PROP_NONE, SOCK_UNAVAIL}, - {SOCK_VECTOR, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {-1, ""} -}; -/* clang-format on */ -static bNodeSocketTemplate sh_node_bump_out[] = {{SOCK_VECTOR, "Normal"}, {-1, ""}}; +namespace blender::nodes::node_shader_bump_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Strength")) + .default_value(1.0f) + .min(0.0f) + .max(1.0f) + .subtype(PROP_FACTOR); + b.add_input<decl::Float>(N_("Distance")).default_value(1.0f).min(0.0f).max(1000.0f); + b.add_input<decl::Float>(N_("Height")) + .default_value(1.0f) + .min(-1000.0f) + .max(1000.0f) + .hide_value(); + b.add_input<decl::Float>(N_("Height_dx")).default_value(1.0f).unavailable(); + b.add_input<decl::Float>(N_("Height_dy")).default_value(1.0f).unavailable(); + b.add_input<decl::Vector>(N_("Normal")).min(-1.0f).max(1.0f).hide_value(); + b.add_output<decl::Vector>(N_("Normal")); +} static int gpu_shader_bump(GPUMaterial *mat, bNode *node, @@ -54,15 +62,18 @@ static int gpu_shader_bump(GPUMaterial *mat, mat, node, "node_bump", in, out, GPU_builtin(GPU_VIEW_POSITION), GPU_constant(&invert)); } +} // namespace blender::nodes::node_shader_bump_cc + /* node type definition */ -void register_node_type_sh_bump(void) +void register_node_type_sh_bump() { + namespace file_ns = blender::nodes::node_shader_bump_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_bump_in, sh_node_bump_out); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, gpu_shader_bump); + sh_node_type_base(&ntype, SH_NODE_BUMP, "Bump", NODE_CLASS_OP_VECTOR); + ntype.declare = file_ns::node_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_bump); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_camera.c b/source/blender/nodes/shader/nodes/node_shader_camera.cc index 5148104700a..ab8a98f47fd 100644 --- a/source/blender/nodes/shader/nodes/node_shader_camera.c +++ b/source/blender/nodes/shader/nodes/node_shader_camera.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_camera_cc { /* **************** CAMERA INFO ******************** */ static bNodeSocketTemplate sh_node_camera_out[] = { @@ -44,14 +46,17 @@ static int gpu_shader_camera(GPUMaterial *mat, return GPU_stack_link(mat, node, "camera", in, out, viewvec); } -void register_node_type_sh_camera(void) +} // namespace blender::nodes::node_shader_camera_cc + +void register_node_type_sh_camera() { + namespace file_ns = blender::nodes::node_shader_camera_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_camera_out); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, gpu_shader_camera); + sh_node_type_base(&ntype, SH_NODE_CAMERA, "Camera Data", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_camera_out); + node_type_gpu(&ntype, file_ns::gpu_shader_camera); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_clamp.cc b/source/blender/nodes/shader/nodes/node_shader_clamp.cc index 6c3457151e5..f4c72f0616f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_clamp.cc +++ b/source/blender/nodes/shader/nodes/node_shader_clamp.cc @@ -21,21 +21,19 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_clamp_cc { static void sh_node_clamp_declare(NodeDeclarationBuilder &b) { b.is_function_node(); - b.add_input<decl::Float>(N_("Value")).min(0.0f).max(1.0f).default_value(1.0f); + b.add_input<decl::Float>(N_("Value")).default_value(1.0f); b.add_input<decl::Float>(N_("Min")).default_value(0.0f).min(-10000.0f).max(10000.0f); b.add_input<decl::Float>(N_("Max")).default_value(1.0f).min(-10000.0f).max(10000.0f); b.add_output<decl::Float>(N_("Result")); }; -} // namespace blender::nodes - static void node_shader_init_clamp(bNodeTree *UNUSED(ntree), bNode *node) { node->custom1 = NODE_CLAMP_MINMAX; /* clamp type */ @@ -75,15 +73,19 @@ static void sh_node_clamp_build_multi_function(blender::nodes::NodeMultiFunction } } +} // namespace blender::nodes::node_shader_clamp_cc + void register_node_type_sh_clamp() { + namespace file_ns = blender::nodes::node_shader_clamp_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_clamp_declare; - node_type_init(&ntype, node_shader_init_clamp); - node_type_gpu(&ntype, gpu_shader_clamp); - ntype.build_multi_function = sh_node_clamp_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_CLAMP, "Clamp", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_clamp_declare; + node_type_init(&ntype, file_ns::node_shader_init_clamp); + node_type_gpu(&ntype, file_ns::gpu_shader_clamp); + ntype.build_multi_function = file_ns::sh_node_clamp_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc new file mode 100644 index 00000000000..ff43885741b --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_color_ramp.cc @@ -0,0 +1,189 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup shdnodes + */ + +#include "DNA_texture_types.h" + +#include "BLI_color.hh" + +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_color_ramp_cc { + +static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); + b.add_output<decl::Color>(N_("Color")); + b.add_output<decl::Float>(N_("Alpha")); +}; + +static void node_shader_exec_valtorgb(void *UNUSED(data), + int UNUSED(thread), + bNode *node, + bNodeExecData *UNUSED(execdata), + bNodeStack **in, + bNodeStack **out) +{ + /* stack order in: fac */ + /* stack order out: col, alpha */ + + if (node->storage) { + float fac; + nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); + + BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec); + out[1]->vec[0] = out[0]->vec[3]; + } +} + +static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node) +{ + node->storage = BKE_colorband_add(true); +} + +static int gpu_shader_valtorgb(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + struct ColorBand *coba = (ColorBand *)node->storage; + float *array, layer; + int size; + + /* Common / easy case optimization. */ + if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) { + float mul_bias[2]; + switch (coba->ipotype) { + case COLBAND_INTERP_LINEAR: + mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos); + mul_bias[1] = -mul_bias[0] * coba->data[0].pos; + return GPU_stack_link(mat, + node, + "valtorgb_opti_linear", + in, + out, + GPU_uniform(mul_bias), + GPU_uniform(&coba->data[0].r), + GPU_uniform(&coba->data[1].r)); + case COLBAND_INTERP_CONSTANT: + mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos); + return GPU_stack_link(mat, + node, + "valtorgb_opti_constant", + in, + out, + GPU_uniform(&mul_bias[1]), + GPU_uniform(&coba->data[0].r), + GPU_uniform(&coba->data[1].r)); + case COLBAND_INTERP_EASE: + mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos); + mul_bias[1] = -mul_bias[0] * coba->data[0].pos; + return GPU_stack_link(mat, + node, + "valtorgb_opti_ease", + in, + out, + GPU_uniform(mul_bias), + GPU_uniform(&coba->data[0].r), + GPU_uniform(&coba->data[1].r)); + default: + break; + } + } + + BKE_colorband_evaluate_table_rgba(coba, &array, &size); + GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); + + if (coba->ipotype == COLBAND_INTERP_CONSTANT) { + return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer)); + } + + return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer)); +} + +class ColorBandFunction : public blender::fn::MultiFunction { + private: + const ColorBand &color_band_; + + public: + ColorBandFunction(const ColorBand &color_band) : color_band_(color_band) + { + static blender::fn::MFSignature signature = create_signature(); + this->set_signature(&signature); + } + + static blender::fn::MFSignature create_signature() + { + blender::fn::MFSignatureBuilder signature{"Color Band"}; + signature.single_input<float>("Value"); + signature.single_output<blender::ColorGeometry4f>("Color"); + signature.single_output<float>("Alpha"); + return signature.build(); + } + + void call(blender::IndexMask mask, + blender::fn::MFParams params, + blender::fn::MFContext UNUSED(context)) const override + { + const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value"); + blender::MutableSpan<blender::ColorGeometry4f> colors = + params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color"); + blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha"); + + for (int64_t i : mask) { + blender::ColorGeometry4f color; + BKE_colorband_evaluate(&color_band_, values[i], color); + colors[i] = color; + alphas[i] = color.a; + } + } +}; + +static void sh_node_valtorgb_build_multi_function( + blender::nodes::NodeMultiFunctionBuilder &builder) +{ + bNode &bnode = builder.node(); + const ColorBand *color_band = (const ColorBand *)bnode.storage; + builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band); +} + +} // namespace blender::nodes::node_shader_color_ramp_cc + +void register_node_type_sh_valtorgb() +{ + namespace file_ns = blender::nodes::node_shader_color_ramp_cc; + + static bNodeType ntype; + + sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_valtorgb_declare; + node_type_init(&ntype, file_ns::node_shader_init_valtorgb); + node_type_size_preset(&ntype, NODE_SIZE_LARGE); + node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_valtorgb); + node_type_gpu(&ntype, file_ns::gpu_shader_valtorgb); + ntype.build_multi_function = file_ns::sh_node_valtorgb_build_multi_function; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.cc index 190e0cfad4c..b5c908c410b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.cc @@ -31,7 +31,7 @@ #include "NOD_common.h" #include "node_common.h" #include "node_exec.h" -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "RNA_access.h" @@ -55,7 +55,7 @@ static void move_stack(bNodeStack *to, bNodeStack *from) to->datatype = from->datatype; to->is_copy = from->is_copy; - from->data = NULL; + from->data = nullptr; from->is_copy = 0; } } @@ -68,7 +68,7 @@ static void *group_initexec(bNodeExecContext *context, bNode *node, bNodeInstanc bNodeTreeExec *exec; if (!ngroup) { - return NULL; + return nullptr; } /* initialize the internal node tree execution */ @@ -91,15 +91,12 @@ static void group_freeexec(void *nodedata) static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack) { bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock; - bNodeStack *ns; - int a; - for (node = ngroup->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { if (node->type == NODE_GROUP_INPUT) { - for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) { - ns = node_get_socket_stack(gstack, sock); + int a; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) { + bNodeStack *ns = node_get_socket_stack(gstack, sock); if (ns) { copy_stack(ns, in[a]); } @@ -113,15 +110,12 @@ static void group_copy_inputs(bNode *gnode, bNodeStack **in, bNodeStack *gstack) static void group_move_outputs(bNode *gnode, bNodeStack **out, bNodeStack *gstack) { bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock; - bNodeStack *ns; - int a; - for (node = ngroup->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { - for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) { - ns = node_get_socket_stack(gstack, sock); + int a; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) { + bNodeStack *ns = node_get_socket_stack(gstack, sock); if (ns) { move_stack(out[a], ns); } @@ -138,8 +132,7 @@ static void group_execute(void *data, struct bNodeStack **in, struct bNodeStack **out) { - bNodeTreeExec *exec = execdata->data; - bNodeThreadStack *nts; + bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data); if (!exec) { return; @@ -149,13 +142,12 @@ static void group_execute(void *data, * it's stupid, but just makes it work. compo redesign will do this better. */ { - bNode *inode; - for (inode = exec->nodetree->nodes.first; inode; inode = inode->next) { + LISTBASE_FOREACH (bNode *, inode, &exec->nodetree->nodes) { inode->need_exec = 1; } } - nts = ntreeGetThreadStack(exec, thread); + bNodeThreadStack *nts = ntreeGetThreadStack(exec, thread); group_copy_inputs(node, in, nts->stack); ntreeExecThreadNodes(exec, nts, data, thread); @@ -167,15 +159,12 @@ static void group_execute(void *data, static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gstack) { bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock; - bNodeStack *ns; - int a; - for (node = ngroup->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { if (node->type == NODE_GROUP_INPUT) { - for (sock = node->outputs.first, a = 0; sock; sock = sock->next, a++) { - ns = node_get_socket_stack(gstack, sock); + int a; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->outputs, a) { + bNodeStack *ns = node_get_socket_stack(gstack, sock); if (ns) { /* convert the external gpu stack back to internal node stack data */ node_data_from_gpu_stack(ns, &in[a]); @@ -190,15 +179,12 @@ static void group_gpu_copy_inputs(bNode *gnode, GPUNodeStack *in, bNodeStack *gs static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack *gstack) { bNodeTree *ngroup = (bNodeTree *)gnode->id; - bNode *node; - bNodeSocket *sock; - bNodeStack *ns; - int a; - for (node = ngroup->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { if (node->type == NODE_GROUP_OUTPUT && (node->flag & NODE_DO_OUTPUT)) { - for (sock = node->inputs.first, a = 0; sock; sock = sock->next, a++) { - ns = node_get_socket_stack(gstack, sock); + int a; + LISTBASE_FOREACH_INDEX (bNodeSocket *, sock, &node->inputs, a) { + bNodeStack *ns = node_get_socket_stack(gstack, sock); if (ns) { /* convert the node stack data result back to gpu stack */ node_gpu_stack_from_data(&out[a], sock->type, ns); @@ -212,36 +198,36 @@ static void group_gpu_move_outputs(bNode *gnode, GPUNodeStack *out, bNodeStack * static int gpu_group_execute( GPUMaterial *mat, bNode *node, bNodeExecData *execdata, GPUNodeStack *in, GPUNodeStack *out) { - bNodeTreeExec *exec = execdata->data; + bNodeTreeExec *exec = static_cast<bNodeTreeExec *>(execdata->data); if (!node->id) { return 0; } group_gpu_copy_inputs(node, in, exec->stack); - ntreeExecGPUNodes(exec, mat, NULL); + ntreeExecGPUNodes(exec, mat, nullptr); group_gpu_move_outputs(node, out, exec->stack); return 1; } -void register_node_type_sh_group(void) +void register_node_type_sh_group() { static bNodeType ntype; /* NOTE: cannot use #sh_node_type_base for node group, because it would map the node type * to the shared #NODE_GROUP integer type id. */ - node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP, 0); + node_type_base_custom(&ntype, "ShaderNodeGroup", "Group", NODE_CLASS_GROUP); ntype.type = NODE_GROUP; ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup"); - BLI_assert(ntype.rna_ext.srna != NULL); + BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); - node_type_socket_templates(&ntype, NULL, NULL); + node_type_socket_templates(&ntype, nullptr, nullptr); node_type_size(&ntype, 140, 60, 400); ntype.labelfunc = node_group_label; node_type_group_update(&ntype, node_group_update); @@ -254,10 +240,10 @@ void register_node_type_sh_group(void) void register_node_type_sh_custom_group(bNodeType *ntype) { /* These methods can be overridden but need a default implementation otherwise. */ - if (ntype->poll == NULL) { + if (ntype->poll == nullptr) { ntype->poll = sh_node_poll_default; } - if (ntype->insert_link == NULL) { + if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/shader/nodes/node_shader_curves.cc b/source/blender/nodes/shader/nodes/node_shader_curves.cc index 09bbf3d851c..12ac83f35a2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_curves.cc +++ b/source/blender/nodes/shader/nodes/node_shader_curves.cc @@ -21,9 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_curves_cc { static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b) { @@ -33,8 +33,6 @@ static void sh_node_curve_vec_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Vector")); }; -} // namespace blender::nodes - static void node_shader_exec_curve_vec(void *UNUSED(data), int UNUSED(thread), bNode *node, @@ -152,25 +150,29 @@ static void sh_node_curve_vec_build_multi_function( builder.construct_and_set_matching_fn<CurveVecFunction>(*cumap); } +} // namespace blender::nodes::node_shader_curves_cc + void register_node_type_sh_curve_vec() { + namespace file_ns = blender::nodes::node_shader_curves_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR, 0); - ntype.declare = blender::nodes::sh_node_curve_vec_declare; - node_type_init(&ntype, node_shader_init_curve_vec); + sh_fn_node_type_base(&ntype, SH_NODE_CURVE_VEC, "Vector Curves", NODE_CLASS_OP_VECTOR); + ntype.declare = file_ns::sh_node_curve_vec_declare; + node_type_init(&ntype, file_ns::node_shader_init_curve_vec); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); - node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_vec); - node_type_gpu(&ntype, gpu_shader_curve_vec); - ntype.build_multi_function = sh_node_curve_vec_build_multi_function; + node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_vec); + node_type_gpu(&ntype, file_ns::gpu_shader_curve_vec); + ntype.build_multi_function = file_ns::sh_node_curve_vec_build_multi_function; nodeRegisterType(&ntype); } /* **************** CURVE RGB ******************** */ -namespace blender::nodes { +namespace blender::nodes::node_shader_curves_cc { static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b) { @@ -180,8 +182,6 @@ static void sh_node_curve_rgb_declare(NodeDeclarationBuilder &b) b.add_output<decl::Color>(N_("Color")); }; -} // namespace blender::nodes - static void node_shader_exec_curve_rgb(void *UNUSED(data), int UNUSED(thread), bNode *node, @@ -329,25 +329,29 @@ static void sh_node_curve_rgb_build_multi_function( builder.construct_and_set_matching_fn<CurveRGBFunction>(*cumap); } +} // namespace blender::nodes::node_shader_curves_cc + void register_node_type_sh_curve_rgb() { + namespace file_ns = blender::nodes::node_shader_curves_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0); - ntype.declare = blender::nodes::sh_node_curve_rgb_declare; - node_type_init(&ntype, node_shader_init_curve_rgb); + sh_fn_node_type_base(&ntype, SH_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR); + ntype.declare = file_ns::sh_node_curve_rgb_declare; + node_type_init(&ntype, file_ns::node_shader_init_curve_rgb); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); - node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_rgb); - node_type_gpu(&ntype, gpu_shader_curve_rgb); - ntype.build_multi_function = sh_node_curve_rgb_build_multi_function; + node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_rgb); + node_type_gpu(&ntype, file_ns::gpu_shader_curve_rgb); + ntype.build_multi_function = file_ns::sh_node_curve_rgb_build_multi_function; nodeRegisterType(&ntype); } /* **************** CURVE FLOAT ******************** */ -namespace blender::nodes { +namespace blender::nodes::node_shader_curves_cc { static void sh_node_curve_float_declare(NodeDeclarationBuilder &b) { @@ -361,8 +365,6 @@ static void sh_node_curve_float_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; -} // namespace blender::nodes - static void node_shader_exec_curve_float(void *UNUSED(data), int UNUSED(thread), bNode *node, @@ -473,18 +475,22 @@ static void sh_node_curve_float_build_multi_function( builder.construct_and_set_matching_fn<CurveFloatFunction>(*cumap); } +} // namespace blender::nodes::node_shader_curves_cc + void register_node_type_sh_curve_float() { + namespace file_ns = blender::nodes::node_shader_curves_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_curve_float_declare; - node_type_init(&ntype, node_shader_init_curve_float); + sh_fn_node_type_base(&ntype, SH_NODE_CURVE_FLOAT, "Float Curve", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_curve_float_declare; + node_type_init(&ntype, file_ns::node_shader_init_curve_float); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_storage(&ntype, "CurveMapping", node_free_curves, node_copy_curves); - node_type_exec(&ntype, node_initexec_curves, nullptr, node_shader_exec_curve_float); - node_type_gpu(&ntype, gpu_shader_curve_float); - ntype.build_multi_function = sh_node_curve_float_build_multi_function; + node_type_exec(&ntype, node_initexec_curves, nullptr, file_ns::node_shader_exec_curve_float); + node_type_gpu(&ntype, file_ns::gpu_shader_curve_float); + ntype.build_multi_function = file_ns::sh_node_curve_float_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_displacement.c b/source/blender/nodes/shader/nodes/node_shader_displacement.cc index e7deef23428..ef79e6d5c7e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_displacement.c +++ b/source/blender/nodes/shader/nodes/node_shader_displacement.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_displacement_cc { /* **************** OUTPUT ******************** */ @@ -68,16 +70,20 @@ static int gpu_shader_displacement(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_displacement_world", in, out); } +} // namespace blender::nodes::node_shader_displacement_cc + /* node type definition */ -void register_node_type_sh_displacement(void) +void register_node_type_sh_displacement() { + namespace file_ns = blender::nodes::node_shader_displacement_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_displacement_in, sh_node_displacement_out); - node_type_storage(&ntype, "", NULL, NULL); - node_type_init(&ntype, node_shader_init_displacement); - node_type_gpu(&ntype, gpu_shader_displacement); + sh_node_type_base(&ntype, SH_NODE_DISPLACEMENT, "Displacement", NODE_CLASS_OP_VECTOR); + node_type_socket_templates( + &ntype, file_ns::sh_node_displacement_in, file_ns::sh_node_displacement_out); + node_type_init(&ntype, file_ns::node_shader_init_displacement); + node_type_gpu(&ntype, file_ns::gpu_shader_displacement); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc index 015af19abb2..aa34ba225a2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_eevee_specular.c +++ b/source/blender/nodes/shader/nodes/node_shader_eevee_specular.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_eevee_specular_cc { /* **************** OUTPUT ******************** */ @@ -81,21 +83,24 @@ static int node_shader_gpu_eevee_specular(GPUMaterial *mat, GPU_link(mat, "set_value", GPU_constant(&one), &in[9].link); } - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY); + GPU_material_flag_set(mat, static_cast<eGPUMatFlag>(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_GLOSSY)); return GPU_stack_link(mat, node, "node_eevee_specular", in, out, GPU_constant(&node->ssr_id)); } +} // namespace blender::nodes::node_shader_eevee_specular_cc + /* node type definition */ -void register_node_type_sh_eevee_specular(void) +void register_node_type_sh_eevee_specular() { + namespace file_ns = blender::nodes::node_shader_eevee_specular_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_eevee_specular_in, sh_node_eevee_specular_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_eevee_specular); + sh_node_type_base(&ntype, SH_NODE_EEVEE_SPECULAR, "Specular BSDF", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_eevee_specular_in, file_ns::sh_node_eevee_specular_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_eevee_specular); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_emission.c b/source/blender/nodes/shader/nodes/node_shader_emission.cc index 13f040fca48..47e4d3ad399 100644 --- a/source/blender/nodes/shader/nodes/node_shader_emission.c +++ b/source/blender/nodes/shader/nodes/node_shader_emission.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_emission_cc { /* **************** OUTPUT ******************** */ @@ -41,16 +43,18 @@ static int node_shader_gpu_emission(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_emission", in, out, GPU_builtin(GPU_VIEW_NORMAL)); } +} // namespace blender::nodes::node_shader_emission_cc + /* node type definition */ -void register_node_type_sh_emission(void) +void register_node_type_sh_emission() { + namespace file_ns = blender::nodes::node_shader_emission_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_emission_in, sh_node_emission_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_emission); + sh_node_type_base(&ntype, SH_NODE_EMISSION, "Emission", NODE_CLASS_SHADER); + node_type_socket_templates(&ntype, file_ns::sh_node_emission_in, file_ns::sh_node_emission_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_emission); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_fresnel.c b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc index 0af4e4ff5fb..4aa615e539e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_fresnel.c +++ b/source/blender/nodes/shader/nodes/node_shader_fresnel.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_fresnel_cc { /* **************** Fresnel ******************** */ static bNodeSocketTemplate sh_node_fresnel_in[] = { @@ -57,17 +59,19 @@ static void node_shader_exec_fresnel(void *UNUSED(data), { } +} // namespace blender::nodes::node_shader_fresnel_cc + /* node type definition */ -void register_node_type_sh_fresnel(void) +void register_node_type_sh_fresnel() { + namespace file_ns = blender::nodes::node_shader_fresnel_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, sh_node_fresnel_in, sh_node_fresnel_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_fresnel); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_fresnel); + sh_node_type_base(&ntype, SH_NODE_FRESNEL, "Fresnel", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_fresnel_in, file_ns::sh_node_fresnel_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_fresnel); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_fresnel); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.cc index b48838e5f56..2c2ef0e5ef8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_gamma_cc { /* **************** Gamma Tools ******************** */ @@ -58,16 +60,18 @@ static int node_shader_gpu_gamma(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_gamma", in, out); } -void register_node_type_sh_gamma(void) +} // namespace blender::nodes::node_shader_gamma_cc + +void register_node_type_sh_gamma() { + namespace file_ns = blender::nodes::node_shader_gamma_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, sh_node_gamma_in, sh_node_gamma_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_gamma); - node_type_gpu(&ntype, node_shader_gpu_gamma); + sh_node_type_base(&ntype, SH_NODE_GAMMA, "Gamma", NODE_CLASS_OP_COLOR); + node_type_socket_templates(&ntype, file_ns::sh_node_gamma_in, file_ns::sh_node_gamma_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_gamma); + node_type_gpu(&ntype, file_ns::node_shader_gpu_gamma); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_geometry.c b/source/blender/nodes/shader/nodes/node_shader_geometry.cc index f66633e64c8..175be15c6e3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_geometry.c +++ b/source/blender/nodes/shader/nodes/node_shader_geometry.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_geometry_cc { /* **************** OUTPUT ******************** */ @@ -79,23 +81,25 @@ static int node_shader_gpu_geometry(GPUMaterial *mat, out[i].link, out[i].link, &out[i].link, - NULL); + nullptr); } } return success; } +} // namespace blender::nodes::node_shader_geometry_cc + /* node type definition */ -void register_node_type_sh_geometry(void) +void register_node_type_sh_geometry() { + namespace file_ns = blender::nodes::node_shader_geometry_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_geometry_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_geometry); + sh_node_type_base(&ntype, SH_NODE_NEW_GEOMETRY, "Geometry", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_geometry_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_geometry); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_hair_info.c b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc index c721fb9c77a..c5af7e16201 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hair_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_hair_info.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_hair_info_cc { static bNodeSocketTemplate outputs[] = { {SOCK_FLOAT, N_("Is Strand"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f}, @@ -43,16 +45,18 @@ static int node_shader_gpu_hair_info(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_hair_info", in, out, length_link); } +} // namespace blender::nodes::node_shader_hair_info_cc + /* node type definition */ -void register_node_type_sh_hair_info(void) +void register_node_type_sh_hair_info() { + namespace file_ns = blender::nodes::node_shader_hair_info_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, outputs); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_hair_info); + sh_node_type_base(&ntype, SH_NODE_HAIR_INFO, "Hair Info", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::outputs); + node_type_gpu(&ntype, file_ns::node_shader_gpu_hair_info); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_holdout.c b/source/blender/nodes/shader/nodes/node_shader_holdout.cc index b58f86c1fc0..5a939d0b4f3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_holdout.c +++ b/source/blender/nodes/shader/nodes/node_shader_holdout.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_holdout_cc { /* **************** OUTPUT ******************** */ @@ -39,16 +41,18 @@ static int gpu_shader_rgb(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_holdout", in, out); } +} // namespace blender::nodes::node_shader_holdout_cc + /* node type definition */ -void register_node_type_sh_holdout(void) +void register_node_type_sh_holdout() { + namespace file_ns = blender::nodes::node_shader_holdout_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_holdout_in, sh_node_holdout_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, gpu_shader_rgb); + sh_node_type_base(&ntype, SH_NODE_HOLDOUT, "Holdout", NODE_CLASS_SHADER); + node_type_socket_templates(&ntype, file_ns::sh_node_holdout_in, file_ns::sh_node_holdout_out); + node_type_gpu(&ntype, file_ns::gpu_shader_rgb); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc index 50eb5bf32c9..d63d664045b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c +++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_hueSatVal_cc { /* **************** Hue Saturation ******************** */ static bNodeSocketTemplate sh_node_hue_sat_in[] = { @@ -85,15 +87,19 @@ static int gpu_shader_hue_sat(GPUMaterial *mat, return GPU_stack_link(mat, node, "hue_sat", in, out); } -void register_node_type_sh_hue_sat(void) +} // namespace blender::nodes::node_shader_hueSatVal_cc + +void register_node_type_sh_hue_sat() { + namespace file_ns = blender::nodes::node_shader_hueSatVal_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, sh_node_hue_sat_in, sh_node_hue_sat_out); + sh_node_type_base(&ntype, SH_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR); + node_type_socket_templates(&ntype, file_ns::sh_node_hue_sat_in, file_ns::sh_node_hue_sat_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_hue_sat); - node_type_gpu(&ntype, gpu_shader_hue_sat); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_hue_sat); + node_type_gpu(&ntype, file_ns::gpu_shader_hue_sat); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_ies_light.c b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc index 9cc5fd46181..a107fd83b0e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ies_light.c +++ b/source/blender/nodes/shader/nodes/node_shader_ies_light.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_ies_light_cc { /* **************** IES Light ******************** */ @@ -34,18 +36,22 @@ static bNodeSocketTemplate sh_node_tex_ies_out[] = { static void node_shader_init_tex_ies(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderTexIES *tex = MEM_callocN(sizeof(NodeShaderTexIES), "NodeShaderIESLight"); + NodeShaderTexIES *tex = MEM_cnew<NodeShaderTexIES>("NodeShaderIESLight"); node->storage = tex; } +} // namespace blender::nodes::node_shader_ies_light_cc + /* node type definition */ -void register_node_type_sh_tex_ies(void) +void register_node_type_sh_tex_ies() { + namespace file_ns = blender::nodes::node_shader_ies_light_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE, 0); - node_type_socket_templates(&ntype, sh_node_tex_ies_in, sh_node_tex_ies_out); - node_type_init(&ntype, node_shader_init_tex_ies); + sh_node_type_base(&ntype, SH_NODE_TEX_IES, "IES Texture", NODE_CLASS_TEXTURE); + node_type_socket_templates(&ntype, file_ns::sh_node_tex_ies_in, file_ns::sh_node_tex_ies_out); + node_type_init(&ntype, file_ns::node_shader_init_tex_ies); node_type_storage( &ntype, "NodeShaderTexIES", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/shader/nodes/node_shader_invert.c b/source/blender/nodes/shader/nodes/node_shader_invert.cc index 0d6709a1968..e85985ce444 100644 --- a/source/blender/nodes/shader/nodes/node_shader_invert.c +++ b/source/blender/nodes/shader/nodes/node_shader_invert.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_invert_cc { /* **************** INVERT ******************** */ static bNodeSocketTemplate sh_node_invert_in[] = { @@ -65,14 +67,18 @@ static int gpu_shader_invert(GPUMaterial *mat, return GPU_stack_link(mat, node, "invert", in, out); } -void register_node_type_sh_invert(void) +} // namespace blender::nodes::node_shader_invert_cc + +void register_node_type_sh_invert() { + namespace file_ns = blender::nodes::node_shader_invert_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, sh_node_invert_in, sh_node_invert_out); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_invert); - node_type_gpu(&ntype, gpu_shader_invert); + sh_node_type_base(&ntype, SH_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); + node_type_socket_templates(&ntype, file_ns::sh_node_invert_in, file_ns::sh_node_invert_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_invert); + node_type_gpu(&ntype, file_ns::gpu_shader_invert); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc index c26b40b081c..de262e20644 100644 --- a/source/blender/nodes/shader/nodes/node_shader_layer_weight.c +++ b/source/blender/nodes/shader/nodes/node_shader_layer_weight.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_layer_weight_cc { /* **************** Layer Weight ******************** */ @@ -59,17 +61,20 @@ static void node_shader_exec_layer_weight(void *UNUSED(data), { } +} // namespace blender::nodes::node_shader_layer_weight_cc + /* node type definition */ -void register_node_type_sh_layer_weight(void) +void register_node_type_sh_layer_weight() { + namespace file_ns = blender::nodes::node_shader_layer_weight_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, sh_node_layer_weight_in, sh_node_layer_weight_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_layer_weight); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_layer_weight); + sh_node_type_base(&ntype, SH_NODE_LAYER_WEIGHT, "Layer Weight", NODE_CLASS_INPUT); + node_type_socket_templates( + &ntype, file_ns::sh_node_layer_weight_in, file_ns::sh_node_layer_weight_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_layer_weight); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_layer_weight); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc index 22172221f77..6c2baa01e54 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_falloff.c +++ b/source/blender/nodes/shader/nodes/node_shader_light_falloff.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_light_falloff_cc { /* **************** INPUT ********************* */ @@ -45,17 +47,20 @@ static int node_shader_gpu_light_falloff(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_light_falloff", in, out); } +} // namespace blender::nodes::node_shader_light_falloff_cc + /* node type definition */ -void register_node_type_sh_light_falloff(void) +void register_node_type_sh_light_falloff() { + namespace file_ns = blender::nodes::node_shader_light_falloff_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR, 0); - node_type_socket_templates(&ntype, sh_node_light_falloff_in, sh_node_light_falloff_out); + sh_node_type_base(&ntype, SH_NODE_LIGHT_FALLOFF, "Light Falloff", NODE_CLASS_OP_COLOR); + node_type_socket_templates( + &ntype, file_ns::sh_node_light_falloff_in, file_ns::sh_node_light_falloff_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_light_falloff); + node_type_gpu(&ntype, file_ns::node_shader_gpu_light_falloff); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_light_path.c b/source/blender/nodes/shader/nodes/node_shader_light_path.cc index 45ad2133ee8..9f8e6502ce5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_light_path.c +++ b/source/blender/nodes/shader/nodes/node_shader_light_path.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_light_path_cc { /* **************** OUTPUT ******************** */ @@ -47,16 +49,18 @@ static int node_shader_gpu_light_path(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_light_path", in, out); } +} // namespace blender::nodes::node_shader_light_path_cc + /* node type definition */ -void register_node_type_sh_light_path(void) +void register_node_type_sh_light_path() { + namespace file_ns = blender::nodes::node_shader_light_path_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_light_path_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_light_path); + sh_node_type_base(&ntype, SH_NODE_LIGHT_PATH, "Light Path", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_light_path_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_light_path); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index 615ae276eb4..c4527fd3420 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -23,13 +23,15 @@ #include <algorithm> -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_math_base_safe.h" -NODE_STORAGE_FUNCS(NodeMapRange) +#include "NOD_socket_search_link.hh" + +namespace blender::nodes::node_shader_map_range_cc { -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeMapRange) static void sh_node_map_range_declare(NodeDeclarationBuilder &b) { @@ -50,8 +52,6 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Vector")); }; -} // namespace blender::nodes - static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { const NodeMapRange &storage = node_storage(*node); @@ -80,7 +80,7 @@ static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) { - NodeMapRange *data = (NodeMapRange *)MEM_callocN(sizeof(NodeMapRange), __func__); + NodeMapRange *data = MEM_cnew<NodeMapRange>(__func__); data->clamp = 1; data->data_type = CD_PROP_FLOAT; data->interpolation_type = NODE_MAP_RANGE_LINEAR; @@ -89,6 +89,66 @@ static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } +class SocketSearchOp { + public: + std::string socket_name; + CustomDataType data_type; + int interpolation_type = NODE_MAP_RANGE_LINEAR; + + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("ShaderNodeMapRange"); + node_storage(node).data_type = data_type; + node_storage(node).interpolation_type = interpolation_type; + params.update_and_connect_available_socket(node, socket_name); + } +}; + +static std::optional<CustomDataType> node_type_from_other_socket(const bNodeSocket &socket) +{ + switch (socket.type) { + case SOCK_FLOAT: + case SOCK_BOOLEAN: + case SOCK_INT: + return CD_PROP_FLOAT; + case SOCK_VECTOR: + case SOCK_RGBA: + return CD_PROP_FLOAT3; + default: + return {}; + } +} + +static void node_map_range_gather_link_searches(GatherLinkSearchOpParams ¶ms) +{ + const std::optional<CustomDataType> type = node_type_from_other_socket(params.other_socket()); + if (!type) { + return; + } + + if (params.in_out() == SOCK_IN) { + if (*type == CD_PROP_FLOAT3) { + params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type}, 0); + } + else { + params.add_item(IFACE_("Value"), SocketSearchOp{"Value", *type}, 0); + } + params.add_item(IFACE_("From Min"), SocketSearchOp{"From Min", *type}, -1); + params.add_item(IFACE_("From Max"), SocketSearchOp{"From Max", *type}, -1); + params.add_item(IFACE_("To Min"), SocketSearchOp{"To Min", *type}, -2); + params.add_item(IFACE_("To Max"), SocketSearchOp{"To Max", *type}, -2); + params.add_item(IFACE_("Steps"), SocketSearchOp{"Steps", *type, NODE_MAP_RANGE_STEPPED}, -3); + } + else { + if (*type == CD_PROP_FLOAT3) { + params.add_item(IFACE_("Vector"), SocketSearchOp{"Vector", *type}); + } + else { + params.add_item(IFACE_("Result"), SocketSearchOp{"Result", *type}); + } + } +} + static const char *gpu_shader_get_name(int mode, bool use_vector) { if (use_vector) { @@ -143,8 +203,6 @@ static int gpu_shader_map_range(GPUMaterial *mat, return ret; } -namespace blender::nodes { - static inline float clamp_range(const float value, const float min, const float max) { return (min > max) ? std::clamp(value, max, min) : std::clamp(value, min, max); @@ -582,20 +640,22 @@ static void sh_node_map_range_build_multi_function( } } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_map_range_cc void register_node_type_sh_map_range() { + namespace file_ns = blender::nodes::node_shader_map_range_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_map_range_declare; - node_type_init(&ntype, node_shader_init_map_range); + sh_fn_node_type_base(&ntype, SH_NODE_MAP_RANGE, "Map Range", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_map_range_declare; + node_type_init(&ntype, file_ns::node_shader_init_map_range); node_type_storage( &ntype, "NodeMapRange", node_free_standard_storage, node_copy_standard_storage); - node_type_update(&ntype, node_shader_update_map_range); - node_type_gpu(&ntype, gpu_shader_map_range); - ntype.build_multi_function = blender::nodes::sh_node_map_range_build_multi_function; - + node_type_update(&ntype, file_ns::node_shader_update_map_range); + node_type_gpu(&ntype, file_ns::gpu_shader_map_range); + ntype.build_multi_function = file_ns::sh_node_map_range_build_multi_function; + ntype.gather_link_search_ops = file_ns::node_map_range_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.cc index cabfecdb6ee..758b675f9d6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_mapping_cc { /* **************** MAPPING ******************** */ static bNodeSocketTemplate sh_node_mapping_in[] = { @@ -37,21 +39,29 @@ static bNodeSocketTemplate sh_node_mapping_out[] = { {-1, ""}, }; +static const char *gpu_shader_get_name(int mode) +{ + switch (mode) { + case NODE_MAPPING_TYPE_POINT: + return "mapping_point"; + case NODE_MAPPING_TYPE_TEXTURE: + return "mapping_texture"; + case NODE_MAPPING_TYPE_VECTOR: + return "mapping_vector"; + case NODE_MAPPING_TYPE_NORMAL: + return "mapping_normal"; + } + return nullptr; +} + static int gpu_shader_mapping(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out) { - static const char *names[] = { - [NODE_MAPPING_TYPE_POINT] = "mapping_point", - [NODE_MAPPING_TYPE_TEXTURE] = "mapping_texture", - [NODE_MAPPING_TYPE_VECTOR] = "mapping_vector", - [NODE_MAPPING_TYPE_NORMAL] = "mapping_normal", - }; - - if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) { - return GPU_stack_link(mat, node, names[node->custom1], in, out); + if (gpu_shader_get_name(node->custom1)) { + return GPU_stack_link(mat, node, gpu_shader_get_name(node->custom1), in, out); } return 0; @@ -64,14 +74,18 @@ static void node_shader_update_mapping(bNodeTree *ntree, bNode *node) ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); } -void register_node_type_sh_mapping(void) +} // namespace blender::nodes::node_shader_mapping_cc + +void register_node_type_sh_mapping() { + namespace file_ns = blender::nodes::node_shader_mapping_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_mapping_in, sh_node_mapping_out); - node_type_gpu(&ntype, gpu_shader_mapping); - node_type_update(&ntype, node_shader_update_mapping); + sh_node_type_base(&ntype, SH_NODE_MAPPING, "Mapping", NODE_CLASS_OP_VECTOR); + node_type_socket_templates(&ntype, file_ns::sh_node_mapping_in, file_ns::sh_node_mapping_out); + node_type_gpu(&ntype, file_ns::gpu_shader_mapping); + node_type_update(&ntype, file_ns::node_shader_update_mapping); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index da237be273f..ca30b16f7ff 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -21,14 +21,16 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "NOD_math_functions.hh" #include "NOD_socket_search_link.hh" +#include "RNA_enum_types.h" + /* **************** SCALAR MATH ******************** */ -namespace blender::nodes { +namespace blender::nodes::node_shader_math_cc { static void sh_node_math_declare(NodeDeclarationBuilder &b) { @@ -45,19 +47,41 @@ static void sh_node_math_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; +class SocketSearchOp { + public: + std::string socket_name; + NodeMathOperation mode = NODE_MATH_ADD; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("ShaderNodeMath"); + node.custom1 = mode; + params.update_and_connect_available_socket(node, socket_name); + } +}; + static void sh_node_math_gather_link_searches(GatherLinkSearchOpParams ¶ms) { - /* For now, do something very basic (only exposing "Add", and a single "Value" socket). */ - if (params.node_tree().typeinfo->validate_link( + if (!params.node_tree().typeinfo->validate_link( static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_FLOAT)) { - params.add_item(IFACE_("Value"), [](LinkSearchOpParams ¶ms) { - bNode &node = params.add_node("ShaderNodeMath"); - params.update_and_connect_available_socket(node, "Value"); - }); + return; } -} -} // namespace blender::nodes + const bool is_geometry_node_tree = params.node_tree().type == NTREE_GEOMETRY; + const int weight = ELEM(params.other_socket().type, SOCK_FLOAT, SOCK_BOOLEAN, SOCK_INT) ? 0 : -1; + + for (const EnumPropertyItem *item = rna_enum_node_math_items; item->identifier != nullptr; + item++) { + if (item->name != nullptr && item->identifier[0] != '\0') { + const int gn_weight = + (is_geometry_node_tree && + ELEM(item->value, NODE_MATH_COMPARE, NODE_MATH_GREATER_THAN, NODE_MATH_LESS_THAN)) ? + -1 : + weight; + params.add_item( + IFACE_(item->name), SocketSearchOp{"Value", (NodeMathOperation)item->value}, gn_weight); + } + } +} static const char *gpu_shader_get_name(int mode) { @@ -174,17 +198,21 @@ static void sh_node_math_build_multi_function(blender::nodes::NodeMultiFunctionB } } +} // namespace blender::nodes::node_shader_math_cc + void register_node_type_sh_math() { + namespace file_ns = blender::nodes::node_shader_math_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_math_declare; + sh_fn_node_type_base(&ntype, SH_NODE_MATH, "Math", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_math_declare; ntype.labelfunc = node_math_label; - node_type_gpu(&ntype, gpu_shader_math); + node_type_gpu(&ntype, file_ns::gpu_shader_math); node_type_update(&ntype, node_math_update); - ntype.build_multi_function = sh_node_math_build_multi_function; - ntype.gather_link_search_ops = blender::nodes::sh_node_math_gather_link_searches; + ntype.build_multi_function = file_ns::sh_node_math_build_multi_function; + ntype.gather_link_search_ops = file_ns::sh_node_math_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc index b89e0527eed..680c0be0fe8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_mix_rgb.cc @@ -21,9 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_mix_rgb_cc { static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b) { @@ -34,8 +34,6 @@ static void sh_node_mix_rgb_declare(NodeDeclarationBuilder &b) b.add_output<decl::Color>(N_("Color")); }; -} // namespace blender::nodes - static void node_shader_exec_mix_rgb(void *UNUSED(data), int UNUSED(thread), bNode *node, @@ -183,16 +181,20 @@ static void sh_node_mix_rgb_build_multi_function(blender::nodes::NodeMultiFuncti builder.construct_and_set_matching_fn<MixRGBFunction>(clamp, mix_type); } +} // namespace blender::nodes::node_shader_mix_rgb_cc + void register_node_type_sh_mix_rgb() { + namespace file_ns = blender::nodes::node_shader_mix_rgb_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); - ntype.declare = blender::nodes::sh_node_mix_rgb_declare; + sh_fn_node_type_base(&ntype, SH_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR); + ntype.declare = file_ns::sh_node_mix_rgb_declare; ntype.labelfunc = node_blend_label; - node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_mix_rgb); - node_type_gpu(&ntype, gpu_shader_mix_rgb); - ntype.build_multi_function = sh_node_mix_rgb_build_multi_function; + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_mix_rgb); + node_type_gpu(&ntype, file_ns::gpu_shader_mix_rgb); + ntype.build_multi_function = file_ns::sh_node_mix_rgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc index 33cbf34543c..d18ae46fc47 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mix_shader.c +++ b/source/blender/nodes/shader/nodes/node_shader_mix_shader.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_mix_shader_cc { /* **************** OUTPUT ******************** */ @@ -42,16 +44,19 @@ static int node_shader_gpu_mix_shader(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_mix_shader", in, out); } +} // namespace blender::nodes::node_shader_mix_shader_cc + /* node type definition */ -void register_node_type_sh_mix_shader(void) +void register_node_type_sh_mix_shader() { + namespace file_ns = blender::nodes::node_shader_mix_shader_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_mix_shader_in, sh_node_mix_shader_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_mix_shader); + sh_node_type_base(&ntype, SH_NODE_MIX_SHADER, "Mix Shader", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_mix_shader_in, file_ns::sh_node_mix_shader_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_mix_shader); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal.c b/source/blender/nodes/shader/nodes/node_shader_normal.cc index 83d5abcba67..9e6085e978a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_normal_cc { /* **************** NORMAL ******************** */ static bNodeSocketTemplate sh_node_normal_in[] = { @@ -64,14 +66,18 @@ static int gpu_shader_normal(GPUMaterial *mat, return GPU_stack_link(mat, node, "normal_new_shading", in, out, vec); } -void register_node_type_sh_normal(void) +} // namespace blender::nodes::node_shader_normal_cc + +void register_node_type_sh_normal() { + namespace file_ns = blender::nodes::node_shader_normal_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_normal_in, sh_node_normal_out); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal); - node_type_gpu(&ntype, gpu_shader_normal); + sh_node_type_base(&ntype, SH_NODE_NORMAL, "Normal", NODE_CLASS_OP_VECTOR); + node_type_socket_templates(&ntype, file_ns::sh_node_normal_in, file_ns::sh_node_normal_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_normal); + node_type_gpu(&ntype, file_ns::gpu_shader_normal); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc index 493acb06963..0c9932e3190 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_normal_map_cc { /* **************** OUTPUT ******************** */ @@ -34,7 +36,7 @@ static bNodeSocketTemplate sh_node_normal_map_out[] = { static void node_shader_init_normal_map(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderNormalMap *attr = MEM_callocN(sizeof(NodeShaderNormalMap), "NodeShaderNormalMap"); + NodeShaderNormalMap *attr = MEM_cnew<NodeShaderNormalMap>("NodeShaderNormalMap"); node->storage = attr; } @@ -53,15 +55,16 @@ static int gpu_shader_normal_map(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - NodeShaderNormalMap *nm = node->storage; + NodeShaderNormalMap *nm = static_cast<NodeShaderNormalMap *>(node->storage); GPUNodeLink *strength; if (in[0].link) { strength = in[0].link; } else if (node->original) { - bNodeSocket *socket = BLI_findlink(&node->original->inputs, 0); - bNodeSocketValueFloat *socket_data = socket->default_value; + bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 0)); + bNodeSocketValueFloat *socket_data = static_cast<bNodeSocketValueFloat *>( + socket->default_value); strength = GPU_uniform(&socket_data->value); } else { @@ -73,8 +76,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat, newnormal = in[1].link; } else if (node->original) { - bNodeSocket *socket = BLI_findlink(&node->original->inputs, 1); - bNodeSocketValueRGBA *socket_data = socket->default_value; + bNodeSocket *socket = static_cast<bNodeSocket *>(BLI_findlink(&node->original->inputs, 1)); + bNodeSocketValueRGBA *socket_data = static_cast<bNodeSocketValueRGBA *>(socket->default_value); newnormal = GPU_uniform(socket_data->value); } else { @@ -114,19 +117,24 @@ static int gpu_shader_normal_map(GPUMaterial *mat, return true; } +} // namespace blender::nodes::node_shader_normal_map_cc + /* node type definition */ -void register_node_type_sh_normal_map(void) +void register_node_type_sh_normal_map() { + namespace file_ns = blender::nodes::node_shader_normal_map_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_normal_map_in, sh_node_normal_map_out); + sh_node_type_base(&ntype, SH_NODE_NORMAL_MAP, "Normal Map", NODE_CLASS_OP_VECTOR); + node_type_socket_templates( + &ntype, file_ns::sh_node_normal_map_in, file_ns::sh_node_normal_map_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_normal_map); + node_type_init(&ntype, file_ns::node_shader_init_normal_map); node_type_storage( &ntype, "NodeShaderNormalMap", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, gpu_shader_normal_map); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_normal_map); + node_type_gpu(&ntype, file_ns::gpu_shader_normal_map); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_normal_map); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_object_info.c b/source/blender/nodes/shader/nodes/node_shader_object_info.cc index 47040954c9e..bbc4bd0015c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_object_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_object_info.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_object_info_cc { /* **************** OUTPUT ******************** */ @@ -49,13 +51,17 @@ static int node_shader_gpu_object_info(GPUMaterial *mat, GPU_constant(&index)); } -void register_node_type_sh_object_info(void) +} // namespace blender::nodes::node_shader_object_info_cc + +void register_node_type_sh_object_info() { + namespace file_ns = blender::nodes::node_shader_object_info_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_object_info_out); - node_type_gpu(&ntype, node_shader_gpu_object_info); + sh_node_type_base(&ntype, SH_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_object_info_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_object_info); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc index 32765b459ca..200ccef7404 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.cc @@ -17,10 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_hash.h" +namespace blender::nodes::node_shader_output_aov_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_output_aov_in[] = { @@ -31,7 +33,7 @@ static bNodeSocketTemplate sh_node_output_aov_in[] = { static void node_shader_init_output_aov(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderOutputAOV *aov = MEM_callocN(sizeof(NodeShaderOutputAOV), "NodeShaderOutputAOV"); + NodeShaderOutputAOV *aov = MEM_cnew<NodeShaderOutputAOV>("NodeShaderOutputAOV"); node->storage = aov; } @@ -52,17 +54,21 @@ static int node_shader_gpu_output_aov(GPUMaterial *mat, return true; } +} // namespace blender::nodes::node_shader_output_aov_cc + /* node type definition */ -void register_node_type_sh_output_aov(void) +void register_node_type_sh_output_aov() { + namespace file_ns = blender::nodes::node_shader_output_aov_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT, 0); - node_type_socket_templates(&ntype, sh_node_output_aov_in, NULL); - node_type_init(&ntype, node_shader_init_output_aov); + sh_node_type_base(&ntype, SH_NODE_OUTPUT_AOV, "AOV Output", NODE_CLASS_OUTPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_output_aov_in, nullptr); + node_type_init(&ntype, file_ns::node_shader_init_output_aov); node_type_storage( &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_output_aov); + node_type_gpu(&ntype, file_ns::node_shader_gpu_output_aov); ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.cc index 6c4837f3c6f..88006563db2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_output_light_cc { /* **************** OUTPUT ******************** */ @@ -26,15 +28,17 @@ static bNodeSocketTemplate sh_node_output_light_in[] = { {-1, ""}, }; +} // namespace blender::nodes::node_shader_output_light_cc + /* node type definition */ -void register_node_type_sh_output_light(void) +void register_node_type_sh_output_light() { + namespace file_ns = blender::nodes::node_shader_output_light_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT, 0); - node_type_socket_templates(&ntype, sh_node_output_light_in, NULL); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); + sh_node_type_base(&ntype, SH_NODE_OUTPUT_LIGHT, "Light Output", NODE_CLASS_OUTPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_output_light_in, nullptr); ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc index 07e253383e2..ee80962d35a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_output_linestyle_cc { /* **************** OUTPUT ******************** */ @@ -29,14 +31,17 @@ static bNodeSocketTemplate sh_node_output_linestyle_in[] = { {-1, ""}, }; +} // namespace blender::nodes::node_shader_output_linestyle_cc + /* node type definition */ -void register_node_type_sh_output_linestyle(void) +void register_node_type_sh_output_linestyle() { + namespace file_ns = blender::nodes::node_shader_output_linestyle_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT, 0); - node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL); - node_type_init(&ntype, NULL); + sh_node_type_base(&ntype, SH_NODE_OUTPUT_LINESTYLE, "Line Style Output", NODE_CLASS_OUTPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_output_linestyle_in, nullptr); ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.cc index 41932cca6a3..c8bb39ffa04 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.cc @@ -17,10 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BKE_scene.h" +namespace blender::nodes::node_shader_output_material_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_output_material_in[] = { @@ -73,16 +75,18 @@ static int node_shader_gpu_output_material(GPUMaterial *mat, return true; } +} // namespace blender::nodes::node_shader_output_material_cc + /* node type definition */ -void register_node_type_sh_output_material(void) +void register_node_type_sh_output_material() { + namespace file_ns = blender::nodes::node_shader_output_material_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT, 0); - node_type_socket_templates(&ntype, sh_node_output_material_in, NULL); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_output_material); + sh_node_type_base(&ntype, SH_NODE_OUTPUT_MATERIAL, "Material Output", NODE_CLASS_OUTPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_output_material_in, nullptr); + node_type_gpu(&ntype, file_ns::node_shader_gpu_output_material); ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.cc index 09eca7f712e..b2382b08d9a 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_output_world_cc { /* **************** OUTPUT ******************** */ @@ -41,16 +43,18 @@ static int node_shader_gpu_output_world(GPUMaterial *mat, return true; } +} // namespace blender::nodes::node_shader_output_world_cc + /* node type definition */ -void register_node_type_sh_output_world(void) +void register_node_type_sh_output_world() { + namespace file_ns = blender::nodes::node_shader_output_world_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT, 0); - node_type_socket_templates(&ntype, sh_node_output_world_in, NULL); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_output_world); + sh_node_type_base(&ntype, SH_NODE_OUTPUT_WORLD, "World Output", NODE_CLASS_OUTPUT); + node_type_socket_templates(&ntype, file_ns::sh_node_output_world_in, nullptr); + node_type_gpu(&ntype, file_ns::node_shader_gpu_output_world); ntype.no_muting = true; diff --git a/source/blender/nodes/shader/nodes/node_shader_particle_info.c b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc index c6eabc3b2cb..444738f81b3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_particle_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_particle_info.cc @@ -17,9 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + #include "RE_texture.h" +namespace blender::nodes::node_shader_particle_info_cc { + static bNodeSocketTemplate outputs[] = { {SOCK_FLOAT, "Index"}, {SOCK_FLOAT, "Random"}, @@ -61,15 +64,19 @@ static int gpu_shader_particle_info(GPUMaterial *mat, GPU_builtin(GPU_PARTICLE_ANG_VELOCITY)); } +} // namespace blender::nodes::node_shader_particle_info_cc + /* node type definition */ -void register_node_type_sh_particle_info(void) +void register_node_type_sh_particle_info() { + namespace file_ns = blender::nodes::node_shader_particle_info_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, outputs); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_particle_info); - node_type_gpu(&ntype, gpu_shader_particle_info); + sh_node_type_base(&ntype, SH_NODE_PARTICLE_INFO, "Particle Info", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::outputs); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_particle_info); + node_type_gpu(&ntype, file_ns::gpu_shader_particle_info); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb.c b/source/blender/nodes/shader/nodes/node_shader_rgb.cc index 0bdef9a2a17..f3b83b72232 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_rgb.cc @@ -21,13 +21,14 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -/* **************** RGB ******************** */ -static bNodeSocketTemplate sh_node_rgb_out[] = { - {SOCK_RGBA, N_("Color"), 0.5f, 0.5f, 0.5f, 1.0f}, - {-1, ""}, -}; +namespace blender::nodes::node_shader_rgb_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_output<decl::Color>(N_("Color")).default_value({0.5f, 0.5f, 0.5f, 1.0f}); +} static int gpu_shader_rgb(GPUMaterial *mat, bNode *node, @@ -39,13 +40,17 @@ static int gpu_shader_rgb(GPUMaterial *mat, return GPU_stack_link(mat, node, "set_rgba", in, out, link); } -void register_node_type_sh_rgb(void) +} // namespace blender::nodes::node_shader_rgb_cc + +void register_node_type_sh_rgb() { + namespace file_ns = blender::nodes::node_shader_rgb_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_rgb_out); - node_type_gpu(&ntype, gpu_shader_rgb); + sh_node_type_base(&ntype, SH_NODE_RGB, "RGB", NODE_CLASS_INPUT); + ntype.declare = file_ns::node_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_rgb); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc index e3808985c0e..8efdae091a7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc +++ b/source/blender/nodes/shader/nodes/node_shader_rgb_to_bw.cc @@ -23,172 +23,9 @@ #include "IMB_colormanagement.h" -#include "DNA_texture_types.h" +#include "node_shader_util.hh" -#include "BLI_color.hh" - -#include "node_shader_util.h" - -namespace blender::nodes { - -static void sh_node_valtorgb_declare(NodeDeclarationBuilder &b) -{ - b.is_function_node(); - b.add_input<decl::Float>(N_("Fac")).default_value(0.5f).min(0.0f).max(1.0f).subtype(PROP_FACTOR); - b.add_output<decl::Color>(N_("Color")); - b.add_output<decl::Float>(N_("Alpha")); -}; - -} // namespace blender::nodes - -static void node_shader_exec_valtorgb(void *UNUSED(data), - int UNUSED(thread), - bNode *node, - bNodeExecData *UNUSED(execdata), - bNodeStack **in, - bNodeStack **out) -{ - /* stack order in: fac */ - /* stack order out: col, alpha */ - - if (node->storage) { - float fac; - nodestack_get_vec(&fac, SOCK_FLOAT, in[0]); - - BKE_colorband_evaluate((ColorBand *)node->storage, fac, out[0]->vec); - out[1]->vec[0] = out[0]->vec[3]; - } -} - -static void node_shader_init_valtorgb(bNodeTree *UNUSED(ntree), bNode *node) -{ - node->storage = BKE_colorband_add(true); -} - -static int gpu_shader_valtorgb(GPUMaterial *mat, - bNode *node, - bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, - GPUNodeStack *out) -{ - struct ColorBand *coba = (ColorBand *)node->storage; - float *array, layer; - int size; - - /* Common / easy case optimization. */ - if ((coba->tot <= 2) && (coba->color_mode == COLBAND_BLEND_RGB)) { - float mul_bias[2]; - switch (coba->ipotype) { - case COLBAND_INTERP_LINEAR: - mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos); - mul_bias[1] = -mul_bias[0] * coba->data[0].pos; - return GPU_stack_link(mat, - node, - "valtorgb_opti_linear", - in, - out, - GPU_uniform(mul_bias), - GPU_uniform(&coba->data[0].r), - GPU_uniform(&coba->data[1].r)); - case COLBAND_INTERP_CONSTANT: - mul_bias[1] = max_ff(coba->data[0].pos, coba->data[1].pos); - return GPU_stack_link(mat, - node, - "valtorgb_opti_constant", - in, - out, - GPU_uniform(&mul_bias[1]), - GPU_uniform(&coba->data[0].r), - GPU_uniform(&coba->data[1].r)); - case COLBAND_INTERP_EASE: - mul_bias[0] = 1.0f / (coba->data[1].pos - coba->data[0].pos); - mul_bias[1] = -mul_bias[0] * coba->data[0].pos; - return GPU_stack_link(mat, - node, - "valtorgb_opti_ease", - in, - out, - GPU_uniform(mul_bias), - GPU_uniform(&coba->data[0].r), - GPU_uniform(&coba->data[1].r)); - default: - break; - } - } - - BKE_colorband_evaluate_table_rgba(coba, &array, &size); - GPUNodeLink *tex = GPU_color_band(mat, size, array, &layer); - - if (coba->ipotype == COLBAND_INTERP_CONSTANT) { - return GPU_stack_link(mat, node, "valtorgb_nearest", in, out, tex, GPU_constant(&layer)); - } - - return GPU_stack_link(mat, node, "valtorgb", in, out, tex, GPU_constant(&layer)); -} - -class ColorBandFunction : public blender::fn::MultiFunction { - private: - const ColorBand &color_band_; - - public: - ColorBandFunction(const ColorBand &color_band) : color_band_(color_band) - { - static blender::fn::MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static blender::fn::MFSignature create_signature() - { - blender::fn::MFSignatureBuilder signature{"Color Band"}; - signature.single_input<float>("Value"); - signature.single_output<blender::ColorGeometry4f>("Color"); - signature.single_output<float>("Alpha"); - return signature.build(); - } - - void call(blender::IndexMask mask, - blender::fn::MFParams params, - blender::fn::MFContext UNUSED(context)) const override - { - const blender::VArray<float> &values = params.readonly_single_input<float>(0, "Value"); - blender::MutableSpan<blender::ColorGeometry4f> colors = - params.uninitialized_single_output<blender::ColorGeometry4f>(1, "Color"); - blender::MutableSpan<float> alphas = params.uninitialized_single_output<float>(2, "Alpha"); - - for (int64_t i : mask) { - blender::ColorGeometry4f color; - BKE_colorband_evaluate(&color_band_, values[i], color); - colors[i] = color; - alphas[i] = color.a; - } - } -}; - -static void sh_node_valtorgb_build_multi_function( - blender::nodes::NodeMultiFunctionBuilder &builder) -{ - bNode &bnode = builder.node(); - const ColorBand *color_band = (const ColorBand *)bnode.storage; - builder.construct_and_set_matching_fn<ColorBandFunction>(*color_band); -} - -void register_node_type_sh_valtorgb() -{ - static bNodeType ntype; - - sh_fn_node_type_base(&ntype, SH_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_valtorgb_declare; - node_type_init(&ntype, node_shader_init_valtorgb); - node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_storage(&ntype, "ColorBand", node_free_standard_storage, node_copy_standard_storage); - node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_valtorgb); - node_type_gpu(&ntype, gpu_shader_valtorgb); - ntype.build_multi_function = sh_node_valtorgb_build_multi_function; - - nodeRegisterType(&ntype); -} - -namespace blender::nodes { +namespace blender::nodes::node_shader_rgb_to_bw_cc { static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b) { @@ -196,8 +33,6 @@ static void sh_node_rgbtobw_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Val")); }; -} // namespace blender::nodes - static void node_shader_exec_rgbtobw(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), @@ -222,14 +57,18 @@ static int gpu_shader_rgbtobw(GPUMaterial *mat, return GPU_stack_link(mat, node, "rgbtobw", in, out); } +} // namespace blender::nodes::node_shader_rgb_to_bw_cc + void register_node_type_sh_rgbtobw() { + namespace file_ns = blender::nodes::node_shader_rgb_to_bw_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_rgbtobw_declare; - node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_rgbtobw); - node_type_gpu(&ntype, gpu_shader_rgbtobw); + sh_node_type_base(&ntype, SH_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_rgbtobw_declare; + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_rgbtobw); + node_type_gpu(&ntype, file_ns::gpu_shader_rgbtobw); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_script.c b/source/blender/nodes/shader/nodes/node_shader_script.cc index 42ab272de0e..6c6578cf6c1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_script.c +++ b/source/blender/nodes/shader/nodes/node_shader_script.cc @@ -21,19 +21,21 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_script_cc { /* **************** Script ******************** */ static void init(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderScript *nss = MEM_callocN(sizeof(NodeShaderScript), "shader script node"); + NodeShaderScript *nss = MEM_cnew<NodeShaderScript>("shader script node"); node->storage = nss; } static void node_free_script(bNode *node) { - NodeShaderScript *nss = node->storage; + NodeShaderScript *nss = static_cast<NodeShaderScript *>(node->storage); if (nss) { if (nss->bytecode) { @@ -48,23 +50,28 @@ static void node_copy_script(bNodeTree *UNUSED(dest_ntree), bNode *dest_node, const bNode *src_node) { - NodeShaderScript *src_nss = src_node->storage; - NodeShaderScript *dest_nss = MEM_dupallocN(src_nss); + NodeShaderScript *src_nss = static_cast<NodeShaderScript *>(src_node->storage); + NodeShaderScript *dest_nss = static_cast<NodeShaderScript *>(MEM_dupallocN(src_nss)); if (src_nss->bytecode) { - dest_nss->bytecode = MEM_dupallocN(src_nss->bytecode); + dest_nss->bytecode = static_cast<char *>(MEM_dupallocN(src_nss->bytecode)); } dest_node->storage = dest_nss; } -void register_node_type_sh_script(void) +} // namespace blender::nodes::node_shader_script_cc + +void register_node_type_sh_script() { + namespace file_ns = blender::nodes::node_shader_script_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT, 0); - node_type_init(&ntype, init); - node_type_storage(&ntype, "NodeShaderScript", node_free_script, node_copy_script); + sh_node_type_base(&ntype, SH_NODE_SCRIPT, "Script", NODE_CLASS_SCRIPT); + node_type_init(&ntype, file_ns::init); + node_type_storage( + &ntype, "NodeShaderScript", file_ns::node_free_script, file_ns::node_copy_script); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc index dfecb830b35..901903a114c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.c +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_hsv.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_sepcomb_hsv_cc { /* **************** SEPARATE HSV ******************** */ static bNodeSocketTemplate sh_node_sephsv_in[] = { @@ -57,18 +59,24 @@ static int gpu_shader_sephsv(GPUMaterial *mat, return GPU_stack_link(mat, node, "separate_hsv", in, out); } -void register_node_type_sh_sephsv(void) +} // namespace blender::nodes::node_shader_sepcomb_hsv_cc + +void register_node_type_sh_sephsv() { + namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER, 0); - node_type_socket_templates(&ntype, sh_node_sephsv_in, sh_node_sephsv_out); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_sephsv); - node_type_gpu(&ntype, gpu_shader_sephsv); + sh_node_type_base(&ntype, SH_NODE_SEPHSV, "Separate HSV", NODE_CLASS_CONVERTER); + node_type_socket_templates(&ntype, file_ns::sh_node_sephsv_in, file_ns::sh_node_sephsv_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_sephsv); + node_type_gpu(&ntype, file_ns::gpu_shader_sephsv); nodeRegisterType(&ntype); } +namespace blender::nodes::node_shader_sepcomb_hsv_cc { + /* **************** COMBINE HSV ******************** */ static bNodeSocketTemplate sh_node_combhsv_in[] = { {SOCK_FLOAT, N_("H"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED}, @@ -105,14 +113,18 @@ static int gpu_shader_combhsv(GPUMaterial *mat, return GPU_stack_link(mat, node, "combine_hsv", in, out); } -void register_node_type_sh_combhsv(void) +} // namespace blender::nodes::node_shader_sepcomb_hsv_cc + +void register_node_type_sh_combhsv() { + namespace file_ns = blender::nodes::node_shader_sepcomb_hsv_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER, 0); - node_type_socket_templates(&ntype, sh_node_combhsv_in, sh_node_combhsv_out); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_combhsv); - node_type_gpu(&ntype, gpu_shader_combhsv); + sh_node_type_base(&ntype, SH_NODE_COMBHSV, "Combine HSV", NODE_CLASS_CONVERTER); + node_type_socket_templates(&ntype, file_ns::sh_node_combhsv_in, file_ns::sh_node_combhsv_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_combhsv); + node_type_gpu(&ntype, file_ns::gpu_shader_combhsv); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc index 4984a530d8b..71ba2561bc7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_rgb.cc @@ -21,9 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_sepcomb_rgb_cc { static void sh_node_seprgb_declare(NodeDeclarationBuilder &b) { @@ -34,8 +34,6 @@ static void sh_node_seprgb_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("B")); }; -} // namespace blender::nodes - static void node_shader_exec_seprgb(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), @@ -103,20 +101,24 @@ static void sh_node_seprgb_build_multi_function(blender::nodes::NodeMultiFunctio builder.set_matching_fn(fn); } +} // namespace blender::nodes::node_shader_sepcomb_rgb_cc + void register_node_type_sh_seprgb() { + namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_seprgb_declare; - node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_seprgb); - node_type_gpu(&ntype, gpu_shader_seprgb); - ntype.build_multi_function = sh_node_seprgb_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_SEPRGB, "Separate RGB", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_seprgb_declare; + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_seprgb); + node_type_gpu(&ntype, file_ns::gpu_shader_seprgb); + ntype.build_multi_function = file_ns::sh_node_seprgb_build_multi_function; nodeRegisterType(&ntype); } -namespace blender::nodes { +namespace blender::nodes::node_shader_sepcomb_rgb_cc { static void sh_node_combrgb_declare(NodeDeclarationBuilder &b) { @@ -127,8 +129,6 @@ static void sh_node_combrgb_declare(NodeDeclarationBuilder &b) b.add_output<decl::Color>(N_("Image")); }; -} // namespace blender::nodes - static void node_shader_exec_combrgb(void *UNUSED(data), int UNUSED(thread), bNode *UNUSED(node), @@ -163,15 +163,19 @@ static void sh_node_combrgb_build_multi_function(blender::nodes::NodeMultiFuncti builder.set_matching_fn(fn); } +} // namespace blender::nodes::node_shader_sepcomb_rgb_cc + void register_node_type_sh_combrgb() { + namespace file_ns = blender::nodes::node_shader_sepcomb_rgb_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_combrgb_declare; - node_type_exec(&ntype, nullptr, nullptr, node_shader_exec_combrgb); - node_type_gpu(&ntype, gpu_shader_combrgb); - ntype.build_multi_function = sh_node_combrgb_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_COMBRGB, "Combine RGB", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_combrgb_declare; + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_combrgb); + node_type_gpu(&ntype, file_ns::gpu_shader_combrgb); + ntype.build_multi_function = file_ns::sh_node_combrgb_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc index a414630829e..57eef716e88 100644 --- a/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc +++ b/source/blender/nodes/shader/nodes/node_shader_sepcomb_xyz.cc @@ -21,9 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_sepcomb_xyz_cc { static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b) { @@ -34,8 +34,6 @@ static void sh_node_sepxyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Z")); }; -} // namespace blender::nodes - static int gpu_shader_sepxyz(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -88,19 +86,23 @@ static void sh_node_sepxyz_build_multi_function(blender::nodes::NodeMultiFunctio builder.set_matching_fn(separate_fn); } +} // namespace blender::nodes::node_shader_sepcomb_xyz_cc + void register_node_type_sh_sepxyz() { + namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_sepxyz_declare; - node_type_gpu(&ntype, gpu_shader_sepxyz); - ntype.build_multi_function = sh_node_sepxyz_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_SEPXYZ, "Separate XYZ", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_sepxyz_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_sepxyz); + ntype.build_multi_function = file_ns::sh_node_sepxyz_build_multi_function; nodeRegisterType(&ntype); } -namespace blender::nodes { +namespace blender::nodes::node_shader_sepcomb_xyz_cc { static void sh_node_combxyz_declare(NodeDeclarationBuilder &b) { @@ -111,8 +113,6 @@ static void sh_node_combxyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Vector")); }; -} // namespace blender::nodes - static int gpu_shader_combxyz(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -129,14 +129,18 @@ static void sh_node_combxyz_build_multi_function(blender::nodes::NodeMultiFuncti builder.set_matching_fn(fn); } +} // namespace blender::nodes::node_shader_sepcomb_xyz_cc + void register_node_type_sh_combxyz() { + namespace file_ns = blender::nodes::node_shader_sepcomb_xyz_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::sh_node_combxyz_declare; - node_type_gpu(&ntype, gpu_shader_combxyz); - ntype.build_multi_function = sh_node_combxyz_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_COMBXYZ, "Combine XYZ", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::sh_node_combxyz_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_combxyz); + ntype.build_multi_function = file_ns::sh_node_combxyz_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc index 25c30aa4081..f5e3787ca7c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.c +++ b/source/blender/nodes/shader/nodes/node_shader_shader_to_rgb.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_shader_to_rgb_cc { /* **************** OUTPUT ******************** */ @@ -45,16 +47,19 @@ static int node_shader_gpu_shadertorgb(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_shader_to_rgba", in, out); } +} // namespace blender::nodes::node_shader_shader_to_rgb_cc + /* node type definition */ -void register_node_type_sh_shadertorgb(void) +void register_node_type_sh_shadertorgb() { + namespace file_ns = blender::nodes::node_shader_shader_to_rgb_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER, 0); - node_type_socket_templates(&ntype, sh_node_shadertorgb_in, sh_node_shadertorgb_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_shadertorgb); + sh_node_type_base(&ntype, SH_NODE_SHADERTORGB, "Shader to RGB", NODE_CLASS_CONVERTER); + node_type_socket_templates( + &ntype, file_ns::sh_node_shadertorgb_in, file_ns::sh_node_shadertorgb_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_shadertorgb); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_squeeze.c b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc index ca7bdf41df9..f41b692ff96 100644 --- a/source/blender/nodes/shader/nodes/node_shader_squeeze.c +++ b/source/blender/nodes/shader/nodes/node_shader_squeeze.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_squeeze_cc { /* **************** VALUE SQUEEZE ******************** */ static bNodeSocketTemplate sh_node_squeeze_in[] = { @@ -57,15 +59,18 @@ static int gpu_shader_squeeze(GPUMaterial *mat, return GPU_stack_link(mat, node, "squeeze", in, out); } -void register_node_type_sh_squeeze(void) +} // namespace blender::nodes::node_shader_squeeze_cc + +void register_node_type_sh_squeeze() { + namespace file_ns = blender::nodes::node_shader_squeeze_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER, 0); - node_type_socket_templates(&ntype, sh_node_squeeze_in, sh_node_squeeze_out); - node_type_storage(&ntype, "", NULL, NULL); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_squeeze); - node_type_gpu(&ntype, gpu_shader_squeeze); + sh_node_type_base(&ntype, SH_NODE_SQUEEZE, "Squeeze Value", NODE_CLASS_CONVERTER); + node_type_socket_templates(&ntype, file_ns::sh_node_squeeze_in, file_ns::sh_node_squeeze_out); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_squeeze); + node_type_gpu(&ntype, file_ns::gpu_shader_squeeze); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc index 85a4a6aa425..a5820aef194 100644 --- a/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.c +++ b/source/blender/nodes/shader/nodes/node_shader_subsurface_scattering.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_subsurface_scattering_cc { /* **************** OUTPUT ******************** */ @@ -53,14 +55,14 @@ static int node_shader_gpu_subsurface_scattering(GPUMaterial *mat, } if (node->sss_id > 0) { - bNodeSocket *socket = BLI_findlink(&node->original->inputs, 2); - bNodeSocketValueRGBA *socket_data = socket->default_value; + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->original->inputs, 2); + bNodeSocketValueRGBA *socket_data = (bNodeSocketValueRGBA *)socket->default_value; /* For some reason it seems that the socket value is in ARGB format. */ GPU_material_sss_profile_create(mat, &socket_data->value[1]); /* sss_id is 0 only the node is not connected to any output. * In this case flagging the material would trigger a bug (see T68736). */ - GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS); + GPU_material_flag_set(mat, (eGPUMatFlag)(GPU_MATFLAG_DIFFUSE | GPU_MATFLAG_SSS)); } return GPU_stack_link( @@ -71,27 +73,31 @@ static void node_shader_update_subsurface_scattering(bNodeTree *ntree, bNode *no { const int sss_method = node->custom1; - for (bNodeSocket *sock = node->inputs.first; sock; sock = sock->next) { + LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (STR_ELEM(sock->name, "IOR", "Anisotropy")) { nodeSetSocketAvailability(ntree, sock, sss_method != SHD_SUBSURFACE_BURLEY); } } } +} // namespace blender::nodes::node_shader_subsurface_scattering_cc + /* node type definition */ -void register_node_type_sh_subsurface_scattering(void) +void register_node_type_sh_subsurface_scattering() { + namespace file_ns = blender::nodes::node_shader_subsurface_scattering_cc; + static bNodeType ntype; sh_node_type_base( - &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER, 0); - node_type_socket_templates( - &ntype, sh_node_subsurface_scattering_in, sh_node_subsurface_scattering_out); + &ntype, SH_NODE_SUBSURFACE_SCATTERING, "Subsurface Scattering", NODE_CLASS_SHADER); + node_type_socket_templates(&ntype, + file_ns::sh_node_subsurface_scattering_in, + file_ns::sh_node_subsurface_scattering_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_subsurface_scattering); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_subsurface_scattering); - node_type_update(&ntype, node_shader_update_subsurface_scattering); + node_type_init(&ntype, file_ns::node_shader_init_subsurface_scattering); + node_type_gpu(&ntype, file_ns::node_shader_gpu_subsurface_scattering); + node_type_update(&ntype, file_ns::node_shader_update_subsurface_scattering); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tangent.c b/source/blender/nodes/shader/nodes/node_shader_tangent.cc index 2c12bf9bc01..9b1c4244604 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tangent.c +++ b/source/blender/nodes/shader/nodes/node_shader_tangent.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_tangent_cc { /* **************** OUTPUT ******************** */ @@ -28,7 +30,7 @@ static bNodeSocketTemplate sh_node_tangent_out[] = { static void node_shader_init_tangent(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderTangent *attr = MEM_callocN(sizeof(NodeShaderTangent), "NodeShaderTangent"); + NodeShaderTangent *attr = MEM_cnew<NodeShaderTangent>("NodeShaderTangent"); attr->axis = SHD_TANGENT_AXIS_Z; node->storage = attr; } @@ -39,7 +41,7 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - NodeShaderTangent *attr = node->storage; + NodeShaderTangent *attr = static_cast<NodeShaderTangent *>(node->storage); if (attr->direction_type == SHD_TANGENT_UVMAP) { return GPU_stack_link( @@ -68,16 +70,20 @@ static int node_shader_gpu_tangent(GPUMaterial *mat, GPU_builtin(GPU_OBJECT_MATRIX)); } +} // namespace blender::nodes::node_shader_tangent_cc + /* node type definition */ -void register_node_type_sh_tangent(void) +void register_node_type_sh_tangent() { + namespace file_ns = blender::nodes::node_shader_tangent_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_tangent_out); + sh_node_type_base(&ntype, SH_NODE_TANGENT, "Tangent", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_tangent_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_tangent); - node_type_gpu(&ntype, node_shader_gpu_tangent); + node_type_init(&ntype, file_ns::node_shader_init_tangent); + node_type_gpu(&ntype, file_ns::node_shader_gpu_tangent); node_type_storage( &ntype, "NodeShaderTangent", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc index 7925c96db3d..6a4a131a315 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_brick.cc @@ -17,12 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_float2.hh" #include "BLI_float4.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_brick_cc { static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b) { @@ -57,11 +57,9 @@ static void sh_node_tex_brick_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")); }; -} // namespace blender::nodes - static void node_shader_init_tex_brick(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexBrick *tex = (NodeTexBrick *)MEM_callocN(sizeof(NodeTexBrick), "NodeTexBrick"); + NodeTexBrick *tex = MEM_cnew<NodeTexBrick>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); @@ -101,8 +99,6 @@ static int node_shader_gpu_tex_brick(GPUMaterial *mat, GPU_constant(&squash_freq)); } -namespace blender::nodes { - class BrickFunction : public fn::MultiFunction { private: const float offset_; @@ -266,20 +262,22 @@ static void sh_node_brick_build_multi_function(blender::nodes::NodeMultiFunction tex->offset, tex->offset_freq, tex->squash, tex->squash_freq); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_brick_cc void register_node_type_sh_tex_brick() { + namespace file_ns = blender::nodes::node_shader_tex_brick_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_brick_declare; + sh_fn_node_type_base(&ntype, SH_NODE_TEX_BRICK, "Brick Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_brick_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_tex_brick); + node_type_init(&ntype, file_ns::node_shader_init_tex_brick); node_type_storage( &ntype, "NodeTexBrick", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_brick); - ntype.build_multi_function = blender::nodes::sh_node_brick_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_brick); + ntype.build_multi_function = file_ns::sh_node_brick_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc index 6d2d199aec8..f22af9f4963 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_checker.cc @@ -17,9 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_checker_cc { static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b) { @@ -36,11 +36,9 @@ static void sh_node_tex_checker_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")); }; -} // namespace blender::nodes - static void node_shader_init_tex_checker(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexChecker *tex = (NodeTexChecker *)MEM_callocN(sizeof(NodeTexChecker), "NodeTexChecker"); + NodeTexChecker *tex = MEM_cnew<NodeTexChecker>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); @@ -59,8 +57,6 @@ static int node_shader_gpu_tex_checker(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_checker", in, out); } -namespace blender::nodes { - class NodeTexChecker : public fn::MultiFunction { public: NodeTexChecker() @@ -121,19 +117,21 @@ static void sh_node_tex_checker_build_multi_function( builder.set_matching_fn(fn); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_checker_cc void register_node_type_sh_tex_checker() { + namespace file_ns = blender::nodes::node_shader_tex_checker_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_checker_declare; - node_type_init(&ntype, node_shader_init_tex_checker); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_CHECKER, "Checker Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_checker_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_checker); node_type_storage( &ntype, "NodeTexChecker", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_checker); - ntype.build_multi_function = blender::nodes::sh_node_tex_checker_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_checker); + ntype.build_multi_function = file_ns::sh_node_tex_checker_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc index 4ce19bdc45e..9372d29456d 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_coord.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_coord.cc @@ -17,10 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "DNA_customdata_types.h" +namespace blender::nodes::node_shader_tex_coord_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_coord_out[] = { @@ -42,11 +44,12 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, { Object *ob = (Object *)node->id; - GPUNodeLink *inv_obmat = (ob != NULL) ? GPU_uniform(&ob->imat[0][0]) : - GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); + GPUNodeLink *inv_obmat = (ob != nullptr) ? GPU_uniform(&ob->imat[0][0]) : + GPU_builtin(GPU_INVERSE_OBJECT_MATRIX); /* Opti: don't request orco if not needed. */ - GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant((float[4]){0.0f, 0.0f, 0.0f, 0.0f}) : + const float default_coords[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPUNodeLink *orco = (!out[0].hasoutput) ? GPU_constant(default_coords) : GPU_attribute(mat, CD_ORCO, ""); GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, ""); GPUNodeLink *viewpos = GPU_builtin(GPU_VIEW_POSITION); @@ -75,23 +78,25 @@ static int node_shader_gpu_tex_coord(GPUMaterial *mat, out[i].link, out[i].link, &out[i].link, - NULL); + nullptr); } } return 1; } +} // namespace blender::nodes::node_shader_tex_coord_cc + /* node type definition */ -void register_node_type_sh_tex_coord(void) +void register_node_type_sh_tex_coord() { + namespace file_ns = blender::nodes::node_shader_tex_coord_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_tex_coord_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_tex_coord); + sh_node_type_base(&ntype, SH_NODE_TEX_COORD, "Texture Coordinate", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_tex_coord_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_coord); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc index ff08961b3e9..aa96d075f7f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_tex_environment_cc { /* **************** OUTPUT ******************** */ @@ -33,7 +35,7 @@ static bNodeSocketTemplate sh_node_tex_environment_out[] = { static void node_shader_init_tex_environment(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexEnvironment *tex = MEM_callocN(sizeof(NodeTexEnvironment), "NodeTexEnvironment"); + NodeTexEnvironment *tex = MEM_cnew<NodeTexEnvironment>("NodeTexEnvironment"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->projection = SHD_PROJ_EQUIRECTANGULAR; @@ -49,12 +51,12 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, GPUNodeStack *out) { Image *ima = (Image *)node->id; - NodeTexEnvironment *tex = node->storage; + NodeTexEnvironment *tex = (NodeTexEnvironment *)node->storage; /* We get the image user from the original node, since GPU image keeps * a pointer to it and the dependency refreshes the original. */ bNode *node_original = node->original ? node->original : node; - NodeTexImage *tex_original = node_original->storage; + NodeTexImage *tex_original = (NodeTexImage *)node_original->storage; ImageUser *iuser = &tex_original->iuser; eGPUSamplerState sampler = GPU_SAMPLER_REPEAT | GPU_SAMPLER_ANISO | GPU_SAMPLER_FILTER; /* TODO(fclem): For now assume mipmap is always enabled. */ @@ -132,17 +134,22 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, return true; } +} // namespace blender::nodes::node_shader_tex_environment_cc + /* node type definition */ -void register_node_type_sh_tex_environment(void) +void register_node_type_sh_tex_environment() { + namespace file_ns = blender::nodes::node_shader_tex_environment_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE, 0); - node_type_socket_templates(&ntype, sh_node_tex_environment_in, sh_node_tex_environment_out); - node_type_init(&ntype, node_shader_init_tex_environment); + sh_node_type_base(&ntype, SH_NODE_TEX_ENVIRONMENT, "Environment Texture", NODE_CLASS_TEXTURE); + node_type_socket_templates( + &ntype, file_ns::sh_node_tex_environment_in, file_ns::sh_node_tex_environment_out); + node_type_init(&ntype, file_ns::node_shader_init_tex_environment); node_type_storage( &ntype, "NodeTexEnvironment", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_environment); + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_environment); ntype.labelfunc = node_image_label; node_type_size_preset(&ntype, NODE_SIZE_LARGE); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc index 48199968547..2f47f214681 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_gradient.cc @@ -17,9 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_gradient_cc { static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b) { @@ -29,12 +29,9 @@ static void sh_node_tex_gradient_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")).no_muted_links(); }; -} // namespace blender::nodes - static void node_shader_init_tex_gradient(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexGradient *tex = (NodeTexGradient *)MEM_callocN(sizeof(NodeTexGradient), - "NodeTexGradient"); + NodeTexGradient *tex = MEM_cnew<NodeTexGradient>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->gradient_type = SHD_BLEND_LINEAR; @@ -56,8 +53,6 @@ static int node_shader_gpu_tex_gradient(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_gradient", in, out, GPU_constant(&gradient_type)); } -namespace blender::nodes { - class GradientFunction : public fn::MultiFunction { private: int gradient_type_; @@ -158,19 +153,21 @@ static void sh_node_gradient_tex_build_multi_function( builder.construct_and_set_matching_fn<GradientFunction>(tex->gradient_type); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_gradient_cc void register_node_type_sh_tex_gradient() { + namespace file_ns = blender::nodes::node_shader_tex_gradient_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_gradient_declare; - node_type_init(&ntype, node_shader_init_tex_gradient); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_GRADIENT, "Gradient Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_gradient_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_gradient); node_type_storage( &ntype, "NodeTexGradient", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_gradient); - ntype.build_multi_function = blender::nodes::sh_node_gradient_tex_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_gradient); + ntype.build_multi_function = file_ns::sh_node_gradient_tex_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc index d139707c6d7..745121691ac 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_image.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_image.cc @@ -17,9 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_image_cc { static void sh_node_tex_image_declare(NodeDeclarationBuilder &b) { @@ -29,11 +29,9 @@ static void sh_node_tex_image_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Alpha")).no_muted_links(); }; -}; // namespace blender::nodes - static void node_shader_init_tex_image(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexImage *tex = (NodeTexImage *)MEM_callocN(sizeof(NodeTexImage), "NodeTexImage"); + NodeTexImage *tex = MEM_cnew<NodeTexImage>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); BKE_imageuser_default(&tex->iuser); @@ -173,17 +171,20 @@ static int node_shader_gpu_tex_image(GPUMaterial *mat, return true; } -/* node type definition */ +} // namespace blender::nodes::node_shader_tex_image_cc + void register_node_type_sh_tex_image() { + namespace file_ns = blender::nodes::node_shader_tex_image_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_image_declare; - node_type_init(&ntype, node_shader_init_tex_image); + sh_node_type_base(&ntype, SH_NODE_TEX_IMAGE, "Image Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_image_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_image); node_type_storage( &ntype, "NodeTexImage", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_image); + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_image); ntype.labelfunc = node_image_label; node_type_size_preset(&ntype, NODE_SIZE_LARGE); diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc index 9bd5c335cee..b388f1a3172 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_magic.cc @@ -17,9 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_magic_cc { static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b) { @@ -31,11 +31,9 @@ static void sh_node_tex_magic_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")).no_muted_links(); }; -} // namespace blender::nodes - static void node_shader_init_tex_magic(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexMagic *tex = (NodeTexMagic *)MEM_callocN(sizeof(NodeTexMagic), "NodeTexMagic"); + NodeTexMagic *tex = MEM_cnew<NodeTexMagic>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->depth = 2; @@ -58,8 +56,6 @@ static int node_shader_gpu_tex_magic(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_magic", in, out, GPU_constant(&depth)); } -namespace blender::nodes { - class MagicFunction : public fn::MultiFunction { private: int depth_; @@ -179,19 +175,21 @@ static void sh_node_magic_tex_build_multi_function( builder.construct_and_set_matching_fn<MagicFunction>(tex->depth); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_magic_cc void register_node_type_sh_tex_magic() { + namespace file_ns = blender::nodes::node_shader_tex_magic_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_magic_declare; - node_type_init(&ntype, node_shader_init_tex_magic); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_MAGIC, "Magic Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_magic_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_magic); node_type_storage( &ntype, "NodeTexMagic", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_magic); - ntype.build_multi_function = blender::nodes::sh_node_magic_tex_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_magic); + ntype.build_multi_function = file_ns::sh_node_magic_tex_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index 97ac199bc03..94713ad24ba 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -17,13 +17,13 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_noise.hh" -NODE_STORAGE_FUNCS(NodeTexMusgrave) +namespace blender::nodes::node_shader_tex_musgrave_cc { -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeTexMusgrave) static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b) { @@ -42,12 +42,9 @@ static void sh_node_tex_musgrave_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")).no_muted_links(); }; -} // namespace blender::nodes - static void node_shader_init_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexMusgrave *tex = (NodeTexMusgrave *)MEM_callocN(sizeof(NodeTexMusgrave), - "NodeTexMusgrave"); + NodeTexMusgrave *tex = MEM_cnew<NodeTexMusgrave>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->musgrave_type = SHD_MUSGRAVE_FBM; @@ -133,8 +130,6 @@ static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node) node_sock_label(outFacSock, "Height"); } -namespace blender::nodes { - class MusgraveFunction : public fn::MultiFunction { private: const int dimensions_; @@ -524,7 +519,7 @@ class MusgraveFunction : public fn::MultiFunction { } } } -}; // namespace blender::nodes +}; static void sh_node_musgrave_build_multi_function( blender::nodes::NodeMultiFunctionBuilder &builder) @@ -534,21 +529,23 @@ static void sh_node_musgrave_build_multi_function( builder.construct_and_set_matching_fn<MusgraveFunction>(tex->dimensions, tex->musgrave_type); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_musgrave_cc void register_node_type_sh_tex_musgrave() { + namespace file_ns = blender::nodes::node_shader_tex_musgrave_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_musgrave_declare; + sh_fn_node_type_base(&ntype, SH_NODE_TEX_MUSGRAVE, "Musgrave Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_musgrave_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_tex_musgrave); + node_type_init(&ntype, file_ns::node_shader_init_tex_musgrave); node_type_storage( &ntype, "NodeTexMusgrave", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_musgrave); - node_type_update(&ntype, node_shader_update_tex_musgrave); - ntype.build_multi_function = blender::nodes::sh_node_musgrave_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_musgrave); + node_type_update(&ntype, file_ns::node_shader_update_tex_musgrave); + ntype.build_multi_function = file_ns::sh_node_musgrave_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index d7f21853a01..fe402675ec6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -17,13 +17,13 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_noise.hh" -NODE_STORAGE_FUNCS(NodeTexNoise) +namespace blender::nodes::node_shader_tex_noise_cc { -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeTexNoise) static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b) { @@ -45,11 +45,9 @@ static void sh_node_tex_noise_declare(NodeDeclarationBuilder &b) b.add_output<decl::Color>(N_("Color")).no_muted_links(); }; -} // namespace blender::nodes - static void node_shader_init_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexNoise *tex = (NodeTexNoise *)MEM_callocN(sizeof(NodeTexNoise), "NodeTexNoise"); + NodeTexNoise *tex = MEM_cnew<NodeTexNoise>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->dimensions = 3; @@ -91,8 +89,6 @@ static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sockW, storage.dimensions == 1 || storage.dimensions == 4); } -namespace blender::nodes { - class NoiseFunction : public fn::MultiFunction { private: int dimensions_; @@ -250,21 +246,22 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction builder.construct_and_set_matching_fn<NoiseFunction>(storage.dimensions); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_noise_cc -/* node type definition */ void register_node_type_sh_tex_noise() { + namespace file_ns = blender::nodes::node_shader_tex_noise_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_noise_declare; - node_type_init(&ntype, node_shader_init_tex_noise); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_NOISE, "Noise Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_noise_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_noise); node_type_storage( &ntype, "NodeTexNoise", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_noise); - node_type_update(&ntype, node_shader_update_tex_noise); - ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_noise); + node_type_update(&ntype, file_ns::node_shader_update_tex_noise); + ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc index 14cd1fd4c0c..31d14d09963 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_pointdensity.cc @@ -17,10 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "RE_texture.h" +namespace blender::nodes::node_shader_tex_pointdensity_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_pointdensity_in[] = { @@ -36,8 +38,7 @@ static bNodeSocketTemplate sh_node_tex_pointdensity_out[] = { static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderTexPointDensity *point_density = MEM_callocN(sizeof(NodeShaderTexPointDensity), - "new pd node"); + NodeShaderTexPointDensity *point_density = MEM_cnew<NodeShaderTexPointDensity>("new pd node"); point_density->resolution = 100; point_density->radius = 0.3f; point_density->space = SHD_POINTDENSITY_SPACE_OBJECT; @@ -47,7 +48,7 @@ static void node_shader_init_tex_pointdensity(bNodeTree *UNUSED(ntree), bNode *n static void node_shader_free_tex_pointdensity(bNode *node) { - NodeShaderTexPointDensity *point_density = node->storage; + NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)node->storage; PointDensity *pd = &point_density->pd; RE_point_density_free(pd); BKE_texture_pointdensity_free_data(pd); @@ -60,23 +61,28 @@ static void node_shader_copy_tex_pointdensity(bNodeTree *UNUSED(dest_ntree), const bNode *src_node) { dest_node->storage = MEM_dupallocN(src_node->storage); - NodeShaderTexPointDensity *point_density = dest_node->storage; + NodeShaderTexPointDensity *point_density = (NodeShaderTexPointDensity *)dest_node->storage; PointDensity *pd = &point_density->pd; memset(pd, 0, sizeof(*pd)); } +} // namespace blender::nodes::node_shader_tex_pointdensity_cc + /* node type definition */ -void register_node_type_sh_tex_pointdensity(void) +void register_node_type_sh_tex_pointdensity() { + namespace file_ns = blender::nodes::node_shader_tex_pointdensity_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE, 0); - node_type_socket_templates(&ntype, sh_node_tex_pointdensity_in, sh_node_tex_pointdensity_out); - node_type_init(&ntype, node_shader_init_tex_pointdensity); + sh_node_type_base(&ntype, SH_NODE_TEX_POINTDENSITY, "Point Density", NODE_CLASS_TEXTURE); + node_type_socket_templates( + &ntype, file_ns::sh_node_tex_pointdensity_in, file_ns::sh_node_tex_pointdensity_out); + node_type_init(&ntype, file_ns::node_shader_init_tex_pointdensity); node_type_storage(&ntype, "NodeShaderTexPointDensity", - node_shader_free_tex_pointdensity, - node_shader_copy_tex_pointdensity); + file_ns::node_shader_free_tex_pointdensity, + file_ns::node_shader_copy_tex_pointdensity); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc index 5c581528c14..56e42708e93 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.cc @@ -17,9 +17,11 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "sky_model.h" +namespace blender::nodes::node_shader_tex_sky_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_tex_sky_in[] = { @@ -34,7 +36,7 @@ static bNodeSocketTemplate sh_node_tex_sky_out[] = { static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexSky *tex = MEM_callocN(sizeof(NodeTexSky), "NodeTexSky"); + NodeTexSky *tex = MEM_cnew<NodeTexSky>("NodeTexSky"); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->sun_direction[0] = 0.0f; @@ -55,10 +57,10 @@ static void node_shader_init_tex_sky(bNodeTree *UNUSED(ntree), bNode *node) node->storage = tex; } -typedef struct SkyModelPreetham { +struct SkyModelPreetham { float config_Y[5], config_x[5], config_y[5]; /* named after xyY color space */ float radiance[3]; -} SkyModelPreetham; +}; static float sky_perez_function(const float *lam, float theta, float gamma) { @@ -203,19 +205,23 @@ static void node_shader_update_sky(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); } +} // namespace blender::nodes::node_shader_tex_sky_cc + /* node type definition */ -void register_node_type_sh_tex_sky(void) +void register_node_type_sh_tex_sky() { + namespace file_ns = blender::nodes::node_shader_tex_sky_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE, 0); - node_type_socket_templates(&ntype, sh_node_tex_sky_in, sh_node_tex_sky_out); + sh_node_type_base(&ntype, SH_NODE_TEX_SKY, "Sky Texture", NODE_CLASS_TEXTURE); + node_type_socket_templates(&ntype, file_ns::sh_node_tex_sky_in, file_ns::sh_node_tex_sky_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_tex_sky); + node_type_init(&ntype, file_ns::node_shader_init_tex_sky); node_type_storage(&ntype, "NodeTexSky", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_sky); + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_sky); /* remove Vector input for Nishita */ - node_type_update(&ntype, node_shader_update_sky); + node_type_update(&ntype, file_ns::node_shader_update_sky); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc index 8a1170de304..72f7fe08a15 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -17,13 +17,13 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_noise.hh" -NODE_STORAGE_FUNCS(NodeTexVoronoi) +namespace blender::nodes::node_shader_tex_voronoi_cc { -namespace blender::nodes { +NODE_STORAGE_FUNCS(NodeTexVoronoi) static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b) { @@ -62,11 +62,9 @@ static void sh_node_tex_voronoi_declare(NodeDeclarationBuilder &b) }); }; -} // namespace blender::nodes - static void node_shader_init_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexVoronoi *tex = (NodeTexVoronoi *)MEM_callocN(sizeof(NodeTexVoronoi), "NodeTexVoronoi"); + NodeTexVoronoi *tex = MEM_cnew<NodeTexVoronoi>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->dimensions = 3; @@ -181,8 +179,6 @@ static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, outRadiusSock, storage.feature == SHD_VORONOI_N_SPHERE_RADIUS); } -namespace blender::nodes { - static MultiFunction::ExecutionHints voronoi_execution_hints{50, false}; class VoronoiMinowskiFunction : public fn::MultiFunction { @@ -1340,20 +1336,22 @@ static void sh_node_voronoi_build_multi_function(blender::nodes::NodeMultiFuncti } } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_voronoi_cc void register_node_type_sh_tex_voronoi() { + namespace file_ns = blender::nodes::node_shader_tex_voronoi_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_voronoi_declare; - node_type_init(&ntype, node_shader_init_tex_voronoi); + sh_fn_node_type_base(&ntype, SH_NODE_TEX_VORONOI, "Voronoi Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_voronoi_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_voronoi); node_type_storage( &ntype, "NodeTexVoronoi", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_voronoi); - node_type_update(&ntype, node_shader_update_tex_voronoi); - ntype.build_multi_function = blender::nodes::sh_node_voronoi_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_voronoi); + node_type_update(&ntype, file_ns::node_shader_update_tex_voronoi); + ntype.build_multi_function = file_ns::sh_node_voronoi_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc index d3e25b533e5..9a3e214333b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_wave.cc @@ -17,11 +17,11 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_noise.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_wave_cc { static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b) { @@ -41,11 +41,9 @@ static void sh_node_tex_wave_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Fac")).no_muted_links(); }; -} // namespace blender::nodes - static void node_shader_init_tex_wave(bNodeTree *UNUSED(ntree), bNode *node) { - NodeTexWave *tex = (NodeTexWave *)MEM_callocN(sizeof(NodeTexWave), "NodeTexWave"); + NodeTexWave *tex = MEM_cnew<NodeTexWave>(__func__); BKE_texture_mapping_default(&tex->base.tex_mapping, TEXMAP_TYPE_POINT); BKE_texture_colormapping_default(&tex->base.color_mapping); tex->wave_type = SHD_WAVE_BANDS; @@ -81,8 +79,6 @@ static int node_shader_gpu_tex_wave(GPUMaterial *mat, GPU_constant(&wave_profile)); } -namespace blender::nodes { - class WaveFunction : public fn::MultiFunction { private: int wave_type_; @@ -216,19 +212,21 @@ static void sh_node_wave_tex_build_multi_function( tex->wave_type, tex->bands_direction, tex->rings_direction, tex->wave_profile); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_wave_cc void register_node_type_sh_tex_wave() { + namespace file_ns = blender::nodes::node_shader_tex_wave_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_wave_declare; + sh_fn_node_type_base(&ntype, SH_NODE_TEX_WAVE, "Wave Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_wave_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_tex_wave); + node_type_init(&ntype, file_ns::node_shader_init_tex_wave); node_type_storage(&ntype, "NodeTexWave", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_tex_wave); - ntype.build_multi_function = blender::nodes::sh_node_wave_tex_build_multi_function; + node_type_gpu(&ntype, file_ns::node_shader_gpu_tex_wave); + ntype.build_multi_function = file_ns::sh_node_wave_tex_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 0e72cee38e7..96d45d7c53b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -17,11 +17,11 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "BLI_noise.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_tex_white_noise_cc { static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b) { @@ -35,8 +35,6 @@ static void sh_node_tex_white_noise_declare(NodeDeclarationBuilder &b) b.add_output<decl::Color>(N_("Color")); }; -} // namespace blender::nodes - static void node_shader_init_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node) { node->custom1 = 3; @@ -70,8 +68,6 @@ static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node) nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4); } -namespace blender::nodes { - class WhiteNoiseFunction : public fn::MultiFunction { private: int dimensions_; @@ -192,19 +188,20 @@ static void sh_node_noise_build_multi_function(blender::nodes::NodeMultiFunction builder.construct_and_set_matching_fn<WhiteNoiseFunction>((int)node.custom1); } -} // namespace blender::nodes +} // namespace blender::nodes::node_shader_tex_white_noise_cc void register_node_type_sh_tex_white_noise() { + namespace file_ns = blender::nodes::node_shader_tex_white_noise_cc; + static bNodeType ntype; - sh_fn_node_type_base( - &ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::sh_node_tex_white_noise_declare; - node_type_init(&ntype, node_shader_init_tex_white_noise); - node_type_gpu(&ntype, gpu_shader_tex_white_noise); - node_type_update(&ntype, node_shader_update_tex_white_noise); - ntype.build_multi_function = blender::nodes::sh_node_noise_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_TEX_WHITE_NOISE, "White Noise Texture", NODE_CLASS_TEXTURE); + ntype.declare = file_ns::sh_node_tex_white_noise_declare; + node_type_init(&ntype, file_ns::node_shader_init_tex_white_noise); + node_type_gpu(&ntype, file_ns::gpu_shader_tex_white_noise); + node_type_update(&ntype, file_ns::node_shader_update_tex_white_noise); + ntype.build_multi_function = file_ns::sh_node_noise_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc index 05c3248af65..1b9bc60b6ea 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.c +++ b/source/blender/nodes/shader/nodes/node_shader_uv_along_stroke.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_uv_along_stroke_cc { /* **************** OUTPUT ******************** */ @@ -26,14 +28,17 @@ static bNodeSocketTemplate sh_node_uvalongstroke_out[] = { {-1, ""}, }; +} // namespace blender::nodes::node_shader_uv_along_stroke_cc + /* node type definition */ -void register_node_type_sh_uvalongstroke(void) +void register_node_type_sh_uvalongstroke() { + namespace file_ns = blender::nodes::node_shader_uv_along_stroke_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_uvalongstroke_out); - node_type_init(&ntype, NULL); + sh_node_type_base(&ntype, SH_NODE_UVALONGSTROKE, "UV Along Stroke", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_uvalongstroke_out); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_uvmap.c b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc index 775b8ffbc06..9d1e02ee919 100644 --- a/source/blender/nodes/shader/nodes/node_shader_uvmap.c +++ b/source/blender/nodes/shader/nodes/node_shader_uvmap.cc @@ -17,10 +17,12 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" #include "DNA_customdata_types.h" +namespace blender::nodes::node_shader_uvmap_cc { + /* **************** OUTPUT ******************** */ static bNodeSocketTemplate sh_node_uvmap_out[] = { @@ -30,7 +32,7 @@ static bNodeSocketTemplate sh_node_uvmap_out[] = { static void node_shader_init_uvmap(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderUVMap *attr = MEM_callocN(sizeof(NodeShaderUVMap), "NodeShaderUVMap"); + NodeShaderUVMap *attr = MEM_cnew<NodeShaderUVMap>("NodeShaderUVMap"); node->storage = attr; } @@ -40,7 +42,7 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, GPUNodeStack *in, GPUNodeStack *out) { - NodeShaderUVMap *attr = node->storage; + NodeShaderUVMap *attr = static_cast<NodeShaderUVMap *>(node->storage); GPUNodeLink *mtface = GPU_attribute(mat, CD_MTFACE, attr->uv_map); GPU_stack_link(mat, node, "node_uvmap", in, out, mtface); @@ -50,18 +52,22 @@ static int node_shader_gpu_uvmap(GPUMaterial *mat, return 1; } +} // namespace blender::nodes::node_shader_uvmap_cc + /* node type definition */ -void register_node_type_sh_uvmap(void) +void register_node_type_sh_uvmap() { + namespace file_ns = blender::nodes::node_shader_uvmap_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_uvmap_out); + sh_node_type_base(&ntype, SH_NODE_UVMAP, "UV Map", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_uvmap_out); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, node_shader_init_uvmap); + node_type_init(&ntype, file_ns::node_shader_init_uvmap); node_type_storage( &ntype, "NodeShaderUVMap", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_uvmap); + node_type_gpu(&ntype, file_ns::node_shader_gpu_uvmap); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index f0eb3ea9bee..21f2e072990 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -21,17 +21,15 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_value_cc { static void sh_node_value_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Value")); }; -} // namespace blender::nodes - static int gpu_shader_value(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -49,14 +47,18 @@ static void sh_node_value_build_multi_function(blender::nodes::NodeMultiFunction builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value); } +} // namespace blender::nodes::node_shader_value_cc + void register_node_type_sh_value() { + namespace file_ns = blender::nodes::node_shader_value_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::sh_node_value_declare; - node_type_gpu(&ntype, gpu_shader_value); - ntype.build_multi_function = sh_node_value_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_VALUE, "Value", NODE_CLASS_INPUT); + ntype.declare = file_ns::sh_node_value_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_value); + ntype.build_multi_function = file_ns::sh_node_value_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc index 0e82f346529..fbdb7177a93 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_displacement.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_displacement.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_vector_displacement_cc { /* **************** OUTPUT ******************** */ @@ -63,18 +65,21 @@ static int gpu_shader_vector_displacement(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_vector_displacement_world", in, out); } +} // namespace blender::nodes::node_shader_vector_displacement_cc + /* node type definition */ -void register_node_type_sh_vector_displacement(void) +void register_node_type_sh_vector_displacement() { + namespace file_ns = blender::nodes::node_shader_vector_displacement_cc; + static bNodeType ntype; sh_node_type_base( - &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR, 0); + &ntype, SH_NODE_VECTOR_DISPLACEMENT, "Vector Displacement", NODE_CLASS_OP_VECTOR); node_type_socket_templates( - &ntype, sh_node_vector_displacement_in, sh_node_vector_displacement_out); - node_type_storage(&ntype, "", NULL, NULL); - node_type_init(&ntype, node_shader_init_vector_displacement); - node_type_gpu(&ntype, gpu_shader_vector_displacement); + &ntype, file_ns::sh_node_vector_displacement_in, file_ns::sh_node_vector_displacement_out); + node_type_init(&ntype, file_ns::node_shader_init_vector_displacement); + node_type_gpu(&ntype, file_ns::gpu_shader_vector_displacement); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 5f5969de78c..1276592e2af 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -21,12 +21,14 @@ * \ingroup shdnodes */ -#include "node_shader_util.h" +#include "node_shader_util.hh" #include "NOD_math_functions.hh" #include "NOD_socket_search_link.hh" -namespace blender::nodes { +#include "RNA_enum_types.h" + +namespace blender::nodes::node_shader_vector_math_cc { static void sh_node_vector_math_declare(NodeDeclarationBuilder &b) { @@ -39,19 +41,46 @@ static void sh_node_vector_math_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Value")); }; +class SocketSearchOp { + public: + std::string socket_name; + NodeVectorMathOperation mode = NODE_VECTOR_MATH_ADD; + void operator()(LinkSearchOpParams ¶ms) + { + bNode &node = params.add_node("ShaderNodeVectorMath"); + node.custom1 = mode; + params.update_and_connect_available_socket(node, socket_name); + } +}; + static void sh_node_vector_math_gather_link_searches(GatherLinkSearchOpParams ¶ms) { - /* For now, do something very basic (only exposing "Add", and a single "Vector" socket). */ - if (params.node_tree().typeinfo->validate_link( + if (!params.node_tree().typeinfo->validate_link( static_cast<eNodeSocketDatatype>(params.other_socket().type), SOCK_VECTOR)) { - params.add_item(IFACE_("Vector"), [](LinkSearchOpParams ¶ms) { - bNode &node = params.add_node("ShaderNodeVectorMath"); - params.update_and_connect_available_socket(node, "Vector"); - }); + return; } -} -} // namespace blender::nodes + const int weight = ELEM(params.other_socket().type, SOCK_VECTOR, SOCK_RGBA) ? 0 : -1; + + for (const EnumPropertyItem *item = rna_enum_node_vec_math_items; item->identifier != nullptr; + item++) { + if (item->name != nullptr && item->identifier[0] != '\0') { + if ((params.in_out() == SOCK_OUT) && ELEM(item->value, + NODE_VECTOR_MATH_LENGTH, + NODE_VECTOR_MATH_DISTANCE, + NODE_VECTOR_MATH_DOT_PRODUCT)) { + params.add_item(IFACE_(item->name), + SocketSearchOp{"Value", (NodeVectorMathOperation)item->value}, + weight); + } + else { + params.add_item(IFACE_(item->name), + SocketSearchOp{"Vector", (NodeVectorMathOperation)item->value}, + weight); + } + } + } +} static const char *gpu_shader_get_name(int mode) { @@ -292,17 +321,21 @@ static void sh_node_vector_math_build_multi_function( builder.set_matching_fn(fn); } +} // namespace blender::nodes::node_shader_vector_math_cc + void register_node_type_sh_vect_math() { + namespace file_ns = blender::nodes::node_shader_vector_math_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR, 0); - ntype.declare = blender::nodes::sh_node_vector_math_declare; + sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_OP_VECTOR); + ntype.declare = file_ns::sh_node_vector_math_declare; ntype.labelfunc = node_vector_math_label; - node_type_gpu(&ntype, gpu_shader_vector_math); - node_type_update(&ntype, node_shader_update_vector_math); - ntype.build_multi_function = sh_node_vector_math_build_multi_function; - ntype.gather_link_search_ops = blender::nodes::sh_node_vector_math_gather_link_searches; + node_type_gpu(&ntype, file_ns::gpu_shader_vector_math); + node_type_update(&ntype, file_ns::node_shader_update_vector_math); + ntype.build_multi_function = file_ns::sh_node_vector_math_build_multi_function; + ntype.gather_link_search_ops = file_ns::sh_node_vector_math_gather_link_searches; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index a3cb82f3245..bb7a81ef5d8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -21,9 +21,9 @@ * \ingroup shdnodes */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_shader_vector_rotate_cc { static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b) { @@ -36,8 +36,6 @@ static void sh_node_vector_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Vector")); }; -} // namespace blender::nodes - static const char *gpu_shader_get_name(int mode) { switch (mode) { @@ -205,15 +203,19 @@ static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } +} // namespace blender::nodes::node_shader_vector_rotate_cc + void register_node_type_sh_vector_rotate() { + namespace file_ns = blender::nodes::node_shader_vector_rotate_cc; + static bNodeType ntype; - sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); - ntype.declare = blender::nodes::sh_node_vector_rotate_declare; - node_type_gpu(&ntype, gpu_shader_vector_rotate); - node_type_update(&ntype, node_shader_update_vector_rotate); - ntype.build_multi_function = sh_node_vector_rotate_build_multi_function; + sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR); + ntype.declare = file_ns::sh_node_vector_rotate_declare; + node_type_gpu(&ntype, file_ns::gpu_shader_vector_rotate); + node_type_update(&ntype, file_ns::node_shader_update_vector_rotate); + ntype.build_multi_function = file_ns::sh_node_vector_rotate_build_multi_function; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc index 7b08178f874..fc1c4c3abf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_transform.c +++ b/source/blender/nodes/shader/nodes/node_shader_vector_transform.cc @@ -21,7 +21,9 @@ * \ingroup shdnodes */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_vector_transform_cc { /* **************** Vector Transform ******************** */ static bNodeSocketTemplate sh_node_vect_transform_in[] = { @@ -34,8 +36,7 @@ static bNodeSocketTemplate sh_node_vect_transform_out[] = { static void node_shader_init_vect_transform(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderVectTransform *vect = MEM_callocN(sizeof(NodeShaderVectTransform), - "NodeShaderVectTransform"); + NodeShaderVectTransform *vect = MEM_cnew<NodeShaderVectTransform>("NodeShaderVectTransform"); /* Convert World into Object Space per default */ vect->convert_to = 1; @@ -58,7 +59,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_OBJECT: switch (to) { case SHD_VECT_TRANSFORM_SPACE_OBJECT: - return NULL; + return nullptr; case SHD_VECT_TRANSFORM_SPACE_WORLD: return GPU_builtin(GPU_OBJECT_MATRIX); case SHD_VECT_TRANSFORM_SPACE_CAMERA: @@ -68,7 +69,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_WORLD: switch (to) { case SHD_VECT_TRANSFORM_SPACE_WORLD: - return NULL; + return nullptr; case SHD_VECT_TRANSFORM_SPACE_CAMERA: return GPU_builtin(GPU_VIEW_MATRIX); case SHD_VECT_TRANSFORM_SPACE_OBJECT: @@ -78,7 +79,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) case SHD_VECT_TRANSFORM_SPACE_CAMERA: switch (to) { case SHD_VECT_TRANSFORM_SPACE_CAMERA: - return NULL; + return nullptr; case SHD_VECT_TRANSFORM_SPACE_WORLD: return GPU_builtin(GPU_INVERSE_VIEW_MATRIX); case SHD_VECT_TRANSFORM_SPACE_OBJECT: @@ -86,7 +87,7 @@ static GPUNodeLink *get_gpulink_matrix_from_to(short from, short to) } break; } - return NULL; + return nullptr; } static int gpu_shader_vect_transform(GPUMaterial *mat, bNode *node, @@ -99,7 +100,7 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, const char *vtransform = "direction_transform_m4v3"; const char *ptransform = "point_transform_m4v3"; - const char *func_name = 0; + const char *func_name = nullptr; NodeShaderVectTransform *nodeprop = (NodeShaderVectTransform *)node->storage; @@ -137,17 +138,22 @@ static int gpu_shader_vect_transform(GPUMaterial *mat, return true; } -void register_node_type_sh_vect_transform(void) +} // namespace blender::nodes::node_shader_vector_transform_cc + +void register_node_type_sh_vect_transform() { + namespace file_ns = blender::nodes::node_shader_vector_transform_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR, 0); - node_type_init(&ntype, node_shader_init_vect_transform); - node_type_socket_templates(&ntype, sh_node_vect_transform_in, sh_node_vect_transform_out); + sh_node_type_base(&ntype, SH_NODE_VECT_TRANSFORM, "Vector Transform", NODE_CLASS_OP_VECTOR); + node_type_init(&ntype, file_ns::node_shader_init_vect_transform); + node_type_socket_templates( + &ntype, file_ns::sh_node_vect_transform_in, file_ns::sh_node_vect_transform_out); node_type_storage( &ntype, "NodeShaderVectTransform", node_free_standard_storage, node_copy_standard_storage); - node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_transform); - node_type_gpu(&ntype, gpu_shader_vect_transform); + node_type_exec(&ntype, nullptr, nullptr, file_ns::node_shader_exec_vect_transform); + node_type_gpu(&ntype, file_ns::gpu_shader_vect_transform); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc index 40576b68dd5..849d2bf58bb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vertex_color.c +++ b/source/blender/nodes/shader/nodes/node_shader_vertex_color.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_vertex_color_cc { static bNodeSocketTemplate sh_node_vertex_color_out[] = { {SOCK_RGBA, N_("Color")}, @@ -27,8 +29,7 @@ static bNodeSocketTemplate sh_node_vertex_color_out[] = { static void node_shader_init_vertex_color(bNodeTree *UNUSED(ntree), bNode *node) { - NodeShaderVertexColor *vertexColor = MEM_callocN(sizeof(NodeShaderVertexColor), - "NodeShaderVertexColor"); + NodeShaderVertexColor *vertexColor = MEM_cnew<NodeShaderVertexColor>("NodeShaderVertexColor"); node->storage = vertexColor; } @@ -47,16 +48,20 @@ static int node_shader_gpu_vertex_color(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_vertex_color", in, out, vertexColorLink); } -void register_node_type_sh_vertex_color(void) +} // namespace blender::nodes::node_shader_vertex_color_cc + +void register_node_type_sh_vertex_color() { + namespace file_ns = blender::nodes::node_shader_vertex_color_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_vertex_color_out); - node_type_init(&ntype, node_shader_init_vertex_color); + sh_node_type_base(&ntype, SH_NODE_VERTEX_COLOR, "Vertex Color", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_vertex_color_out); + node_type_init(&ntype, file_ns::node_shader_init_vertex_color); node_type_storage( &ntype, "NodeShaderVertexColor", node_free_standard_storage, node_copy_standard_storage); - node_type_gpu(&ntype, node_shader_gpu_vertex_color); + node_type_gpu(&ntype, file_ns::node_shader_gpu_vertex_color); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc index abf2e63e6d5..cd697c96d66 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_absorption.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_absorption.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_volume_absorption_cc { /* **************** OUTPUT ******************** */ @@ -41,16 +43,19 @@ static int node_shader_gpu_volume_absorption(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_volume_absorption", in, out); } +} // namespace blender::nodes::node_shader_volume_absorption_cc + /* node type definition */ -void register_node_type_sh_volume_absorption(void) +void register_node_type_sh_volume_absorption() { + namespace file_ns = blender::nodes::node_shader_volume_absorption_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_volume_absorption_in, sh_node_volume_absorption_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_volume_absorption); + sh_node_type_base(&ntype, SH_NODE_VOLUME_ABSORPTION, "Volume Absorption", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_volume_absorption_in, file_ns::sh_node_volume_absorption_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_absorption); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc index 6cafc991e13..53458ed962c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_volume_info_cc { static bNodeSocketTemplate sh_node_volume_info_out[] = { {SOCK_RGBA, N_("Color")}, @@ -49,13 +51,17 @@ static int node_shader_gpu_volume_info(GPUMaterial *mat, return true; } -void register_node_type_sh_volume_info(void) +} // namespace blender::nodes::node_shader_volume_info_cc + +void register_node_type_sh_volume_info() { + namespace file_ns = blender::nodes::node_shader_volume_info_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, NULL, sh_node_volume_info_out); - node_type_gpu(&ntype, node_shader_gpu_volume_info); + sh_node_type_base(&ntype, SH_NODE_VOLUME_INFO, "Volume Info", NODE_CLASS_INPUT); + node_type_socket_templates(&ntype, nullptr, file_ns::sh_node_volume_info_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_info); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc index 1a25aec5cb8..3acf8c35ac1 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_volume_principled_cc { /* **************** OUTPUT ******************** */ @@ -64,14 +66,14 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, bool use_blackbody = (in[8].link || in[8].vec[0] != 0.0f); /* Get volume attributes. */ - GPUNodeLink *density = NULL, *color = NULL, *temperature = NULL; + GPUNodeLink *density = nullptr, *color = nullptr, *temperature = nullptr; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { if (sock->typeinfo->type != SOCK_STRING) { continue; } - bNodeSocketValueString *value = sock->default_value; + bNodeSocketValueString *value = (bNodeSocketValueString *)sock->default_value; const char *attribute_name = value->value; if (attribute_name[0] == '\0') { continue; @@ -106,11 +108,11 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, const int size = CM_TABLE + 1; float *data, layer; if (use_blackbody) { - data = MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"); + data = (float *)MEM_mallocN(sizeof(float) * size * 4, "blackbody texture"); blackbody_temperature_to_rgb_table(data, size, 965.0f, 12000.0f); } else { - data = MEM_callocN(sizeof(float) * size * 4, "blackbody black"); + data = (float *)MEM_callocN(sizeof(float) * size * 4, "blackbody black"); } GPUNodeLink *spectrummap = GPU_color_band(mat, size, data, &layer); @@ -126,17 +128,21 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, GPU_constant(&layer)); } +} // namespace blender::nodes::node_shader_volume_principled_cc + /* node type definition */ -void register_node_type_sh_volume_principled(void) +void register_node_type_sh_volume_principled() { + namespace file_ns = blender::nodes::node_shader_volume_principled_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_volume_principled_in, sh_node_volume_principled_out); + sh_node_type_base(&ntype, SH_NODE_VOLUME_PRINCIPLED, "Principled Volume", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_volume_principled_in, file_ns::sh_node_volume_principled_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, node_shader_init_volume_principled); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_volume_principled); + node_type_init(&ntype, file_ns::node_shader_init_volume_principled); + node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_principled); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc index f4cfe7729ca..e07087e8529 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_scatter.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_scatter.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_volume_scatter_cc { /* **************** OUTPUT ******************** */ @@ -42,16 +44,19 @@ static int node_shader_gpu_volume_scatter(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_volume_scatter", in, out); } +} // namespace blender::nodes::node_shader_volume_scatter_cc + /* node type definition */ -void register_node_type_sh_volume_scatter(void) +void register_node_type_sh_volume_scatter() { + namespace file_ns = blender::nodes::node_shader_volume_scatter_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER, 0); - node_type_socket_templates(&ntype, sh_node_volume_scatter_in, sh_node_volume_scatter_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_volume_scatter); + sh_node_type_base(&ntype, SH_NODE_VOLUME_SCATTER, "Volume Scatter", NODE_CLASS_SHADER); + node_type_socket_templates( + &ntype, file_ns::sh_node_volume_scatter_in, file_ns::sh_node_volume_scatter_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_volume_scatter); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_wavelength.c b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc index f978537ee85..a67c7830edd 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wavelength.c +++ b/source/blender/nodes/shader/nodes/node_shader_wavelength.cc @@ -17,18 +17,15 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" -/* **************** Wavelength ******************** */ -static bNodeSocketTemplate sh_node_wavelength_in[] = { - {SOCK_FLOAT, N_("Wavelength"), 500.0f, 0.0f, 0.0f, 0.0f, 380.0f, 780.0f}, - {-1, ""}, -}; +namespace blender::nodes::node_shader_wavelength_cc { -static bNodeSocketTemplate sh_node_wavelength_out[] = { - {SOCK_RGBA, N_("Color")}, - {-1, ""}, -}; +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Wavelength")).default_value(500.0f).min(380.0f).max(780.0f); + b.add_output<decl::Color>(N_("Color")); +} static int node_shader_gpu_wavelength(GPUMaterial *mat, bNode *node, @@ -37,7 +34,7 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat, GPUNodeStack *out) { const int size = CM_TABLE + 1; - float *data = MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture"); + float *data = static_cast<float *>(MEM_mallocN(sizeof(float) * size * 4, "cie_xyz texture")); wavelength_to_xyz_table(data, size); @@ -57,17 +54,19 @@ static int node_shader_gpu_wavelength(GPUMaterial *mat, GPU_uniform(xyz_to_rgb.b)); } +} // namespace blender::nodes::node_shader_wavelength_cc + /* node type definition */ -void register_node_type_sh_wavelength(void) +void register_node_type_sh_wavelength() { + namespace file_ns = blender::nodes::node_shader_wavelength_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER, 0); + sh_node_type_base(&ntype, SH_NODE_WAVELENGTH, "Wavelength", NODE_CLASS_CONVERTER); + ntype.declare = file_ns::node_declare; node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_socket_templates(&ntype, sh_node_wavelength_in, sh_node_wavelength_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_wavelength); + node_type_gpu(&ntype, file_ns::node_shader_gpu_wavelength); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_wireframe.c b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc index 37e60ddb205..1b38dd795cb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_wireframe.c +++ b/source/blender/nodes/shader/nodes/node_shader_wireframe.cc @@ -17,7 +17,9 @@ * All rights reserved. */ -#include "../node_shader_util.h" +#include "node_shader_util.hh" + +namespace blender::nodes::node_shader_wireframe_cc { /* **************** Wireframe ******************** */ static bNodeSocketTemplate sh_node_wireframe_in[] = { @@ -52,16 +54,19 @@ static int node_shader_gpu_wireframe(GPUMaterial *mat, GPU_builtin(GPU_BARYCENTRIC_DIST)); } +} // namespace blender::nodes::node_shader_wireframe_cc + /* node type definition */ -void register_node_type_sh_wireframe(void) +void register_node_type_sh_wireframe() { + namespace file_ns = blender::nodes::node_shader_wireframe_cc; + static bNodeType ntype; - sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT, 0); - node_type_socket_templates(&ntype, sh_node_wireframe_in, sh_node_wireframe_out); - node_type_init(&ntype, NULL); - node_type_storage(&ntype, "", NULL, NULL); - node_type_gpu(&ntype, node_shader_gpu_wireframe); + sh_node_type_base(&ntype, SH_NODE_WIREFRAME, "Wireframe", NODE_CLASS_INPUT); + node_type_socket_templates( + &ntype, file_ns::sh_node_wireframe_in, file_ns::sh_node_wireframe_out); + node_type_gpu(&ntype, file_ns::node_shader_gpu_wireframe); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c index 14597050524..3d914d486c3 100644 --- a/source/blender/nodes/texture/node_texture_tree.c +++ b/source/blender/nodes/texture/node_texture_tree.c @@ -50,6 +50,8 @@ #include "RE_texture.h" +#include "UI_resources.h" + static void texture_get_from_context(const bContext *C, bNodeTreeType *UNUSED(treetype), bNodeTree **r_ntree, @@ -132,24 +134,9 @@ static void localize(bNodeTree *UNUSED(localtree), bNodeTree *UNUSED(ntree)) } #endif -static void local_sync(bNodeTree *localtree, bNodeTree *ntree) -{ - BKE_node_preview_sync_tree(ntree, localtree); -} - -static void local_merge(Main *UNUSED(bmain), bNodeTree *localtree, bNodeTree *ntree) -{ - BKE_node_preview_merge_tree(ntree, localtree, true); -} - static void update(bNodeTree *ntree) { ntree_update_reroute_nodes(ntree); - - if (ntree->update & NTREE_UPDATE_NODES) { - /* clean up preview cache, in case nodes have been removed */ - BKE_node_preview_remove_unused(ntree); - } } static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype), @@ -169,14 +156,12 @@ void register_node_tree_type_tex(void) tt->type = NTREE_TEXTURE; strcpy(tt->idname, "TextureNodeTree"); strcpy(tt->ui_name, N_("Texture Node Editor")); - tt->ui_icon = 0; /* Defined in `drawnode.c`. */ + tt->ui_icon = ICON_NODE_TEXTURE; /* Defined in `drawnode.c`. */ strcpy(tt->ui_description, N_("Texture nodes")); tt->foreach_nodeclass = foreach_nodeclass; tt->update = update; tt->localize = localize; - tt->local_sync = local_sync; - tt->local_merge = local_merge; tt->get_from_context = texture_get_from_context; tt->valid_socket_type = texture_node_tree_socket_type_valid; diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index fe8e68bfc42..dc5e2bfcd6b 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -50,10 +50,9 @@ bool tex_node_poll_default(bNodeType *UNUSED(ntype), return true; } -void tex_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag) +void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass) { - node_type_base(ntype, type, name, nclass, flag); + node_type_base(ntype, type, name, nclass); ntype->poll = tex_node_poll_default; ntype->insert_link = node_insert_link_default; @@ -63,10 +62,6 @@ static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, sh { if (dg->node->need_exec) { dg->fn(out, params, dg->node, dg->in, thread); - - if (dg->cdata->do_preview) { - tex_do_preview(dg->preview, params->previewco, out, dg->cdata->do_manage); - } } } @@ -123,19 +118,6 @@ void params_from_cdata(TexParams *out, TexCallData *in) out->mtex = in->mtex; } -void tex_do_preview(bNodePreview *preview, - const float coord[2], - const float col[4], - bool do_manage) -{ - if (preview) { - int xs = ((coord[0] + 1.0f) * 0.5f) * preview->xsize; - int ys = ((coord[1] + 1.0f) * 0.5f) * preview->ysize; - - BKE_node_preview_set_pixel(preview, col, xs, ys, do_manage); - } -} - void tex_output(bNode *node, bNodeExecData *execdata, bNodeStack **in, diff --git a/source/blender/nodes/texture/node_texture_util.h b/source/blender/nodes/texture/node_texture_util.h index 84d2c5c903a..d53000058a3 100644 --- a/source/blender/nodes/texture/node_texture_util.h +++ b/source/blender/nodes/texture/node_texture_util.h @@ -108,8 +108,7 @@ typedef struct TexDelegate { bool tex_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree, const char **r_disabled_hint); -void tex_node_type_base( - struct bNodeType *ntype, int type, const char *name, short nclass, short flag); +void tex_node_type_base(struct bNodeType *ntype, int type, const char *name, short nclass); void tex_input_rgba(float *out, bNodeStack *in, TexParams *params, short thread); void tex_input_vec(float *out, bNodeStack *in, TexParams *params, short thread); @@ -121,10 +120,6 @@ void tex_output(bNode *node, bNodeStack *out, TexFn texfn, TexCallData *data); -void tex_do_preview(bNodePreview *preview, - const float coord[2], - const float col[4], - bool do_manage); void params_from_cdata(TexParams *out, TexCallData *in); diff --git a/source/blender/nodes/texture/nodes/node_texture_at.c b/source/blender/nodes/texture/nodes/node_texture_at.c index a6f8d28db75..41dea303ea2 100644 --- a/source/blender/nodes/texture/nodes/node_texture_at.c +++ b/source/blender/nodes/texture/nodes/node_texture_at.c @@ -58,7 +58,7 @@ void register_node_type_tex_at(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT, 0); + tex_node_type_base(&ntype, TEX_NODE_AT, "At", NODE_CLASS_DISTORT); node_type_socket_templates(&ntype, inputs, outputs); node_type_size(&ntype, 140, 100, 320); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_bricks.c b/source/blender/nodes/texture/nodes/node_texture_bricks.c index 72690d6ccfe..0dc92dc33d0 100644 --- a/source/blender/nodes/texture/nodes/node_texture_bricks.c +++ b/source/blender/nodes/texture/nodes/node_texture_bricks.c @@ -119,11 +119,12 @@ void register_node_type_tex_bricks(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_BRICKS, "Bricks", NODE_CLASS_PATTERN); node_type_socket_templates(&ntype, inputs, outputs); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, init); node_type_exec(&ntype, NULL, NULL, exec); + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_checker.c b/source/blender/nodes/texture/nodes/node_texture_checker.c index e3c4d44e7f5..62657cd7def 100644 --- a/source/blender/nodes/texture/nodes/node_texture_checker.c +++ b/source/blender/nodes/texture/nodes/node_texture_checker.c @@ -70,9 +70,10 @@ void register_node_type_tex_checker(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_CHECKER, "Checker", NODE_CLASS_PATTERN); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index f873ed5e457..b01353bcd21 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -161,7 +161,7 @@ void register_node_type_tex_group(void) /* NOTE: Cannot use #sh_node_type_base for node group, because it would map the node type * to the shared #NODE_GROUP integer type id. */ - node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP, 0); + node_type_base_custom(&ntype, "TextureNodeGroup", "Group", NODE_CLASS_GROUP); ntype.type = NODE_GROUP; ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; diff --git a/source/blender/nodes/texture/nodes/node_texture_compose.c b/source/blender/nodes/texture/nodes/node_texture_compose.c index ffa0e9ae43e..cd918ca8314 100644 --- a/source/blender/nodes/texture/nodes/node_texture_compose.c +++ b/source/blender/nodes/texture/nodes/node_texture_compose.c @@ -58,7 +58,7 @@ void register_node_type_tex_compose(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_COMPOSE, "Combine RGBA", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_coord.c b/source/blender/nodes/texture/nodes/node_texture_coord.c index 5a0cf5eb497..e31fdcafbf2 100644 --- a/source/blender/nodes/texture/nodes/node_texture_coord.c +++ b/source/blender/nodes/texture/nodes/node_texture_coord.c @@ -49,9 +49,8 @@ void register_node_type_tex_coord(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT, 0); + tex_node_type_base(&ntype, TEX_NODE_COORD, "Coordinates", NODE_CLASS_INPUT); node_type_socket_templates(&ntype, NULL, outputs); - node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_curves.c b/source/blender/nodes/texture/nodes/node_texture_curves.c index f61e3f36db5..7fed45c5558 100644 --- a/source/blender/nodes/texture/nodes/node_texture_curves.c +++ b/source/blender/nodes/texture/nodes/node_texture_curves.c @@ -65,7 +65,7 @@ void register_node_type_tex_curve_time(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT, 0); + tex_node_type_base(&ntype, TEX_NODE_CURVE_TIME, "Time", NODE_CLASS_INPUT); node_type_socket_templates(&ntype, NULL, time_outputs); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, time_init); @@ -114,7 +114,7 @@ void register_node_type_tex_curve_rgb(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_CURVE_RGB, "RGB Curves", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, rgb_inputs, rgb_outputs); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, rgb_init); diff --git a/source/blender/nodes/texture/nodes/node_texture_decompose.c b/source/blender/nodes/texture/nodes/node_texture_decompose.c index 83922ea03ab..9c3cb6911e1 100644 --- a/source/blender/nodes/texture/nodes/node_texture_decompose.c +++ b/source/blender/nodes/texture/nodes/node_texture_decompose.c @@ -78,7 +78,7 @@ void register_node_type_tex_decompose(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_DECOMPOSE, "Separate RGBA", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_distance.c b/source/blender/nodes/texture/nodes/node_texture_distance.c index c2241858737..2f8b28722bd 100644 --- a/source/blender/nodes/texture/nodes/node_texture_distance.c +++ b/source/blender/nodes/texture/nodes/node_texture_distance.c @@ -60,9 +60,8 @@ void register_node_type_tex_distance(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER, 0); + tex_node_type_base(&ntype, TEX_NODE_DISTANCE, "Distance", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, inputs, outputs); - node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c index 759fb3d43d5..f405c3b0bec 100644 --- a/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c +++ b/source/blender/nodes/texture/nodes/node_texture_hueSatVal.c @@ -107,7 +107,7 @@ void register_node_type_tex_hue_sat(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_HUE_SAT, "Hue Saturation Value", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_image.c b/source/blender/nodes/texture/nodes/node_texture_image.c index 9c61405ea23..18ae3609407 100644 --- a/source/blender/nodes/texture/nodes/node_texture_image.c +++ b/source/blender/nodes/texture/nodes/node_texture_image.c @@ -108,12 +108,13 @@ void register_node_type_tex_image(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_IMAGE, "Image", NODE_CLASS_INPUT); node_type_socket_templates(&ntype, NULL, outputs); node_type_init(&ntype, init); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); node_type_exec(&ntype, NULL, NULL, exec); ntype.labelfunc = node_image_label; + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_invert.c b/source/blender/nodes/texture/nodes/node_texture_invert.c index 5d3f86c5c9c..7854ac4b5b8 100644 --- a/source/blender/nodes/texture/nodes/node_texture_invert.c +++ b/source/blender/nodes/texture/nodes/node_texture_invert.c @@ -63,7 +63,7 @@ void register_node_type_tex_invert(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_INVERT, "Invert", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_math.c b/source/blender/nodes/texture/nodes/node_texture_math.c index 9e37f4ee643..2f50f6aaae0 100644 --- a/source/blender/nodes/texture/nodes/node_texture_math.c +++ b/source/blender/nodes/texture/nodes/node_texture_math.c @@ -335,10 +335,9 @@ void register_node_type_tex_math(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER, 0); + tex_node_type_base(&ntype, TEX_NODE_MATH, "Math", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, inputs, outputs); ntype.labelfunc = node_math_label; - node_type_storage(&ntype, "", NULL, NULL); node_type_exec(&ntype, NULL, NULL, exec); node_type_update(&ntype, node_math_update); diff --git a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c index 044875cce90..5599807d8b1 100644 --- a/source/blender/nodes/texture/nodes/node_texture_mixRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_mixRgb.c @@ -69,7 +69,7 @@ void register_node_type_tex_mix_rgb(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR, 0); + tex_node_type_base(&ntype, TEX_NODE_MIX_RGB, "Mix", NODE_CLASS_OP_COLOR); node_type_socket_templates(&ntype, inputs, outputs); ntype.labelfunc = node_blend_label; node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index 19e24c9f82a..4911ab7ba9e 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -37,7 +37,7 @@ static bNodeSocketTemplate inputs[] = { static void exec(void *data, int UNUSED(thread), bNode *node, - bNodeExecData *execdata, + bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **UNUSED(out)) { @@ -54,7 +54,6 @@ static void exec(void *data, else { tex_input_rgba(&target->tr, in[0], ¶ms, cdata->thread); } - tex_do_preview(execdata->preview, params.co, &target->tr, cdata->do_manage); } else { /* 0 means don't care, so just use first */ @@ -167,13 +166,14 @@ void register_node_type_tex_output(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_OUTPUT, "Output", NODE_CLASS_OUTPUT); node_type_socket_templates(&ntype, inputs, NULL); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_init(&ntype, init); node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy); node_type_exec(&ntype, NULL, NULL, exec); + ntype.flag |= NODE_PREVIEW; ntype.no_muting = true; nodeRegisterType(&ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_proc.c b/source/blender/nodes/texture/nodes/node_texture_proc.c index a8a82153e58..8c294b5954d 100644 --- a/source/blender/nodes/texture/nodes/node_texture_proc.c +++ b/source/blender/nodes/texture/nodes/node_texture_proc.c @@ -294,12 +294,13 @@ static void init(bNodeTree *UNUSED(ntree), bNode *node) { \ static bNodeType ntype; \ \ - tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE, NODE_PREVIEW); \ + tex_node_type_base(&ntype, TEX_NODE_PROC + TEXTYPE, Name, NODE_CLASS_TEXTURE); \ node_type_socket_templates(&ntype, name##_inputs, outputs); \ node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); \ node_type_init(&ntype, init); \ node_type_storage(&ntype, "Tex", node_free_standard_storage, node_copy_standard_storage); \ node_type_exec(&ntype, NULL, NULL, name##_exec); \ + ntype.flag |= NODE_PREVIEW; \ \ nodeRegisterType(&ntype); \ } diff --git a/source/blender/nodes/texture/nodes/node_texture_rotate.c b/source/blender/nodes/texture/nodes/node_texture_rotate.c index 9985499772e..18024a4d41d 100644 --- a/source/blender/nodes/texture/nodes/node_texture_rotate.c +++ b/source/blender/nodes/texture/nodes/node_texture_rotate.c @@ -95,7 +95,7 @@ void register_node_type_tex_rotate(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT, 0); + tex_node_type_base(&ntype, TEX_NODE_ROTATE, "Rotate", NODE_CLASS_DISTORT); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_scale.c b/source/blender/nodes/texture/nodes/node_texture_scale.c index d23b1b4d037..d570c73a67b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_scale.c +++ b/source/blender/nodes/texture/nodes/node_texture_scale.c @@ -68,7 +68,7 @@ void register_node_type_tex_scale(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT, 0); + tex_node_type_base(&ntype, TEX_NODE_SCALE, "Scale", NODE_CLASS_DISTORT); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_texture.c b/source/blender/nodes/texture/nodes/node_texture_texture.c index 59e2e9be581..083ae67ccb6 100644 --- a/source/blender/nodes/texture/nodes/node_texture_texture.c +++ b/source/blender/nodes/texture/nodes/node_texture_texture.c @@ -94,9 +94,10 @@ void register_node_type_tex_texture(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_TEXTURE, "Texture", NODE_CLASS_INPUT); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_translate.c b/source/blender/nodes/texture/nodes/node_texture_translate.c index 2eef3132a18..732cd0a89a1 100644 --- a/source/blender/nodes/texture/nodes/node_texture_translate.c +++ b/source/blender/nodes/texture/nodes/node_texture_translate.c @@ -64,7 +64,7 @@ void register_node_type_tex_translate(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT, 0); + tex_node_type_base(&ntype, TEX_NODE_TRANSLATE, "Translate", NODE_CLASS_DISTORT); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_valToNor.c b/source/blender/nodes/texture/nodes/node_texture_valToNor.c index 5ccd44b8bf0..3f0d4fb668e 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToNor.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToNor.c @@ -80,7 +80,7 @@ void register_node_type_tex_valtonor(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER, 0); + tex_node_type_base(&ntype, TEX_NODE_VALTONOR, "Value to Normal", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c index 2446ef05e0c..844a4188663 100644 --- a/source/blender/nodes/texture/nodes/node_texture_valToRgb.c +++ b/source/blender/nodes/texture/nodes/node_texture_valToRgb.c @@ -63,7 +63,7 @@ void register_node_type_tex_valtorgb(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER, 0); + tex_node_type_base(&ntype, TEX_NODE_VALTORGB, "ColorRamp", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, valtorgb_in, valtorgb_out); node_type_size_preset(&ntype, NODE_SIZE_LARGE); node_type_init(&ntype, valtorgb_init); @@ -105,7 +105,7 @@ void register_node_type_tex_rgbtobw(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER, 0); + tex_node_type_base(&ntype, TEX_NODE_RGBTOBW, "RGB to BW", NODE_CLASS_CONVERTER); node_type_socket_templates(&ntype, rgbtobw_in, rgbtobw_out); node_type_exec(&ntype, NULL, NULL, rgbtobw_exec); diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c index 18b11b86d6f..e40cdb66cb1 100644 --- a/source/blender/nodes/texture/nodes/node_texture_viewer.c +++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c @@ -36,7 +36,7 @@ static bNodeSocketTemplate outputs[] = { static void exec(void *data, int UNUSED(thread), bNode *UNUSED(node), - bNodeExecData *execdata, + bNodeExecData *UNUSED(execdata), bNodeStack **in, bNodeStack **UNUSED(out)) { @@ -48,7 +48,6 @@ static void exec(void *data, params_from_cdata(¶ms, cdata); tex_input_rgba(col, in[0], ¶ms, cdata->thread); - tex_do_preview(execdata->preview, params.previewco, col, cdata->do_manage); } } @@ -56,11 +55,12 @@ void register_node_type_tex_viewer(void) { static bNodeType ntype; - tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, NODE_PREVIEW); + tex_node_type_base(&ntype, TEX_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT); node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); ntype.no_muting = true; + ntype.flag |= NODE_PREVIEW; nodeRegisterType(&ntype); } diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index 48fbe09f0ce..19013dc9ca3 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -65,6 +65,14 @@ /** \name GPUOffScreen Common Utilities * \{ */ +static const struct PyC_StringEnumItems pygpu_framebuffer_color_texture_formats[] = { + {GPU_RGBA8, "RGBA8"}, + {GPU_RGBA16, "RGBA16"}, + {GPU_RGBA16F, "RGBA16F"}, + {GPU_RGBA32F, "RGBA32F"}, + {0, NULL}, +}; + static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs) { if (UNLIKELY(py_ofs->ofs == NULL)) { @@ -219,16 +227,18 @@ static PyObject *pygpu_offscreen__tp_new(PyTypeObject *UNUSED(self), GPUOffScreen *ofs = NULL; int width, height; + struct PyC_StringEnum pygpu_textureformat = {pygpu_framebuffer_color_texture_formats, GPU_RGBA8}; char err_out[256]; - static const char *_keywords[] = {"width", "height", NULL}; - static _PyArg_Parser _parser = {"ii:GPUOffScreen.__new__", _keywords, 0}; - if (!_PyArg_ParseTupleAndKeywordsFast(args, kwds, &_parser, &width, &height)) { + static const char *_keywords[] = {"width", "height", "format", NULL}; + static _PyArg_Parser _parser = {"ii|$O&:GPUOffScreen.__new__", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kwds, &_parser, &width, &height, PyC_ParseStringEnum, &pygpu_textureformat)) { return NULL; } if (GPU_context_active_get()) { - ofs = GPU_offscreen_create(width, height, true, GPU_RGBA8, err_out); + ofs = GPU_offscreen_create(width, height, true, pygpu_textureformat.value_found, err_out); } else { STRNCPY(err_out, "No active GPU context found"); @@ -456,14 +466,21 @@ static struct PyMethodDef pygpu_offscreen__tp_methods[] = { }; PyDoc_STRVAR(pygpu_offscreen__tp_doc, - ".. class:: GPUOffScreen(width, height)\n" + ".. class:: GPUOffScreen(width, height, *, format='RGBA8')\n" "\n" " This object gives access to off screen buffers.\n" "\n" " :arg width: Horizontal dimension of the buffer.\n" " :type width: int\n" " :arg height: Vertical dimension of the buffer.\n" - " :type height: int\n"); + " :type height: int\n" + " :arg format: Internal data format inside GPU memory for color attachment " + "texture. Possible values are:\n" + " `RGBA8`,\n" + " `RGBA16`,\n" + " `RGBA16F`,\n" + " `RGBA32F`,\n" + " :type format: str\n"); PyTypeObject BPyGPUOffScreen_Type = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "GPUOffScreen", .tp_basicsize = sizeof(BPyGPUOffScreen), diff --git a/source/blender/render/intern/pipeline.c b/source/blender/render/intern/pipeline.c index a800361a41f..721abe45932 100644 --- a/source/blender/render/intern/pipeline.c +++ b/source/blender/render/intern/pipeline.c @@ -1131,7 +1131,7 @@ static void do_render_compositor_scenes(Render *re) render_scene_has_layers_to_render(scene, false)) { do_render_compositor_scene(re, scene, cfra); BLI_gset_add(scenes_rendered, scene); - nodeUpdate(restore_scene->nodetree, node); + node->typeinfo->updatefunc(restore_scene->nodetree, node); } } } @@ -1821,7 +1821,7 @@ void RE_RenderFrame(Render *re, render_callback_exec_id(re, re->main, &scene->id, BKE_CB_EVT_RENDER_INIT); /* Ugly global still... - * is to prevent preview events and signal subsurfs etc to make full resol. */ + * is to prevent preview events and signal subdivision-surface etc to make full resolution. */ G.is_rendering = true; scene->r.cfra = frame; @@ -2331,8 +2331,8 @@ void RE_RenderAnim(Render *re, } } - /* Ugly global still... is to prevent renderwin events and signal subsurfs etc to make full resol - * is also set by caller renderwin.c */ + /* Ugly global still... is to prevent renderwin events and signal subdivision-surface etc + * to make full resolution is also set by caller renderwin.c */ G.is_rendering = true; re->flag |= R_ANIMATION; diff --git a/source/blender/render/intern/render_result.c b/source/blender/render/intern/render_result.c index a21351539f6..5455b2d883a 100644 --- a/source/blender/render/intern/render_result.c +++ b/source/blender/render/intern/render_result.c @@ -470,6 +470,12 @@ RenderResult *render_result_new(Render *re, void render_result_passes_allocated_ensure(RenderResult *rr) { + if (rr == NULL) { + /* Happens when the result was not yet allocated for the current scene or slot configuration. + */ + return; + } + LISTBASE_FOREACH (RenderLayer *, rl, &rr->layers) { LISTBASE_FOREACH (RenderPass *, rp, &rl->passes) { if (rl->exrhandle != NULL && !STREQ(rp->name, RE_PASSNAME_COMBINED)) { diff --git a/source/blender/sequencer/SEQ_effects.h b/source/blender/sequencer/SEQ_effects.h index 4bd5b54b36b..87a8288a593 100644 --- a/source/blender/sequencer/SEQ_effects.h +++ b/source/blender/sequencer/SEQ_effects.h @@ -68,10 +68,10 @@ struct SeqEffectHandle { * 0: no early out, * 1: out = ibuf1, * 2: out = ibuf2 */ - int (*early_out)(struct Sequence *seq, float facf0, float facf1); + int (*early_out)(struct Sequence *seq, float fac); - /* stores the default facf0 and facf1 if no IPO is present */ - void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *facf0, float *facf1); + /* sets the default `fac` value */ + void (*get_default_fac)(struct Sequence *seq, float timeline_frame, float *fac); /* execute the effect * sequence effects are only required to either support @@ -81,8 +81,7 @@ struct SeqEffectHandle { struct ImBuf *(*execute)(const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, struct ImBuf *ibuf1, struct ImBuf *ibuf2, struct ImBuf *ibuf3); @@ -95,8 +94,7 @@ struct SeqEffectHandle { void (*execute_slice)(const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, struct ImBuf *ibuf1, struct ImBuf *ibuf2, struct ImBuf *ibuf3, diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index 05ce35deeec..8776bc63cf0 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -206,69 +206,22 @@ static void init_alpha_over_or_under(Sequence *seq) seq->seq1 = seq2; } -static void do_alphaover_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - float fac2, mfac, fac, fac4; - int xo; - unsigned char *cp1, *cp2, *rt; - float tempc[4], rt1[4], rt2[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { - /* rt = rt1 over rt2 (alpha from rt1) */ - - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); - - fac = fac2; - mfac = 1.0f - fac2 * rt1[3]; - - if (fac <= 0.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else if (mfac <= 0.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp1); - } - else { - tempc[0] = fac * rt1[0] + mfac * rt2[0]; - tempc[1] = fac * rt1[1] + mfac * rt2[1]; - tempc[2] = fac * rt1[2] + mfac * rt2[2]; - tempc[3] = fac * rt1[3] + mfac * rt2[3]; - - premul_float_to_straight_uchar(rt, tempc); - } - cp1 += 4; - cp2 += 4; - rt += 4; - } +static void do_alphaover_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - if (y == 0) { - break; - } - y--; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + /* rt = rt1 over rt2 (alpha from rt1) */ - x = xo; - while (x--) { + float tempc[4], rt1[4], rt2[4]; straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); - fac = fac4; - mfac = 1.0f - (fac4 * rt1[3]); + float mfac = 1.0f - fac * rt1[3]; if (fac <= 0.0f) { *((unsigned int *)rt) = *((unsigned int *)cp2); @@ -292,27 +245,17 @@ static void do_alphaover_effect_byte(float facf0, } static void do_alphaover_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac2, mfac, fac, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 over rt2 (alpha from rt1) */ - fac = fac2; - mfac = 1.0f - (fac2 * rt1[3]); + float mfac = 1.0f - (fac * rt1[3]); if (fac <= 0.0f) { memcpy(rt, rt2, sizeof(float[4])); @@ -330,41 +273,13 @@ static void do_alphaover_effect_float( rt2 += 4; rt += 4; } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - fac = fac4; - mfac = 1.0f - (fac4 * rt1[3]); - - if (fac <= 0.0f) { - memcpy(rt, rt2, sizeof(float[4])); - } - else if (mfac <= 0.0f) { - memcpy(rt, rt1, sizeof(float[4])); - } - else { - rt[0] = fac * rt1[0] + mfac * rt2[0]; - rt[1] = fac * rt1[1] + mfac * rt2[1]; - rt[2] = fac * rt1[2] + mfac * rt2[2]; - rt[3] = fac * rt1[3] + mfac * rt2[3]; - } - rt1 += 4; - rt2 += 4; - rt += 4; - } } } static void do_alphaover_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -378,7 +293,7 @@ static void do_alphaover_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaover_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -386,96 +301,47 @@ static void do_alphaover_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaover_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaover_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Alpha Under *************************/ -static void do_alphaunder_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - float fac2, fac, fac4; - int xo; - unsigned char *cp1, *cp2, *rt; - float tempc[4], rt1[4], rt2[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; - - while (y--) { - x = xo; - while (x--) { +static void do_alphaunder_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 under rt2 (alpha from rt2) */ + + float tempc[4], rt1[4], rt2[4]; straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); /* this complex optimization is because the * 'skybuf' can be crossed in */ - if (rt2[3] <= 0.0f && fac2 >= 1.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp1); - } - else if (rt2[3] >= 1.0f) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else { - fac = (fac2 * (1.0f - rt2[3])); - - if (fac <= 0) { - *((unsigned int *)rt) = *((unsigned int *)cp2); - } - else { - tempc[0] = (fac * rt1[0] + rt2[0]); - tempc[1] = (fac * rt1[1] + rt2[1]); - tempc[2] = (fac * rt1[2] + rt2[2]); - tempc[3] = (fac * rt1[3] + rt2[3]); - - premul_float_to_straight_uchar(rt, tempc); - } - } - cp1 += 4; - cp2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); - - if (rt2[3] <= 0.0f && fac4 >= 1.0f) { + if (rt2[3] <= 0.0f && fac >= 1.0f) { *((unsigned int *)rt) = *((unsigned int *)cp1); } else if (rt2[3] >= 1.0f) { *((unsigned int *)rt) = *((unsigned int *)cp2); } else { - fac = (fac4 * (1.0f - rt2[3])); + float temp_fac = (fac * (1.0f - rt2[3])); if (fac <= 0) { *((unsigned int *)rt) = *((unsigned int *)cp2); } else { - tempc[0] = (fac * rt1[0] + rt2[0]); - tempc[1] = (fac * rt1[1] + rt2[1]); - tempc[2] = (fac * rt1[2] + rt2[2]); - tempc[3] = (fac * rt1[3] + rt2[3]); + tempc[0] = (temp_fac * rt1[0] + rt2[0]); + tempc[1] = (temp_fac * rt1[1] + rt2[1]); + tempc[2] = (temp_fac * rt1[2] + rt2[2]); + tempc[3] = (temp_fac * rt1[3] + rt2[3]); premul_float_to_straight_uchar(rt, tempc); } @@ -488,76 +354,36 @@ static void do_alphaunder_effect_byte(float facf0, } static void do_alphaunder_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac2, fac, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac2 = facf0; - fac4 = facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - while (y--) { - x = xo; - while (x--) { + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { /* rt = rt1 under rt2 (alpha from rt2) */ /* this complex optimization is because the * 'skybuf' can be crossed in */ - if (rt2[3] <= 0 && fac2 >= 1.0f) { + if (rt2[3] <= 0 && fac >= 1.0f) { memcpy(rt, rt1, sizeof(float[4])); } else if (rt2[3] >= 1.0f) { memcpy(rt, rt2, sizeof(float[4])); } else { - fac = fac2 * (1.0f - rt2[3]); + float temp_fac = fac * (1.0f - rt2[3]); if (fac == 0) { memcpy(rt, rt2, sizeof(float[4])); } else { - rt[0] = fac * rt1[0] + rt2[0]; - rt[1] = fac * rt1[1] + rt2[1]; - rt[2] = fac * rt1[2] + rt2[2]; - rt[3] = fac * rt1[3] + rt2[3]; - } - } - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - if (rt2[3] <= 0 && fac4 >= 1.0f) { - memcpy(rt, rt1, sizeof(float[4])); - } - else if (rt2[3] >= 1.0f) { - memcpy(rt, rt2, sizeof(float[4])); - } - else { - fac = fac4 * (1.0f - rt2[3]); - - if (fac == 0) { - memcpy(rt, rt2, sizeof(float[4])); - } - else { - rt[0] = fac * rt1[0] + rt2[0]; - rt[1] = fac * rt1[1] + rt2[1]; - rt[2] = fac * rt1[2] + rt2[2]; - rt[3] = fac * rt1[3] + rt2[3]; + rt[0] = temp_fac * rt1[0] + rt2[0]; + rt[1] = temp_fac * rt1[1] + rt2[1]; + rt[2] = temp_fac * rt1[2] + rt2[2]; + rt[3] = temp_fac * rt1[3] + rt2[3]; } } rt1 += 4; @@ -570,8 +396,7 @@ static void do_alphaunder_effect_float( static void do_alphaunder_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -585,7 +410,7 @@ static void do_alphaunder_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaunder_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -593,58 +418,28 @@ static void do_alphaunder_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_alphaunder_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_alphaunder_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Cross *************************/ -static void do_cross_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_cross_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int fac1, fac2, fac3, fac4; - int xo; - unsigned char *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac2 = (int)(256.0f * facf0); - fac1 = 256 - fac2; - fac4 = (int)(256.0f * facf1); - fac3 = 256 - fac4; - - while (y--) { - x = xo; - while (x--) { - rt[0] = (fac1 * rt1[0] + fac2 * rt2[0]) >> 8; - rt[1] = (fac1 * rt1[1] + fac2 * rt2[1]) >> 8; - rt[2] = (fac1 * rt1[2] + fac2 * rt2[2]) >> 8; - rt[3] = (fac1 * rt1[3] + fac2 * rt2[3]) >> 8; - - rt1 += 4; - rt2 += 4; - rt += 4; - } + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; - if (y == 0) { - break; - } - y--; + int temp_fac = (int)(256.0f * fac); + int temp_mfac = 256 - temp_fac; - x = xo; - while (x--) { - rt[0] = (fac3 * rt1[0] + fac4 * rt2[0]) >> 8; - rt[1] = (fac3 * rt1[1] + fac4 * rt2[1]) >> 8; - rt[2] = (fac3 * rt1[2] + fac4 * rt2[2]) >> 8; - rt[3] = (fac3 * rt1[3] + fac4 * rt2[3]) >> 8; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = (temp_mfac * rt1[0] + temp_fac * rt2[0]) >> 8; + rt[1] = (temp_mfac * rt1[1] + temp_fac * rt2[1]) >> 8; + rt[2] = (temp_mfac * rt1[2] + temp_fac * rt2[2]) >> 8; + rt[3] = (temp_mfac * rt1[3] + temp_fac * rt2[3]) >> 8; rt1 += 4; rt2 += 4; @@ -653,47 +448,20 @@ static void do_cross_effect_byte(float facf0, } } -static void do_cross_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_cross_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac1, fac2, fac3, fac4; - int xo; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac2 = facf0; - fac1 = 1.0f - fac2; - fac4 = facf1; - fac3 = 1.0f - fac4; - - while (y--) { - x = xo; - while (x--) { - rt[0] = fac1 * rt1[0] + fac2 * rt2[0]; - rt[1] = fac1 * rt1[1] + fac2 * rt2[1]; - rt[2] = fac1 * rt1[2] + fac2 * rt2[2]; - rt[3] = fac1 * rt1[3] + fac2 * rt2[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - if (y == 0) { - break; - } - y--; + float mfac = 1.0f - fac; - x = xo; - while (x--) { - rt[0] = fac3 * rt1[0] + fac4 * rt2[0]; - rt[1] = fac3 * rt1[1] + fac4 * rt2[1]; - rt[2] = fac3 * rt1[2] + fac4 * rt2[2]; - rt[3] = fac3 * rt1[3] + fac4 * rt2[3]; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = mfac * rt1[0] + fac * rt2[0]; + rt[1] = mfac * rt1[1] + fac * rt2[1]; + rt[2] = mfac * rt1[2] + fac * rt2[2]; + rt[3] = mfac * rt1[3] + fac * rt2[3]; rt1 += 4; rt2 += 4; @@ -705,8 +473,7 @@ static void do_cross_effect_float( static void do_cross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -720,7 +487,7 @@ static void do_cross_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_cross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -728,7 +495,7 @@ static void do_cross_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_cross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_cross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -888,58 +655,26 @@ static void free_gammacross(Sequence *UNUSED(seq), const bool UNUSED(do_id_user) { } -static void do_gammacross_effect_byte(float facf0, - float UNUSED(facf1), - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_gammacross_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - float fac1, fac2; - int xo; - unsigned char *cp1, *cp2, *rt; - float rt1[4], rt2[4], tempc[4]; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac2 = facf0; - fac1 = 1.0f - fac2; + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - while (y--) { - x = xo; - while (x--) { - straight_uchar_to_premul_float(rt1, cp1); - straight_uchar_to_premul_float(rt2, cp2); + float mfac = 1.0f - fac; - tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); - tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); - tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); - tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float rt1[4], rt2[4], tempc[4]; - premul_float_to_straight_uchar(rt, tempc); - cp1 += 4; - cp2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { straight_uchar_to_premul_float(rt1, cp1); straight_uchar_to_premul_float(rt2, cp2); - tempc[0] = gammaCorrect(fac1 * invGammaCorrect(rt1[0]) + fac2 * invGammaCorrect(rt2[0])); - tempc[1] = gammaCorrect(fac1 * invGammaCorrect(rt1[1]) + fac2 * invGammaCorrect(rt2[1])); - tempc[2] = gammaCorrect(fac1 * invGammaCorrect(rt1[2]) + fac2 * invGammaCorrect(rt2[2])); - tempc[3] = gammaCorrect(fac1 * invGammaCorrect(rt1[3]) + fac2 * invGammaCorrect(rt2[3])); + tempc[0] = gammaCorrect(mfac * invGammaCorrect(rt1[0]) + fac * invGammaCorrect(rt2[0])); + tempc[1] = gammaCorrect(mfac * invGammaCorrect(rt1[1]) + fac * invGammaCorrect(rt2[1])); + tempc[2] = gammaCorrect(mfac * invGammaCorrect(rt1[2]) + fac * invGammaCorrect(rt2[2])); + tempc[3] = gammaCorrect(mfac * invGammaCorrect(rt1[3]) + fac * invGammaCorrect(rt2[3])); premul_float_to_straight_uchar(rt, tempc); cp1 += 4; @@ -950,38 +685,17 @@ static void do_gammacross_effect_byte(float facf0, } static void do_gammacross_effect_float( - float facf0, float UNUSED(facf1), int x, int y, float *rect1, float *rect2, float *out) + float fac, int x, int y, float *rect1, float *rect2, float *out) { - float fac1, fac2; - int xo; - float *rt1, *rt2, *rt; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac2 = facf0; - fac1 = 1.0f - fac2; - - while (y--) { - x = xo * 4; - while (x--) { - *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2)); - rt1++; - rt2++; - rt++; - } - - if (y == 0) { - break; - } - y--; - - x = xo * 4; - while (x--) { - *rt = gammaCorrect(fac1 * invGammaCorrect(*rt1) + fac2 * invGammaCorrect(*rt2)); + float mfac = 1.0f - fac; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + *rt = gammaCorrect(mfac * invGammaCorrect(*rt1) + fac * invGammaCorrect(*rt2)); rt1++; rt2++; rt++; @@ -1003,8 +717,7 @@ static struct ImBuf *gammacross_init_execution(const SeqRenderData *context, static void do_gammacross_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1018,7 +731,7 @@ static void do_gammacross_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_gammacross_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_gammacross_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1026,57 +739,27 @@ static void do_gammacross_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_gammacross_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_gammacross_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Add *************************/ -static void do_add_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - int xo, fac1, fac3; - unsigned char *cp1, *cp2, *rt; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); - - while (y--) { - x = xo; - - while (x--) { - const int m = fac1 * (int)cp2[3]; - rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); - rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); - rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); - rt[3] = cp1[3]; +static void do_add_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - cp1 += 4; - cp2 += 4; - rt += 4; - } + int temp_fac = (int)(256.0f * fac); - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const int m = fac3 * (int)cp2[3]; - rt[0] = min_ii(cp1[0] + ((m * cp2[0]) >> 16), 255); - rt[1] = min_ii(cp1[1] + ((m * cp2[1]) >> 16), 255); - rt[2] = min_ii(cp1[2] + ((m * cp2[2]) >> 16), 255); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const int temp_fac2 = temp_fac * (int)cp2[3]; + rt[0] = min_ii(cp1[0] + ((temp_fac2 * cp2[0]) >> 16), 255); + rt[1] = min_ii(cp1[1] + ((temp_fac2 * cp2[1]) >> 16), 255); + rt[2] = min_ii(cp1[2] + ((temp_fac2 * cp2[2]) >> 16), 255); rt[3] = cp1[3]; cp1 += 4; @@ -1086,46 +769,18 @@ static void do_add_effect_byte(float facf0, } } -static void do_add_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_add_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float fac1, fac3; - float *rt1, *rt2, *rt; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac1 = facf0; - fac3 = facf1; - - while (y--) { - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * (1.0f - fac1))) * rt2[3]; - rt[0] = rt1[0] + m * rt2[0]; - rt[1] = rt1[1] + m * rt2[1]; - rt[2] = rt1[2] + m * rt2[2]; - rt[3] = rt1[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * (1.0f - fac3))) * rt2[3]; - rt[0] = rt1[0] + m * rt2[0]; - rt[1] = rt1[1] + m * rt2[1]; - rt[2] = rt1[2] + m * rt2[2]; + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const float temp_fac = (1.0f - (rt1[3] * (1.0f - fac))) * rt2[3]; + rt[0] = rt1[0] + temp_fac * rt2[0]; + rt[1] = rt1[1] + temp_fac * rt2[1]; + rt[2] = rt1[2] + temp_fac * rt2[2]; rt[3] = rt1[3]; rt1 += 4; @@ -1138,8 +793,7 @@ static void do_add_effect_float( static void do_add_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1153,7 +807,7 @@ static void do_add_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_add_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_add_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1161,56 +815,27 @@ static void do_add_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_add_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_add_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } /*********************** Sub *************************/ -static void do_sub_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) -{ - int xo, fac1, fac3; - unsigned char *cp1, *cp2, *rt; - - xo = x; - cp1 = rect1; - cp2 = rect2; - rt = out; - - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); - - while (y--) { - x = xo; - while (x--) { - const int m = fac1 * (int)cp2[3]; - rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); - rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); - rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); - rt[3] = cp1[3]; +static void do_sub_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) +{ + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - cp1 += 4; - cp2 += 4; - rt += 4; - } + int temp_fac = (int)(256.0f * fac); - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const int m = fac3 * (int)cp2[3]; - rt[0] = max_ii(cp1[0] - ((m * cp2[0]) >> 16), 0); - rt[1] = max_ii(cp1[1] - ((m * cp2[1]) >> 16), 0); - rt[2] = max_ii(cp1[2] - ((m * cp2[2]) >> 16), 0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const int temp_fac2 = temp_fac * (int)cp2[3]; + rt[0] = max_ii(cp1[0] - ((temp_fac2 * cp2[0]) >> 16), 0); + rt[1] = max_ii(cp1[1] - ((temp_fac2 * cp2[1]) >> 16), 0); + rt[2] = max_ii(cp1[2] - ((temp_fac2 * cp2[2]) >> 16), 0); rt[3] = cp1[3]; cp1 += 4; @@ -1220,47 +845,20 @@ static void do_sub_effect_byte(float facf0, } } -static void do_sub_effect_float( - float UNUSED(facf0), float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_sub_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float /* fac1, */ fac3_inv; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - /* UNUSED */ - // fac1 = facf0; - fac3_inv = 1.0f - facf1; + float mfac = 1.0f - fac; - while (y--) { - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; - rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); - rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); - rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); - rt[3] = rt1[3]; - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - const float m = (1.0f - (rt1[3] * fac3_inv)) * rt2[3]; - rt[0] = max_ff(rt1[0] - m * rt2[0], 0.0f); - rt[1] = max_ff(rt1[1] - m * rt2[1], 0.0f); - rt[2] = max_ff(rt1[2] - m * rt2[2], 0.0f); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + const float temp_fac = (1.0f - (rt1[3] * mfac)) * rt2[3]; + rt[0] = max_ff(rt1[0] - temp_fac * rt2[0], 0.0f); + rt[1] = max_ff(rt1[1] - temp_fac * rt2[1], 0.0f); + rt[2] = max_ff(rt1[2] - temp_fac * rt2[2], 0.0f); rt[3] = rt1[3]; rt1 += 4; @@ -1273,8 +871,7 @@ static void do_sub_effect_float( static void do_sub_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1288,7 +885,7 @@ static void do_sub_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_sub_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1296,7 +893,7 @@ static void do_sub_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_sub_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_sub_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -1306,161 +903,95 @@ static void do_sub_effect(const SeqRenderData *context, #define XOFF 8 #define YOFF 8 -static void do_drop_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect2i, - unsigned char *rect1i, - unsigned char *outi) -{ - int temp, fac, fac1, fac2; - unsigned char *rt1, *rt2, *out; - int field = 1; - - const int width = x; - const int height = y; - const int xoff = min_ii(XOFF, width); - const int yoff = min_ii(YOFF, height); - - fac1 = (int)(70.0f * facf0); - fac2 = (int)(70.0f * facf1); - - rt2 = rect2i + yoff * 4 * width; - rt1 = rect1i; - out = outi; - for (y = 0; y < height - yoff; y++) { - if (field) { - fac = fac1; - } - else { - fac = fac2; - } - field = !field; +static void do_drop_effect_byte( + float fac, int x, int y, unsigned char *rect2i, unsigned char *rect1i, unsigned char *outi) +{ + const int xoff = min_ii(XOFF, x); + const int yoff = min_ii(YOFF, y); + + int temp_fac = (int)(70.0f * fac); + unsigned char *rt2 = rect2i + yoff * 4 * x; + unsigned char *rt1 = rect1i; + unsigned char *out = outi; + for (int i = 0; i < y - yoff; i++) { memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; - for (x = xoff; x < width; x++) { - temp = ((fac * rt2[3]) >> 8); + for (int j = xoff; j < x; j++) { + int temp_fac2 = ((temp_fac * rt2[3]) >> 8); - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0, *rt1 - temp); + *(out++) = MAX2(0, *rt1 - temp_fac2); rt1++; rt2 += 4; } rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * x); } static void do_drop_effect_float( - float facf0, float facf1, int x, int y, float *rect2i, float *rect1i, float *outi) -{ - float temp, fac, fac1, fac2; - float *rt1, *rt2, *out; - int field = 1; - - const int width = x; - const int height = y; - const int xoff = min_ii(XOFF, width); - const int yoff = min_ii(YOFF, height); - - fac1 = 70.0f * facf0; - fac2 = 70.0f * facf1; - - rt2 = rect2i + yoff * 4 * width; - rt1 = rect1i; - out = outi; - for (y = 0; y < height - yoff; y++) { - if (field) { - fac = fac1; - } - else { - fac = fac2; - } - field = !field; + float fac, int x, int y, float *rect2i, float *rect1i, float *outi) +{ + const int xoff = min_ii(XOFF, x); + const int yoff = min_ii(YOFF, y); + + float temp_fac = 70.0f * fac; + float *rt2 = rect2i + yoff * 4 * x; + float *rt1 = rect1i; + float *out = outi; + for (int i = 0; i < y - yoff; i++) { memcpy(out, rt1, sizeof(*out) * xoff * 4); rt1 += xoff * 4; out += xoff * 4; - for (x = xoff; x < width; x++) { - temp = fac * rt2[3]; + for (int j = xoff; j < x; j++) { + float temp_fac2 = temp_fac * rt2[3]; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; - *(out++) = MAX2(0.0f, *rt1 - temp); + *(out++) = MAX2(0.0f, *rt1 - temp_fac2); rt1++; rt2 += 4; } rt2 += xoff * 4; } - memcpy(out, rt1, sizeof(*out) * yoff * 4 * width); + memcpy(out, rt1, sizeof(*out) * yoff * 4 * x); } /*********************** Mul *************************/ -static void do_mul_effect_byte(float facf0, - float facf1, - int x, - int y, - unsigned char *rect1, - unsigned char *rect2, - unsigned char *out) +static void do_mul_effect_byte( + float fac, int x, int y, unsigned char *rect1, unsigned char *rect2, unsigned char *out) { - int xo, fac1, fac3; - unsigned char *rt1, *rt2, *rt; + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac1 = (int)(256.0f * facf0); - fac3 = (int)(256.0f * facf1); + int temp_fac = (int)(256.0f * fac); /* Formula: * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + axaux = c * px + py * s;` // + centx * `yaux = -s * px + c * py;` // + centy */ - while (y--) { - - x = xo; - while (x--) { - - rt[0] = rt1[0] + ((fac1 * rt1[0] * (rt2[0] - 255)) >> 16); - rt[1] = rt1[1] + ((fac1 * rt1[1] * (rt2[1] - 255)) >> 16); - rt[2] = rt1[2] + ((fac1 * rt1[2] * (rt2[2] - 255)) >> 16); - rt[3] = rt1[3] + ((fac1 * rt1[3] * (rt2[3] - 255)) >> 16); - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - - rt[0] = rt1[0] + ((fac3 * rt1[0] * (rt2[0] - 255)) >> 16); - rt[1] = rt1[1] + ((fac3 * rt1[1] * (rt2[1] - 255)) >> 16); - rt[2] = rt1[2] + ((fac3 * rt1[2] * (rt2[2] - 255)) >> 16); - rt[3] = rt1[3] + ((fac3 * rt1[3] * (rt2[3] - 255)) >> 16); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = rt1[0] + ((temp_fac * rt1[0] * (rt2[0] - 255)) >> 16); + rt[1] = rt1[1] + ((temp_fac * rt1[1] * (rt2[1] - 255)) >> 16); + rt[2] = rt1[2] + ((temp_fac * rt1[2] * (rt2[2] - 255)) >> 16); + rt[3] = rt1[3] + ((temp_fac * rt1[3] * (rt2[3] - 255)) >> 16); rt1 += 4; rt2 += 4; @@ -1469,48 +1000,21 @@ static void do_mul_effect_byte(float facf0, } } -static void do_mul_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, float *out) +static void do_mul_effect_float(float fac, int x, int y, float *rect1, float *rect2, float *out) { - int xo; - float fac1, fac3; - float *rt1, *rt2, *rt; - - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - - fac1 = facf0; - fac3 = facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; /* Formula: * `fac * (a * b) + (1 - fac) * a => fac * a * (b - 1) + a`. */ - while (y--) { - x = xo; - while (x--) { - rt[0] = rt1[0] + fac1 * rt1[0] * (rt2[0] - 1.0f); - rt[1] = rt1[1] + fac1 * rt1[1] * (rt2[1] - 1.0f); - rt[2] = rt1[2] + fac1 * rt1[2] * (rt2[2] - 1.0f); - rt[3] = rt1[3] + fac1 * rt1[3] * (rt2[3] - 1.0f); - - rt1 += 4; - rt2 += 4; - rt += 4; - } - - if (y == 0) { - break; - } - y--; - - x = xo; - while (x--) { - rt[0] = rt1[0] + fac3 * rt1[0] * (rt2[0] - 1.0f); - rt[1] = rt1[1] + fac3 * rt1[1] * (rt2[1] - 1.0f); - rt[2] = rt1[2] + fac3 * rt1[2] * (rt2[2] - 1.0f); - rt[3] = rt1[3] + fac3 * rt1[3] * (rt2[3] - 1.0f); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rt[0] = rt1[0] + fac * rt1[0] * (rt2[0] - 1.0f); + rt[1] = rt1[1] + fac * rt1[1] * (rt2[1] - 1.0f); + rt[2] = rt1[2] + fac * rt1[2] * (rt2[2] - 1.0f); + rt[3] = rt1[3] + fac * rt1[3] * (rt2[3] - 1.0f); rt1 += 4; rt2 += 4; @@ -1522,8 +1026,7 @@ static void do_mul_effect_float( static void do_mul_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1537,7 +1040,7 @@ static void do_mul_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_mul_effect_float(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_mul_effect_float(fac, context->rectx, total_lines, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -1545,7 +1048,7 @@ static void do_mul_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_mul_effect_byte(facf0, facf1, context->rectx, total_lines, rect1, rect2, rect_out); + do_mul_effect_byte(fac, context->rectx, total_lines, rect1, rect2, rect_out); } } @@ -1555,8 +1058,7 @@ typedef void (*IMB_blend_func_byte)(unsigned char *dst, const unsigned char *src2); typedef void (*IMB_blend_func_float)(float *dst, const float *src1, const float *src2); -BLI_INLINE void apply_blend_function_byte(float facf0, - float facf1, +BLI_INLINE void apply_blend_function_byte(float fac, int x, int y, unsigned char *rect1, @@ -1564,33 +1066,16 @@ BLI_INLINE void apply_blend_function_byte(float facf0, unsigned char *out, IMB_blend_func_byte blend_function) { - int xo; - unsigned char *rt1, *rt2, *rt; - unsigned int achannel; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - while (y--) { - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = (unsigned int)achannel * facf0; - blend_function(rt, rt1, rt2); - rt1[3] = achannel; - rt[3] = rt1[3]; - rt1 += 4; - rt2 += 4; - rt += 4; - } - if (y == 0) { - break; - } - y--; - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = (unsigned int)achannel * facf1; + unsigned char *rt1 = rect1; + unsigned char *rt2 = rect2; + unsigned char *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + unsigned int achannel = rt2[3]; + rt2[3] = (unsigned int)achannel * fac; blend_function(rt, rt1, rt2); - rt1[3] = achannel; + rt2[3] = achannel; rt[3] = rt1[3]; rt1 += 4; rt2 += 4; @@ -1599,8 +1084,7 @@ BLI_INLINE void apply_blend_function_byte(float facf0, } } -BLI_INLINE void apply_blend_function_float(float facf0, - float facf1, +BLI_INLINE void apply_blend_function_float(float fac, int x, int y, float *rect1, @@ -1608,33 +1092,16 @@ BLI_INLINE void apply_blend_function_float(float facf0, float *out, IMB_blend_func_float blend_function) { - int xo; - float *rt1, *rt2, *rt; - float achannel; - xo = x; - rt1 = rect1; - rt2 = rect2; - rt = out; - while (y--) { - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = achannel * facf0; - blend_function(rt, rt1, rt2); - rt1[3] = achannel; - rt[3] = rt1[3]; - rt1 += 4; - rt2 += 4; - rt += 4; - } - if (y == 0) { - break; - } - y--; - for (x = xo; x > 0; x--) { - achannel = rt1[3]; - rt1[3] = achannel * facf1; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; + + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float achannel = rt2[3]; + rt2[3] = achannel * fac; blend_function(rt, rt1, rt2); - rt1[3] = achannel; + rt2[3] = achannel; rt[3] = rt1[3]; rt1 += 4; rt2 += 4; @@ -1644,89 +1111,78 @@ BLI_INLINE void apply_blend_function_float(float facf0, } static void do_blend_effect_float( - float facf0, float facf1, int x, int y, float *rect1, float *rect2, int btype, float *out) + float fac, int x, int y, float *rect1, float *rect2, int btype, float *out) { switch (btype) { case SEQ_TYPE_ADD: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_add_float); break; case SEQ_TYPE_SUB: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_sub_float); break; case SEQ_TYPE_MUL: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_mul_float); break; case SEQ_TYPE_DARKEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_darken_float); break; case SEQ_TYPE_COLOR_BURN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_burn_float); break; case SEQ_TYPE_LINEAR_BURN: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearburn_float); break; case SEQ_TYPE_SCREEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_screen_float); break; case SEQ_TYPE_LIGHTEN: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_lighten_float); break; case SEQ_TYPE_DODGE: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_dodge_float); break; case SEQ_TYPE_OVERLAY: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_overlay_float); break; case SEQ_TYPE_SOFT_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_softlight_float); break; case SEQ_TYPE_HARD_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hardlight_float); break; case SEQ_TYPE_PIN_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_pinlight_float); break; case SEQ_TYPE_LIN_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_linearlight_float); break; case SEQ_TYPE_VIVID_LIGHT: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_vividlight_float); break; case SEQ_TYPE_BLEND_COLOR: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_color_float); break; case SEQ_TYPE_HUE: - apply_blend_function_float(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_hue_float); break; case SEQ_TYPE_SATURATION: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_saturation_float); break; case SEQ_TYPE_VALUE: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_luminosity_float); break; case SEQ_TYPE_DIFFERENCE: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_difference_float); break; case SEQ_TYPE_EXCLUSION: - apply_blend_function_float( - facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_float); + apply_blend_function_float(fac, x, y, rect1, rect2, out, blend_color_exclusion_float); break; default: break; } } -static void do_blend_effect_byte(float facf0, - float facf1, +static void do_blend_effect_byte(float fac, int x, int y, unsigned char *rect1, @@ -1736,73 +1192,67 @@ static void do_blend_effect_byte(float facf0, { switch (btype) { case SEQ_TYPE_ADD: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_add_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_add_byte); break; case SEQ_TYPE_SUB: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_sub_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_sub_byte); break; case SEQ_TYPE_MUL: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_mul_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_mul_byte); break; case SEQ_TYPE_DARKEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_darken_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_darken_byte); break; case SEQ_TYPE_COLOR_BURN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_burn_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_burn_byte); break; case SEQ_TYPE_LINEAR_BURN: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearburn_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearburn_byte); break; case SEQ_TYPE_SCREEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_screen_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_screen_byte); break; case SEQ_TYPE_LIGHTEN: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_lighten_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_lighten_byte); break; case SEQ_TYPE_DODGE: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_dodge_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_dodge_byte); break; case SEQ_TYPE_OVERLAY: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_overlay_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_overlay_byte); break; case SEQ_TYPE_SOFT_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_softlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_softlight_byte); break; case SEQ_TYPE_HARD_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hardlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hardlight_byte); break; case SEQ_TYPE_PIN_LIGHT: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_pinlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_pinlight_byte); break; case SEQ_TYPE_LIN_LIGHT: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_linearlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_linearlight_byte); break; case SEQ_TYPE_VIVID_LIGHT: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_vividlight_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_vividlight_byte); break; case SEQ_TYPE_BLEND_COLOR: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_color_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_color_byte); break; case SEQ_TYPE_HUE: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_hue_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_hue_byte); break; case SEQ_TYPE_SATURATION: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_saturation_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_saturation_byte); break; case SEQ_TYPE_VALUE: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_luminosity_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_luminosity_byte); break; case SEQ_TYPE_DIFFERENCE: - apply_blend_function_byte( - facf0, facf1, x, y, rect1, rect2, out, blend_color_difference_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_difference_byte); break; case SEQ_TYPE_EXCLUSION: - apply_blend_function_byte(facf0, facf1, x, y, rect1, rect2, out, blend_color_exclusion_byte); + apply_blend_function_byte(fac, x, y, rect1, rect2, out, blend_color_exclusion_byte); break; default: break; @@ -1812,8 +1262,7 @@ static void do_blend_effect_byte(float facf0, static void do_blend_mode_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1826,14 +1275,14 @@ static void do_blend_mode_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_float( - facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_byte( - facf0, facf1, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); + fac, context->rectx, total_lines, rect1, rect2, seq->blend_mode, rect_out); } } /*********************** Color Mix Effect *************************/ @@ -1853,8 +1302,7 @@ static void init_colormix_effect(Sequence *seq) static void do_colormix_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -1862,24 +1310,24 @@ static void do_colormix_effect(const SeqRenderData *context, int total_lines, ImBuf *out) { - float facf; + float fac; ColorMixVars *data = seq->effectdata; - facf = data->factor; + fac = data->factor; if (out->rect_float) { float *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_float( - facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); do_blend_effect_byte( - facf, facf, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); + fac, context->rectx, total_lines, rect1, rect2, data->blend_effect, rect_out); } } @@ -1930,7 +1378,7 @@ static float in_band(float width, float dist, int side, int dir) return alpha; } -static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float facf0) +static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float fac) { float posx, posy, hyp, hyp2, angle, hwidth, b1, b2, b3, pointdist; /* some future stuff */ @@ -1950,18 +1398,18 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f angle = wipezone->angle; if (wipe->forward) { - posx = facf0 * xo; - posy = facf0 * yo; + posx = fac * xo; + posy = fac * yo; } else { - posx = xo - facf0 * xo; - posy = yo - facf0 * yo; + posx = xo - fac * xo; + posy = yo - fac * yo; } switch (wipe->wipetype) { case DO_SINGLE_WIPE: - width = min_ii(wipezone->width, facf0 * yo); - width = min_ii(width, yo - facf0 * yo); + width = min_ii(wipezone->width, fac * yo); + width = min_ii(width, yo - fac * yo); if (angle == 0.0f) { b1 = posy; @@ -2000,7 +1448,7 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f case DO_DOUBLE_WIPE: if (!wipe->forward) { - facf0 = 1.0f - facf0; /* Go the other direction */ + fac = 1.0f - fac; /* Go the other direction */ } width = wipezone->width; /* calculate the blur width */ @@ -2053,9 +1501,9 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f * temp3: angle of low side of blur * temp4: angle of high side of blur */ - output = 1.0f - facf0; + output = 1.0f - fac; widthf = wipe->edgeWidth * 2.0f * (float)M_PI; - temp1 = 2.0f * (float)M_PI * facf0; + temp1 = 2.0f * (float)M_PI * fac; if (wipe->forward) { temp1 = 2.0f * (float)M_PI - temp1; @@ -2076,12 +1524,12 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f } if (wipe->forward) { - temp3 = temp1 - (widthf * 0.5f) * facf0; - temp4 = temp1 + (widthf * 0.5f) * (1 - facf0); + temp3 = temp1 - (widthf * 0.5f) * fac; + temp4 = temp1 + (widthf * 0.5f) * (1 - fac); } else { - temp3 = temp1 - (widthf * 0.5f) * (1 - facf0); - temp4 = temp1 + (widthf * 0.5f) * facf0; + temp3 = temp1 - (widthf * 0.5f) * (1 - fac); + temp4 = temp1 + (widthf * 0.5f) * fac; } if (temp3 < 0) { temp3 = 0; @@ -2118,13 +1566,13 @@ static float check_zone(WipeZone *wipezone, int x, int y, Sequence *seq, float f } if (!wipe->forward) { - facf0 = 1 - facf0; + fac = 1 - fac; } width = wipezone->width; hwidth = width * 0.5f; - temp1 = (halfx - (halfx)*facf0); + temp1 = (halfx - (halfx)*fac); pointdist = hypotf(temp1, temp1); temp2 = hypotf(halfx - x, halfy - y); @@ -2175,8 +1623,7 @@ static void copy_wipe_effect(Sequence *dst, Sequence *src, const int UNUSED(flag } static void do_wipe_effect_byte(Sequence *seq, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, unsigned char *rect1, @@ -2185,20 +1632,15 @@ static void do_wipe_effect_byte(Sequence *seq, { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; - int xo, yo; - unsigned char *cp1, *cp2, *rt; - precalc_wipe_zone(&wipezone, wipe, x, y); - cp1 = rect1; - cp2 = rect2; - rt = out; + unsigned char *cp1 = rect1; + unsigned char *cp2 = rect2; + unsigned char *rt = out; - xo = x; - yo = y; - for (y = 0; y < yo; y++) { - for (x = 0; x < xo; x++) { - float check = check_zone(&wipezone, x, y, seq, facf0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float check = check_zone(&wipezone, x, y, seq, fac); if (check) { if (cp1) { float rt1[4], rt2[4], tempc[4]; @@ -2246,31 +1688,20 @@ static void do_wipe_effect_byte(Sequence *seq, } } -static void do_wipe_effect_float(Sequence *seq, - float facf0, - float UNUSED(facf1), - int x, - int y, - float *rect1, - float *rect2, - float *out) +static void do_wipe_effect_float( + Sequence *seq, float fac, int x, int y, float *rect1, float *rect2, float *out) { WipeZone wipezone; WipeVars *wipe = (WipeVars *)seq->effectdata; - int xo, yo; - float *rt1, *rt2, *rt; - precalc_wipe_zone(&wipezone, wipe, x, y); - rt1 = rect1; - rt2 = rect2; - rt = out; + float *rt1 = rect1; + float *rt2 = rect2; + float *rt = out; - xo = x; - yo = y; - for (y = 0; y < yo; y++) { - for (x = 0; x < xo; x++) { - float check = check_zone(&wipezone, x, y, seq, facf0); + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + float check = check_zone(&wipezone, x, y, seq, fac); if (check) { if (rt1) { rt[0] = rt1[0] * check + rt2[0] * (1 - check); @@ -2314,8 +1745,7 @@ static void do_wipe_effect_float(Sequence *seq, static ImBuf *do_wipe_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2324,8 +1754,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context, if (out->rect_float) { do_wipe_effect_float(seq, - facf0, - facf1, + fac, context->rectx, context->recty, ibuf1->rect_float, @@ -2334,8 +1763,7 @@ static ImBuf *do_wipe_effect(const SeqRenderData *context, } else { do_wipe_effect_byte(seq, - facf0, - facf1, + fac, context->rectx, context->recty, (unsigned char *)ibuf1->rect, @@ -2442,8 +1870,7 @@ static void transform_image(int x, static void do_transform_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3), @@ -2731,8 +2158,7 @@ static void copy_glow_effect(Sequence *dst, Sequence *src, const int UNUSED(flag static void do_glow_effect_byte(Sequence *seq, int render_size, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, unsigned char *rect1, @@ -2749,7 +2175,7 @@ static void do_glow_effect_byte(Sequence *seq, IMB_buffer_float_premultiply(inbuf, x, y); RVIsolateHighlights_float( - inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp); RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) { RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); @@ -2765,8 +2191,7 @@ static void do_glow_effect_byte(Sequence *seq, static void do_glow_effect_float(Sequence *seq, int render_size, - float facf0, - float UNUSED(facf1), + float fac, int x, int y, float *rect1, @@ -2778,7 +2203,7 @@ static void do_glow_effect_float(Sequence *seq, GlowVars *glow = (GlowVars *)seq->effectdata; RVIsolateHighlights_float( - inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * facf0, glow->fClamp); + inbuf, outbuf, x, y, glow->fMini * 3.0f, glow->fBoost * fac, glow->fClamp); RVBlurBitmap2_float(outbuf, x, y, glow->dDist * (render_size / 100.0f), glow->dQuality); if (!glow->bNoComp) { RVAddBitmaps_float(inbuf, outbuf, outbuf, x, y); @@ -2788,8 +2213,7 @@ static void do_glow_effect_float(Sequence *seq, static ImBuf *do_glow_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2801,8 +2225,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, if (out->rect_float) { do_glow_effect_float(seq, render_size, - facf0, - facf1, + fac, context->rectx, context->recty, ibuf1->rect_float, @@ -2812,8 +2235,7 @@ static ImBuf *do_glow_effect(const SeqRenderData *context, else { do_glow_effect_byte(seq, render_size, - facf0, - facf1, + fac, context->rectx, context->recty, (unsigned char *)ibuf1->rect, @@ -2855,7 +2277,7 @@ static void copy_solid_color(Sequence *dst, Sequence *src, const int UNUSED(flag dst->effectdata = MEM_dupallocN(src->effectdata); } -static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_color(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -2863,8 +2285,7 @@ static int early_out_color(Sequence *UNUSED(seq), float UNUSED(facf0), float UNU static ImBuf *do_solid_color(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float facf0, - float facf1, + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -2873,72 +2294,44 @@ static ImBuf *do_solid_color(const SeqRenderData *context, SolidColorVars *cv = (SolidColorVars *)seq->effectdata; - unsigned char *rect; - float *rect_float; - int x; /*= context->rectx;*/ /*UNUSED*/ - int y; /*= context->recty;*/ /*UNUSED*/ + int x = out->x; + int y = out->y; if (out->rect) { - unsigned char col0[3]; - unsigned char col1[3]; - - col0[0] = facf0 * cv->col[0] * 255; - col0[1] = facf0 * cv->col[1] * 255; - col0[2] = facf0 * cv->col[2] * 255; + unsigned char color[4]; + color[0] = cv->col[0] * 255; + color[1] = cv->col[1] * 255; + color[2] = cv->col[2] * 255; + color[3] = 255; - col1[0] = facf1 * cv->col[0] * 255; - col1[1] = facf1 * cv->col[1] * 255; - col1[2] = facf1 * cv->col[2] * 255; + unsigned char *rect = (unsigned char *)out->rect; - rect = (unsigned char *)out->rect; - - for (y = 0; y < out->y; y++) { - for (x = 0; x < out->x; x++, rect += 4) { - rect[0] = col0[0]; - rect[1] = col0[1]; - rect[2] = col0[2]; - rect[3] = 255; - } - y++; - if (y < out->y) { - for (x = 0; x < out->x; x++, rect += 4) { - rect[0] = col1[0]; - rect[1] = col1[1]; - rect[2] = col1[2]; - rect[3] = 255; - } + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rect[0] = color[0]; + rect[1] = color[1]; + rect[2] = color[2]; + rect[3] = color[3]; + rect += 4; } } } else if (out->rect_float) { - float col0[3]; - float col1[3]; - - col0[0] = facf0 * cv->col[0]; - col0[1] = facf0 * cv->col[1]; - col0[2] = facf0 * cv->col[2]; + float color[4]; + color[0] = cv->col[0]; + color[1] = cv->col[1]; + color[2] = cv->col[2]; + color[3] = 255; - col1[0] = facf1 * cv->col[0]; - col1[1] = facf1 * cv->col[1]; - col1[2] = facf1 * cv->col[2]; + float *rect_float = out->rect_float; - rect_float = out->rect_float; - - for (y = 0; y < out->y; y++) { - for (x = 0; x < out->x; x++, rect_float += 4) { - rect_float[0] = col0[0]; - rect_float[1] = col0[1]; - rect_float[2] = col0[2]; - rect_float[3] = 1.0; - } - y++; - if (y < out->y) { - for (x = 0; x < out->x; x++, rect_float += 4) { - rect_float[0] = col1[0]; - rect_float[1] = col1[1]; - rect_float[2] = col1[2]; - rect_float[3] = 1.0; - } + for (int i = 0; i < y; i++) { + for (int j = 0; j < x; j++) { + rect_float[0] = color[0]; + rect_float[1] = color[1]; + rect_float[2] = color[2]; + rect_float[3] = color[3]; + rect_float += 4; } } } @@ -2956,7 +2349,7 @@ static int num_inputs_multicam(void) return 0; } -static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -2964,8 +2357,7 @@ static int early_out_multicam(Sequence *UNUSED(seq), float UNUSED(facf0), float static ImBuf *do_multicam(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -3000,7 +2392,7 @@ static int num_inputs_adjustment(void) return 0; } -static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_adjustment(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_NO_INPUT; } @@ -3044,8 +2436,7 @@ static ImBuf *do_adjustment_impl(const SeqRenderData *context, Sequence *seq, fl static ImBuf *do_adjustment(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *UNUSED(ibuf1), ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -3111,7 +2502,7 @@ static void copy_speed_effect(Sequence *dst, Sequence *src, const int UNUSED(fla v->frameMap = NULL; } -static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_speed(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_DO_EFFECT; } @@ -3243,8 +2634,7 @@ static float speed_effect_interpolation_ratio_get(Scene *scene, static ImBuf *do_speed_effect(const SeqRenderData *context, Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -3255,10 +2645,10 @@ static ImBuf *do_speed_effect(const SeqRenderData *context, if (s->flags & SEQ_SPEED_USE_INTERPOLATION) { out = prepare_effect_imbufs(context, ibuf1, ibuf2, ibuf3); - facf0 = facf1 = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame); + fac = speed_effect_interpolation_ratio_get(context->scene, seq, timeline_frame); /* Current frame is ibuf1, next frame is ibuf2. */ out = seq_render_effect_execute_threaded( - &cross_effect, context, NULL, timeline_frame, facf0, facf1, ibuf1, ibuf2, ibuf3); + &cross_effect, context, NULL, timeline_frame, fac, ibuf1, ibuf2, ibuf3); return out; } @@ -3271,8 +2661,7 @@ static ImBuf *do_speed_effect(const SeqRenderData *context, static void do_overdrop_effect(const SeqRenderData *context, Sequence *UNUSED(seq), float UNUSED(timeline_frame), - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *UNUSED(ibuf3), @@ -3289,8 +2678,8 @@ static void do_overdrop_effect(const SeqRenderData *context, slice_get_float_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out); - do_alphaover_effect_float(facf0, facf1, x, y, rect1, rect2, rect_out); + do_drop_effect_float(fac, x, y, rect1, rect2, rect_out); + do_alphaover_effect_float(fac, x, y, rect1, rect2, rect_out); } else { unsigned char *rect1 = NULL, *rect2 = NULL, *rect_out = NULL; @@ -3298,8 +2687,8 @@ static void do_overdrop_effect(const SeqRenderData *context, slice_get_byte_buffers( context, ibuf1, ibuf2, NULL, out, start_line, &rect1, &rect2, NULL, &rect_out); - do_drop_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); - do_alphaover_effect_byte(facf0, facf1, x, y, rect1, rect2, rect_out); + do_drop_effect_byte(fac, x, y, rect1, rect2, rect_out); + do_alphaover_effect_byte(fac, x, y, rect1, rect2, rect_out); } } @@ -3337,7 +2726,7 @@ static void copy_gaussian_blur_effect(Sequence *dst, Sequence *src, const int UN dst->effectdata = MEM_dupallocN(src->effectdata); } -static int early_out_gaussian_blur(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_gaussian_blur(Sequence *seq, float UNUSED(fac)) { GaussianBlurVars *data = seq->effectdata; if (data->size_x == 0.0f && data->size_y == 0) { @@ -3691,8 +3080,7 @@ static void *render_effect_execute_do_y_thread(void *thread_data_v) static ImBuf *do_gaussian_blur_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *UNUSED(ibuf2), ImBuf *UNUSED(ibuf3)) @@ -3839,7 +3227,7 @@ static int num_inputs_text(void) return 0; } -static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_text(Sequence *seq, float UNUSED(fac)) { TextVars *data = seq->effectdata; if (data->text[0] == 0 || data->text_size < 1.0f || @@ -3853,8 +3241,7 @@ static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1 static ImBuf *do_text_effect(const SeqRenderData *context, Sequence *seq, float UNUSED(timeline_frame), - float UNUSED(facf0), - float UNUSED(facf1), + float UNUSED(fac), ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -4000,52 +3387,47 @@ static void free_effect_default(Sequence *seq, const bool UNUSED(do_id_user)) MEM_SAFE_FREE(seq->effectdata); } -static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(facf0), float UNUSED(facf1)) +static int early_out_noop(Sequence *UNUSED(seq), float UNUSED(fac)) { return EARLY_DO_EFFECT; } -static int early_out_fade(Sequence *UNUSED(seq), float facf0, float facf1) +static int early_out_fade(Sequence *UNUSED(seq), float fac) { - if (facf0 == 0.0f && facf1 == 0.0f) { + if (fac == 0.0f) { return EARLY_USE_INPUT_1; } - if (facf0 == 1.0f && facf1 == 1.0f) { + if (fac == 1.0f) { return EARLY_USE_INPUT_2; } return EARLY_DO_EFFECT; } -static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) +static int early_out_mul_input2(Sequence *UNUSED(seq), float fac) { - if (facf0 == 0.0f && facf1 == 0.0f) { + if (fac == 0.0f) { return EARLY_USE_INPUT_1; } return EARLY_DO_EFFECT; } -static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1) +static int early_out_mul_input1(Sequence *UNUSED(seq), float fac) { - if (facf0 == 0.0f && facf1 == 0.0f) { + if (fac == 0.0f) { return EARLY_USE_INPUT_2; } return EARLY_DO_EFFECT; } -static void get_default_fac_noop(Sequence *UNUSED(seq), - float UNUSED(timeline_frame), - float *facf0, - float *facf1) +static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *fac) { - *facf0 = *facf1 = 1.0; + *fac = 1.0f; } -static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *facf0, float *facf1) +static void get_default_fac_fade(Sequence *seq, float timeline_frame, float *fac) { - *facf0 = (float)(timeline_frame - seq->startdisp); - *facf1 = (float)(*facf0 + 0.5f); - *facf0 /= seq->len; - *facf1 /= seq->len; + *fac = (float)(timeline_frame - seq->startdisp); + *fac /= seq->len; } static struct ImBuf *init_execution(const SeqRenderData *context, diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index a391deaccb4..371e4b7becd 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -683,7 +683,7 @@ typedef struct RenderEffectInitData { struct SeqEffectHandle *sh; const SeqRenderData *context; Sequence *seq; - float timeline_frame, facf0, facf1; + float timeline_frame, fac; ImBuf *ibuf1, *ibuf2, *ibuf3; ImBuf *out; @@ -693,7 +693,7 @@ typedef struct RenderEffectThread { struct SeqEffectHandle *sh; const SeqRenderData *context; Sequence *seq; - float timeline_frame, facf0, facf1; + float timeline_frame, fac; ImBuf *ibuf1, *ibuf2, *ibuf3; ImBuf *out; @@ -712,8 +712,7 @@ static void render_effect_execute_init_handle(void *handle_v, handle->context = init_data->context; handle->seq = init_data->seq; handle->timeline_frame = init_data->timeline_frame; - handle->facf0 = init_data->facf0; - handle->facf1 = init_data->facf1; + handle->fac = init_data->fac; handle->ibuf1 = init_data->ibuf1; handle->ibuf2 = init_data->ibuf2; handle->ibuf3 = init_data->ibuf3; @@ -730,8 +729,7 @@ static void *render_effect_execute_do_thread(void *thread_data_v) thread_data->sh->execute_slice(thread_data->context, thread_data->seq, thread_data->timeline_frame, - thread_data->facf0, - thread_data->facf1, + thread_data->fac, thread_data->ibuf1, thread_data->ibuf2, thread_data->ibuf3, @@ -746,8 +744,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const SeqRenderData *context, Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, ImBuf *ibuf1, ImBuf *ibuf2, ImBuf *ibuf3) @@ -759,8 +756,7 @@ ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, init_data.context = context; init_data.seq = seq; init_data.timeline_frame = timeline_frame; - init_data.facf0 = facf0; - init_data.facf1 = facf1; + init_data.fac = fac; init_data.ibuf1 = ibuf1; init_data.ibuf2 = ibuf2; init_data.ibuf3 = ibuf3; @@ -781,7 +777,7 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, float timeline_frame) { Scene *scene = context->scene; - float fac, facf; + float fac; int early_out; int i; struct SeqEffectHandle sh = SEQ_effect_handle_get(seq); @@ -803,24 +799,23 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, } if (seq->flag & SEQ_USE_EFFECT_DEFAULT_FADE) { - sh.get_default_fac(seq, timeline_frame, &fac, &facf); - facf = fac; + sh.get_default_fac(seq, timeline_frame, &fac); } else { fcu = id_data_find_fcurve(&scene->id, seq, &RNA_Sequence, "effect_fader", 0, NULL); if (fcu) { - fac = facf = evaluate_fcurve(fcu, timeline_frame); + fac = evaluate_fcurve(fcu, timeline_frame); } else { - fac = facf = seq->effect_fader; + fac = seq->effect_fader; } } - early_out = sh.early_out(seq, fac, facf); + early_out = sh.early_out(seq, fac); switch (early_out) { case EARLY_NO_INPUT: - out = sh.execute(context, seq, timeline_frame, fac, facf, NULL, NULL, NULL); + out = sh.execute(context, seq, timeline_frame, fac, NULL, NULL, NULL); break; case EARLY_DO_EFFECT: for (i = 0; i < 3; i++) { @@ -839,10 +834,10 @@ static ImBuf *seq_render_effect_strip_impl(const SeqRenderData *context, if (ibuf[0] && (ibuf[1] || SEQ_effect_get_num_inputs(seq->type) == 1)) { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]); + &sh, context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]); } else { - out = sh.execute(context, seq, timeline_frame, fac, facf, ibuf[0], ibuf[1], ibuf[2]); + out = sh.execute(context, seq, timeline_frame, fac, ibuf[0], ibuf[1], ibuf[2]); } } break; @@ -1774,8 +1769,8 @@ static bool seq_must_swap_input_in_blend_mode(Sequence *seq) static int seq_get_early_out_for_blend_mode(Sequence *seq) { struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); - float facf = seq->blend_opacity / 100.0f; - int early_out = sh.early_out(seq, facf, facf); + float fac = seq->blend_opacity / 100.0f; + int early_out = sh.early_out(seq, fac); if (ELEM(early_out, EARLY_DO_EFFECT, EARLY_NO_INPUT)) { return early_out; @@ -1797,25 +1792,25 @@ static ImBuf *seq_render_strip_stack_apply_effect( { ImBuf *out; struct SeqEffectHandle sh = seq_effect_get_sequence_blend(seq); - float facf = seq->blend_opacity / 100.0f; + float fac = seq->blend_opacity / 100.0f; int swap_input = seq_must_swap_input_in_blend_mode(seq); if (swap_input) { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL); + &sh, context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL); } else { - out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf2, ibuf1, NULL); + out = sh.execute(context, seq, timeline_frame, fac, ibuf2, ibuf1, NULL); } } else { if (sh.multithreaded) { out = seq_render_effect_execute_threaded( - &sh, context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL); + &sh, context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL); } else { - out = sh.execute(context, seq, timeline_frame, facf, facf, ibuf1, ibuf2, NULL); + out = sh.execute(context, seq, timeline_frame, fac, ibuf1, ibuf2, NULL); } } diff --git a/source/blender/sequencer/intern/render.h b/source/blender/sequencer/intern/render.h index a0cdf24d84b..eb1f71769a6 100644 --- a/source/blender/sequencer/intern/render.h +++ b/source/blender/sequencer/intern/render.h @@ -54,8 +54,7 @@ struct ImBuf *seq_render_effect_execute_threaded(struct SeqEffectHandle *sh, const struct SeqRenderData *context, struct Sequence *seq, float timeline_frame, - float facf0, - float facf1, + float fac, struct ImBuf *ibuf1, struct ImBuf *ibuf2, struct ImBuf *ibuf3); diff --git a/source/blender/sequencer/intern/sequencer.c b/source/blender/sequencer/intern/sequencer.c index 908a5bd4f79..e4120a3cf95 100644 --- a/source/blender/sequencer/intern/sequencer.c +++ b/source/blender/sequencer/intern/sequencer.c @@ -140,6 +140,7 @@ Sequence *SEQ_sequence_alloc(ListBase *lb, int timeline_frame, int machine, int seq->pitch = 1.0f; seq->scene_sound = NULL; seq->type = type; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->strip = seq_strip_alloc(type); seq->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Sequence Stereo Format"); @@ -418,6 +419,10 @@ void SEQ_meta_stack_free(Editing *ed, MetaStack *ms) MetaStack *SEQ_meta_stack_active_get(const Editing *ed) { + if (ed == NULL) { + return NULL; + } + return ed->metastack.last; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index a4b537b9074..f342765eec9 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -141,7 +141,6 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->scene = load_data->scene; seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); @@ -154,7 +153,6 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->clip = load_data->clip; seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); @@ -167,7 +165,6 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->mask = load_data->mask; seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); @@ -191,9 +188,6 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa if (SEQ_effect_get_num_inputs(seq->type) == 1) { seq->blend_mode = seq->seq1->blend_mode; } - else { - seq->blend_mode = SEQ_TYPE_ALPHAOVER; - } if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ @@ -250,7 +244,6 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ seq->len = load_data->image.len; Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); @@ -482,8 +475,6 @@ Sequence *SEQ_add_movie_strip( } } - seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ - if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 912ba9d41db..cf303e5be4e 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -489,21 +489,27 @@ Sequence *SEQ_edit_strip_split(Main *bmain, ListBase right_strips = {NULL, NULL}; SEQ_sequence_base_dupli_recursive(scene, scene, &right_strips, &left_strips, SEQ_DUPE_ALL, 0); - /* Split strips. */ Sequence *left_seq = left_strips.first; Sequence *right_seq = right_strips.first; - Sequence *return_seq = right_strips.first; + Sequence *return_seq = NULL; - /* Strips can't be tagged while in detached `seqbase`. Collect all strips which needs to be - * deleted and delay tagging until they are moved back to `seqbase` in `Editing`. */ - SeqCollection *strips_to_delete = SEQ_collection_create(__func__); + /* Move strips from detached `ListBase`, otherwise they can't be flagged for removal, + * SEQ_time_update_sequence can fail to update meta strips and they can't be renamed. + * This is because these functions check all strips in `Editing` to manage relationships. */ + BLI_movelisttolist(seqbase, &left_strips); + BLI_movelisttolist(seqbase, &right_strips); + /* Split strips. */ while (left_seq && right_seq) { if (left_seq->startdisp >= timeline_frame) { - SEQ_collection_append_strip(left_seq, strips_to_delete); + SEQ_edit_flag_for_removal(scene, seqbase, left_seq); } if (right_seq->enddisp <= timeline_frame) { - SEQ_collection_append_strip(right_seq, strips_to_delete); + SEQ_edit_flag_for_removal(scene, seqbase, right_seq); + } + else if (return_seq == NULL) { + /* Store return value - pointer to strip that will not be removed. */ + return_seq = right_seq; } seq_edit_split_handle_strip_offsets( @@ -512,20 +518,14 @@ Sequence *SEQ_edit_strip_split(Main *bmain, right_seq = right_seq->next; } - seq = right_strips.first; - BLI_movelisttolist(seqbase, &left_strips); - BLI_movelisttolist(seqbase, &right_strips); + SEQ_edit_remove_flagged_sequences(scene, seqbase); - for (; seq; seq = seq->next) { - SEQ_ensure_unique_name(seq, scene); + /* Rename duplicated strips. */ + Sequence *seq_rename = return_seq; + for (; seq_rename; seq_rename = seq_rename->next) { + SEQ_ensure_unique_name(seq_rename, scene); } - Sequence *seq_delete; - SEQ_ITERATOR_FOREACH (seq_delete, strips_to_delete) { - SEQ_edit_flag_for_removal(scene, seqbase, seq_delete); - } - SEQ_edit_remove_flagged_sequences(scene, seqbase); - SEQ_collection_free(strips_to_delete); return return_seq; } diff --git a/source/blender/sequencer/intern/strip_time.c b/source/blender/sequencer/intern/strip_time.c index 3228277ce72..31ee20cb6ca 100644 --- a/source/blender/sequencer/intern/strip_time.c +++ b/source/blender/sequencer/intern/strip_time.c @@ -193,6 +193,10 @@ static void seq_time_update_meta_strip(Scene *scene, Sequence *seq_meta) void SEQ_time_update_meta_strip_range(Scene *scene, Sequence *seq_meta) { + if (seq_meta == NULL) { + return; + } + seq_time_update_meta_strip(scene, seq_meta); /* Prevent meta-strip to move in timeline. */ diff --git a/source/blender/sequencer/intern/utils.c b/source/blender/sequencer/intern/utils.c index cd779b0b0c7..156c6ac4cb9 100644 --- a/source/blender/sequencer/intern/utils.c +++ b/source/blender/sequencer/intern/utils.c @@ -446,7 +446,7 @@ Sequence *SEQ_get_meta_by_seqbase(ListBase *seqbase_main, ListBase *meta_seqbase { SeqCollection *strips = SEQ_query_all_strips_recursive(seqbase_main); - Sequence *seq; + Sequence *seq = NULL; SEQ_ITERATOR_FOREACH (seq, strips) { if (seq->type == SEQ_TYPE_META && &seq->seqbase == meta_seqbase) { break; diff --git a/source/blender/simulation/intern/SIM_mass_spring.cpp b/source/blender/simulation/intern/SIM_mass_spring.cpp index f9a22276363..36513690584 100644 --- a/source/blender/simulation/intern/SIM_mass_spring.cpp +++ b/source/blender/simulation/intern/SIM_mass_spring.cpp @@ -1295,8 +1295,7 @@ int SIM_cloth_solve( BKE_sim_debug_data_clear_category("collision"); if (!clmd->solver_result) { - clmd->solver_result = (ClothSolverResult *)MEM_callocN(sizeof(ClothSolverResult), - "cloth solver result"); + clmd->solver_result = MEM_cnew<ClothSolverResult>("cloth solver result"); } cloth_clear_result(clmd); diff --git a/source/blender/simulation/intern/hair_volume.cpp b/source/blender/simulation/intern/hair_volume.cpp index e47593eda05..d4550eec5d6 100644 --- a/source/blender/simulation/intern/hair_volume.cpp +++ b/source/blender/simulation/intern/hair_volume.cpp @@ -1160,7 +1160,7 @@ HairGrid *SIM_hair_volume_create_vertex_grid(float cellsize, } size = hair_grid_size(res); - grid = (HairGrid *)MEM_callocN(sizeof(HairGrid), "hair grid"); + grid = MEM_cnew<HairGrid>("hair grid"); grid->res[0] = res[0]; grid->res[1] = res[1]; grid->res[2] = res[2]; diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index e1017c4236e..f2459b7fdc9 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -884,7 +884,7 @@ void wm_drags_draw(bContext *C, wmWindow *win) bScreen *screen = CTX_wm_screen(C); /* To start with, use the area and region under the mouse cursor, just like event handling. The * operator context may still override it. */ - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, UNPACK2(xy)); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, xy); ARegion *region = ED_area_find_region_xy_visual(area, RGN_TYPE_ANY, xy); /* Will be overridden and unset eventually. */ BLI_assert(!CTX_wm_area(C) && !CTX_wm_region(C)); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 1b6df9fb0db..ef644da5578 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -1861,8 +1861,7 @@ static void wm_handler_op_context(bContext *C, wmEventHandler_Op *handler, const CTX_wm_area_set(C, area); if (op && (op->flag & OP_IS_MODAL_CURSOR_REGION)) { - region = BKE_area_find_region_xy( - area, handler->context.region_type, event->xy[0], event->xy[1]); + region = BKE_area_find_region_xy(area, handler->context.region_type, event->xy); if (region) { handler->context.region = region; } diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 2f87e5789fe..957ec7d800d 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -562,6 +562,13 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_blender_free(); /* blender.c, does entire library and spacetypes */ // BKE_material_copybuf_free(); + + /* Free the GPU subdivision data after the database to ensure that subdivision structs used by + * the modifiers were garbage collected. */ + if (opengl_is_init) { + DRW_subdiv_free(); + } + ANIM_fcurves_copybuf_free(); ANIM_drivers_copybuf_free(); ANIM_driver_vars_copybuf_free(); diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index a5887fc07b3..ebd6719d54d 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -184,6 +184,9 @@ void WM_operator_properties_filesel(wmOperatorType *ot, prop = RNA_def_boolean( ot->srna, "filter_usd", (filter & FILE_TYPE_USD) != 0, "Filter USD files", ""); RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); + prop = RNA_def_boolean( + ot->srna, "filter_obj", (filter & FILE_TYPE_OBJECT_IO) != 0, "Filter OBJ files", ""); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "filter_volume", (filter & FILE_TYPE_VOLUME) != 0, diff --git a/source/tools b/source/tools -Subproject b22d19e47f4d0353082f3d9f30ee8d244c5266d +Subproject 26bc78162ec89f21453ce3ded7b999bc6649f32 |