diff --git a/CMakeLists.txt b/CMakeLists.txt index d00b89ef3ed..035cf81e1b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1763,8 +1763,20 @@ if(WITH_BLENDER) # internal and external library information first, for test linking add_subdirectory(source) elseif(WITH_CYCLES_STANDALONE) + add_subdirectory(intern/glew-mx) + add_subdirectory(intern/guardedalloc) + add_subdirectory(intern/libc_compat) + add_subdirectory(intern/numaapi) + add_subdirectory(intern/sky) + add_subdirectory(intern/cycles) add_subdirectory(extern/clew) + if(WITH_CYCLES_LOGGING) + if(NOT WITH_SYSTEM_GFLAGS) + add_subdirectory(extern/gflags) + endif() + add_subdirectory(extern/glog) + endif() if(WITH_CUDA_DYNLOAD) add_subdirectory(extern/cuew) endif() @@ -1845,6 +1857,8 @@ if(FIRST_RUN) info_cfg_option(WITH_OPENCOLORIO) info_cfg_option(WITH_OPENIMAGEDENOISE) info_cfg_option(WITH_OPENVDB) + info_cfg_option(WITH_POTRACE) + info_cfg_option(WITH_PUGIXML) info_cfg_option(WITH_QUADRIFLOW) info_cfg_option(WITH_TBB) info_cfg_option(WITH_USD) diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 08065ec0276..aab997ab453 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -44,6 +44,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) set(WITH_OPENVDB ON CACHE BOOL "" FORCE) set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE) +set(WITH_POTRACE ON CACHE BOOL "" FORCE) +set(WITH_PUGIXML ON CACHE BOOL "" FORCE) set(WITH_NANOVDB ON CACHE BOOL "" FORCE) set(WITH_POTRACE ON CACHE BOOL "" FORCE) set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 4150094e9f5..480548abca7 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -51,6 +51,8 @@ set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE) set(WITH_OPENMP OFF CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE) set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) +set(WITH_POTRACE OFF CACHE BOOL "" FORCE) +set(WITH_PUGIXML OFF CACHE BOOL "" FORCE) set(WITH_NANOVDB OFF CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index fd3225b0287..96101ee7bcc 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -45,6 +45,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) set(WITH_OPENVDB ON CACHE BOOL "" FORCE) set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE) +set(WITH_POTRACE ON CACHE BOOL "" FORCE) +set(WITH_PUGIXML ON CACHE BOOL "" FORCE) set(WITH_NANOVDB ON CACHE BOOL "" FORCE) set(WITH_POTRACE ON CACHE BOOL "" FORCE) set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index abacd0500e5..a2448829206 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -352,6 +352,11 @@ endif() if(WITH_PUGIXML) find_package_wrapper(PugiXML) + + if (NOT PUGIXML_FOUND) + set(WITH_PUGIXML OFF) + message(STATUS "PugiXML not found, disabling WITH_PUGIXML") + endif() endif() if(WITH_OPENIMAGEIO) diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 8167576a177..2a28d905144 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -14,7 +14,7 @@ # Standalone or with Blender if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE) - set(CYCLES_INSTALL_PATH "") + set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}) else() set(WITH_CYCLES_BLENDER ON) # WINDOWS_PYTHON_DEBUG needs to write into the user addons folder since it will diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index f057ce7a2f0..6b3513b065a 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -133,12 +133,12 @@ static void scene_init() /* Camera width/height override? */ if (!(options.width == 0 || options.height == 0)) { - options.scene->camera->width = options.width; - options.scene->camera->height = options.height; + options.scene->camera->set_full_width(options.width); + options.scene->camera->set_full_height(options.height); } else { - options.width = options.scene->camera->width; - options.height = options.scene->camera->height; + options.width = options.scene->camera->get_full_width(); + options.height = options.scene->camera->get_full_height(); } /* Calculate Viewplane */ @@ -233,7 +233,7 @@ static void display() static void motion(int x, int y, int button) { if (options.interactive) { - Transform matrix = options.session->scene->camera->matrix; + Transform matrix = options.session->scene->camera->get_matrix(); /* Translate */ if (button == 0) { @@ -251,8 +251,8 @@ static void motion(int x, int y, int button) } /* Update and Reset */ - options.session->scene->camera->matrix = matrix; - options.session->scene->camera->need_update = true; + options.session->scene->camera->set_matrix(matrix); + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -266,10 +266,10 @@ static void resize(int width, int height) if (options.session) { /* Update camera */ - options.session->scene->camera->width = width; - options.session->scene->camera->height = height; + options.session->scene->camera->set_full_width(options.width); + options.session->scene->camera->set_full_height(options.height); options.session->scene->camera->compute_auto_viewplane(); - options.session->scene->camera->need_update = true; + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -302,7 +302,7 @@ static void keyboard(unsigned char key) /* Navigation */ else if (options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) { - Transform matrix = options.session->scene->camera->matrix; + Transform matrix = options.session->scene->camera->get_matrix(); float3 translate; if (key == 'w') @@ -317,8 +317,8 @@ static void keyboard(unsigned char key) matrix = matrix * transform_translate(translate); /* Update and Reset */ - options.session->scene->camera->matrix = matrix; - options.session->scene->camera->need_update = true; + options.session->scene->camera->set_matrix(matrix); + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -345,10 +345,7 @@ static void keyboard(unsigned char key) break; } - options.session->scene->integrator->max_bounce = bounce; - - /* Update and Reset */ - options.session->scene->integrator->need_update = true; + options.session->scene->integrator->set_max_bounce(bounce); options.session->reset(session_buffer_params(), options.session_params.samples); } diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index a86e06f92d1..272d509585e 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -190,17 +190,18 @@ static void xml_read_camera(XMLReadState &state, xml_node node) { Camera *cam = state.scene->camera; - xml_read_int(&cam->width, node, "width"); - xml_read_int(&cam->height, node, "height"); + int width = -1, height = -1; + xml_read_int(&width, node, "width"); + xml_read_int(&height, node, "height"); - cam->full_width = cam->width; - cam->full_height = cam->height; + cam->set_full_width(width); + cam->set_full_height(height); xml_read_node(state, cam, node); - cam->matrix = state.tfm; + cam->set_matrix(state.tfm); - cam->need_update = true; + cam->need_flags_update = true; cam->update(state.scene); } @@ -338,11 +339,13 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node if (node_name == "image_texture") { ImageTextureNode *img = (ImageTextureNode *)snode; - img->filename = path_join(state.base, img->filename.string()); + ustring filename(path_join(state.base, img->get_filename().string())); + img->set_filename(filename); } else if (node_name == "environment_texture") { EnvironmentTextureNode *env = (EnvironmentTextureNode *)snode; - env->filename = path_join(state.base, env->filename.string()); + ustring filename(path_join(state.base, env->get_filename().string())); + env->set_filename(filename); } if (snode) { @@ -384,8 +387,8 @@ static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm) /* create object*/ Object *object = new Object(); - object->geometry = mesh; - object->tfm = tfm; + object->set_geometry(mesh); + object->set_tfm(tfm); scene->objects.push_back(object); return mesh; @@ -395,7 +398,9 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) { /* add mesh */ Mesh *mesh = xml_add_mesh(state.scene, state.tfm); - mesh->used_shaders.push_back(state.shader); + array used_shaders = mesh->get_used_shaders(); + used_shaders.push_back_slow(state.shader); + mesh->set_used_shaders(used_shaders); /* read state */ int shader = 0; @@ -411,20 +416,24 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) xml_read_int_array(nverts, node, "nverts"); if (xml_equal_string(node, "subdivision", "catmull-clark")) { - mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK; + mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK); } else if (xml_equal_string(node, "subdivision", "linear")) { - mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR; + mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR); } - if (mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { + array P_array; + P_array = P; + + if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) { /* create vertices */ - mesh->verts = P; + + mesh->set_verts(P_array); size_t num_triangles = 0; for (size_t i = 0; i < nverts.size(); i++) num_triangles += nverts[i] - 2; - mesh->reserve_mesh(mesh->verts.size(), num_triangles); + mesh->reserve_mesh(mesh->get_verts().size(), num_triangles); /* create triangles */ int index_offset = 0; @@ -474,7 +483,7 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) } else { /* create vertices */ - mesh->verts = P; + mesh->set_verts(P_array); size_t num_ngons = 0; size_t num_corners = 0; @@ -513,23 +522,20 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) } /* setup subd params */ - if (!mesh->subd_params) { - mesh->subd_params = new SubdParams(mesh); - } - SubdParams &sdparams = *mesh->subd_params; + float dicing_rate = state.dicing_rate; + xml_read_float(&dicing_rate, node, "dicing_rate"); + dicing_rate = std::max(0.1f, dicing_rate); - sdparams.dicing_rate = state.dicing_rate; - xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); - sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate); - - sdparams.objecttoworld = state.tfm; + mesh->set_subd_dicing_rate(dicing_rate); + mesh->set_subd_objecttoworld(state.tfm); } /* we don't yet support arbitrary attributes, for now add vertex * coordinates as generated coordinates if requested */ if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); - memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3) * mesh->verts.size()); + memcpy( + attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); } } @@ -539,7 +545,7 @@ static void xml_read_light(XMLReadState &state, xml_node node) { Light *light = new Light(); - light->shader = state.shader; + light->set_shader(state.shader); xml_read_node(state, light, node); state.scene->lights.push_back(light); diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 307d8436668..855d774bfdb 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -45,7 +45,7 @@ template struct is_array : public std::false_type { template struct is_array> : public std::true_type { }; -/* Store the data set for an animation at every time points, or at the begining of the animation +/* Store the data set for an animation at every time points, or at the beginning of the animation * for constant data. * * The data is supposed to be stored in chronological order, and is looked up using the current diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 6a3fbb7772f..ce4ae6e4295 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -661,15 +661,8 @@ void AttributeSet::update(AttributeSet &&new_attributes) { /* add or update old_attributes based on the new_attributes */ foreach (Attribute &attr, new_attributes.attributes) { - Attribute *nattr = nullptr; - - if (attr.std != ATTR_STD_NONE) { - nattr = add(attr.std, attr.name); - } - else { - nattr = add(attr.name, attr.type, attr.element); - } - + Attribute *nattr = add(attr.name, attr.type, attr.element); + nattr->std = attr.std; nattr->set_data_from(std::move(attr)); } diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 92cf712d32a..3beb3d1d4d3 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -212,8 +212,8 @@ void Camera::compute_auto_viewplane() viewplane.top = 1.0f; } else { - float aspect = (float)width / (float)height; - if (width >= height) { + float aspect = (float)full_width / (float)full_height; + if (full_width >= full_height) { viewplane.left = -aspect; viewplane.right = aspect; viewplane.bottom = -1.0f; diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index ce2fe66dd41..2ee20e08589 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -43,18 +43,21 @@ rna_reverse_prop = BoolProperty( name="Reverse", description="Cycle backwards", default=False, + options={'SKIP_SAVE'}, ) rna_wrap_prop = BoolProperty( name="Wrap", description="Wrap back to the first/last values", default=False, + options={'SKIP_SAVE'}, ) rna_relative_prop = BoolProperty( name="Relative", description="Apply relative to the current value (delta)", default=False, + options={'SKIP_SAVE'}, ) rna_space_type_prop = EnumProperty( @@ -228,6 +231,7 @@ class WM_OT_context_scale_int(Operator): name="Always Step", description="Always adjust the value by a minimum of 1 when 'value' is not 1.0", default=True, + options={'SKIP_SAVE'}, ) def execute(self, context): @@ -736,10 +740,12 @@ class WM_OT_context_modal_mouse(Operator): input_scale: FloatProperty( description="Scale the mouse movement by this value before applying the delta", default=0.01, + options={'SKIP_SAVE'}, ) invert: BoolProperty( description="Invert the mouse input", default=False, + options={'SKIP_SAVE'}, ) initial_x: IntProperty(options={'HIDDEN'}) @@ -1727,6 +1733,7 @@ class WM_OT_tool_set_by_index(Operator): expand: BoolProperty( description="Include tool subgroups", default=True, + options={'SKIP_SAVE'}, ) as_fallback: BoolProperty( diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 3b9ce5311f3..774e2938deb 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -107,6 +107,9 @@ class TIME_MT_editor_menus(Menu): text="Keying", ) + # Add a separator to keep the popover button from aligning with the menu button. + sub.separator(factor=0.4) + if horizontal: sub = row.row(align=True) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index 76ce990ccbe..ba738a26b2d 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1594,6 +1594,7 @@ class _defs_texture_paint: icon_prefix="brush.paint_texture.", type=bpy.types.Brush, attr="image_tool", + cursor='PAINT_CROSS', ) diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 9da261d13f5..56f0b5c0ba4 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -521,6 +521,9 @@ geometry_node_categories = [ NodeItem("GeometryNodeRotatePoints"), NodeItem("GeometryNodeAlignRotationToVector"), ]), + GeometryNodeCategory("GEO_VOLUME", "Volume", items=[ + NodeItem("GeometryNodePointsToVolume"), + ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeClamp"), diff --git a/release/scripts/templates_py/driver_functions.py b/release/scripts/templates_py/driver_functions.py index 1c6af0e574f..d3aab75e7ba 100644 --- a/release/scripts/templates_py/driver_functions.py +++ b/release/scripts/templates_py/driver_functions.py @@ -1,8 +1,8 @@ -# This script defines functions to be used directly in drivers expressions to -# extend the builtin set of python functions. +# This script defines functions to be used directly in driver expressions to +# extend the built-in set of python functions. # # This can be executed on manually or set to 'Register' to -# initialize thefunctions on file load. +# initialize the functions on file load. # two sample functions @@ -30,6 +30,6 @@ def slow_value(value, fac, uuid): import bpy -# Add variable defined in this script into the drivers namespace. +# Add functions defined in this script into the drivers namespace. bpy.app.driver_namespace["invert"] = invert bpy.app.driver_namespace["slow_value"] = slow_value diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 8854949fa11..7c77c6a8f86 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 3 +#define BLENDER_FILE_SUBVERSION 4 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 5b8273def66..27ac6d98688 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -46,9 +46,7 @@ typedef struct InstancedData { } InstancedData; int BKE_geometry_set_instances(const struct GeometrySet *geometry_set, - float (**r_positions)[3], - float (**r_rotations)[3], - float (**r_scales)[3], + float (**r_transforms)[4][4], int **r_ids, struct InstancedData **r_instanced_data); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index adc08f699fd..51f7507bd6c 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -24,6 +24,7 @@ #include #include "BLI_float3.hh" +#include "BLI_float4x4.hh" #include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_set.hh" @@ -427,9 +428,7 @@ class PointCloudComponent : public GeometryComponent { /** A geometry component that stores instances. */ class InstancesComponent : public GeometryComponent { private: - blender::Vector positions_; - blender::Vector rotations_; - blender::Vector scales_; + blender::Vector transforms_; blender::Vector ids_; blender::Vector instanced_data_; @@ -439,30 +438,14 @@ class InstancesComponent : public GeometryComponent { GeometryComponent *copy() const override; void clear(); - void add_instance(Object *object, - blender::float3 position, - blender::float3 rotation = {0, 0, 0}, - blender::float3 scale = {1, 1, 1}, - const int id = -1); - void add_instance(Collection *collection, - blender::float3 position, - blender::float3 rotation = {0, 0, 0}, - blender::float3 scale = {1, 1, 1}, - const int id = -1); - void add_instance(InstancedData data, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id = -1); + void add_instance(Object *object, blender::float4x4 transform, const int id = -1); + void add_instance(Collection *collection, blender::float4x4 transform, const int id = -1); + void add_instance(InstancedData data, blender::float4x4 transform, const int id = -1); blender::Span instanced_data() const; - blender::Span positions() const; - blender::Span rotations() const; - blender::Span scales() const; + blender::Span transforms() const; blender::Span ids() const; - blender::MutableSpan positions(); - blender::MutableSpan rotations(); - blender::MutableSpan scales(); + blender::MutableSpan transforms(); int instances_amount() const; bool is_empty() const final; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 12266cd48d9..4912d634471 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -685,7 +685,7 @@ void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); /* Node Clipboard */ -void BKE_node_clipboard_init(struct bNodeTree *ntree); +void BKE_node_clipboard_init(const struct bNodeTree *ntree); void BKE_node_clipboard_clear(void); void BKE_node_clipboard_free(void); bool BKE_node_clipboard_validate(void); @@ -706,8 +706,8 @@ extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE; extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE; bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, - struct bNodeTree *ntree, - struct bNode *node); + const struct bNodeTree *ntree, + const struct bNode *node); bNodeInstanceHash *BKE_node_instance_hash_new(const char *info); void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp); @@ -1362,6 +1362,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_POINT_TRANSLATE 1019 #define GEO_NODE_POINT_SCALE 1020 #define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021 +#define GEO_NODE_POINTS_TO_VOLUME 1022 /** \} */ diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 4e29ca80d30..601ee57fc89 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1943,9 +1943,6 @@ static void scene_collections_build_array(Collection *collection, void *data) static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot) { - Collection *collection; - Collection **array; - *collections_array = NULL; *tot = 0; @@ -1953,7 +1950,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - collection = scene->master_collection; + Collection *collection = scene->master_collection; BLI_assert(collection != NULL); scene_collection_callback(collection, scene_collections_count, tot); @@ -1961,7 +1958,8 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + Collection **array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + *collections_array = array; scene_collection_callback(collection, scene_collections_build_array, &array); } diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 5d61b1165ed..37e9c810123 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -212,9 +212,9 @@ static void layerFree_mdeformvert(void *data, int count, int size) /* copy just zeros in this case */ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count) { - int i, size = sizeof(void *); + const int size = sizeof(void *); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { void **ptr = POINTER_OFFSET(dest, i * size); *ptr = NULL; } @@ -253,15 +253,14 @@ static void layerInterp_mdeformvert(const void **sources, MDeformVert *dvert = dest; struct MDeformWeight_Link *dest_dwlink = NULL; struct MDeformWeight_Link *node; - int i, j, totweight; /* build a list of unique def_nrs for dest */ - totweight = 0; - for (i = 0; i < count; i++) { + int totweight = 0; + for (int i = 0; i < count; i++) { const MDeformVert *source = sources[i]; float interp_weight = weights[i]; - for (j = 0; j < source->totweight; j++) { + for (int j = 0; j < source->totweight; j++) { MDeformWeight *dw = &source->dw[j]; float weight = dw->weight * interp_weight; @@ -311,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources, if (totweight) { dvert->totweight = totweight; - for (i = 0, node = dest_dwlink; node; node = node->next, i++) { + int i = 0; + for (node = dest_dwlink; node; node = node->next, i++) { if (node->dw.weight > 1.0f) { node->dw.weight = 1.0f; } @@ -416,18 +416,16 @@ static void layerInterp_tface( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { MTFace *tf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const MTFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -446,9 +444,8 @@ static void layerSwap_tface(void *data, const int *corner_indices) { MTFace *tf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { const int source_index = corner_indices[j]; copy_v2_v2(uv[j], tf->uv[source_index]); } @@ -517,18 +514,16 @@ static void layerInterp_origspace_face( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { OrigSpaceFace *osf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const OrigSpaceFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -546,9 +541,8 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices) { OrigSpaceFace *osf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { copy_v2_v2(uv[j], osf->uv[corner_indices[j]]); } memcpy(osf->uv, uv, sizeof(osf->uv)); @@ -567,13 +561,11 @@ static void layerDefault_origspace_face(void *data, int count) static void layerSwap_mdisps(void *data, const int *ci) { MDisps *s = data; - float(*d)[3] = NULL; - int corners, cornersize, S; if (s->disps) { int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */ - corners = multires_mdisp_corners(s); - cornersize = s->totdisp / corners; + int corners = multires_mdisp_corners(s); + int cornersize = s->totdisp / corners; if (corners != nverts) { /* happens when face changed vertex count in edit mode @@ -585,9 +577,9 @@ static void layerSwap_mdisps(void *data, const int *ci) return; } - d = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); + float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); - for (S = 0; S < corners; S++) { + for (int S = 0; S < corners; S++) { memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize); } @@ -1128,9 +1120,8 @@ static void layerSwap_mcol(void *data, const int *corner_indices) { MCol *mcol = data; MCol col[4]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { col[j] = mcol[corner_indices[j]]; } @@ -2064,13 +2055,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void CustomData_update_typemap(CustomData *data) { - int i, lasttype = -1; + int lasttype = -1; - for (i = 0; i < CD_NUMTYPES; i++) { + for (int i = 0; i < CD_NUMTYPES; i++) { data->typemap[i] = -1; } - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { const int type = data->layers[i].type; if (type != lasttype) { data->typemap[type] = i; @@ -2097,18 +2088,16 @@ bool CustomData_merge(const struct CustomData *source, { /*const LayerTypeInfo *typeInfo;*/ CustomDataLayer *layer, *newlayer; - void *data; - int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, - flag = 0; + int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; int number = 0, maxnumber = -1; bool changed = false; - for (i = 0; i < source->totlayer; i++) { + for (int i = 0; i < source->totlayer; i++) { layer = &source->layers[i]; /*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/ - type = layer->type; - flag = layer->flag; + int type = layer->type; + int flag = layer->flag; if (type != lasttype) { number = 0; @@ -2136,6 +2125,7 @@ bool CustomData_merge(const struct CustomData *source, continue; } + void *data; switch (alloctype) { case CD_ASSIGN: case CD_REFERENCE: @@ -2518,8 +2508,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, /* Passing a layer-data to copy from with an alloctype that won't copy is * most likely a bug */ - BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) || - (alloctype == CD_REFERENCE)); + BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; @@ -2616,10 +2605,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void *CustomData_add_layer( CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem) { - CustomDataLayer *layer; const LayerTypeInfo *typeInfo = layerType_getInfo(type); - layer = customData_add_layer__internal( + CustomDataLayer *layer = customData_add_layer__internal( data, type, alloctype, layerdata, totelem, typeInfo->defaultname); CustomData_update_typemap(data); @@ -2638,9 +2626,8 @@ void *CustomData_add_layer_named(CustomData *data, int totelem, const char *name) { - CustomDataLayer *layer; - - layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, alloctype, layerdata, totelem, name); CustomData_update_typemap(data); if (layer) { @@ -2828,12 +2815,10 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type) void CustomData_free_temporary(CustomData *data, int totelem) { - CustomDataLayer *layer; int i, j; bool changed = false; - for (i = 0, j = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; + CustomDataLayer *layer = &data->layers[i]; if (i != j) { data->layers[j] = data->layers[i]; @@ -3681,10 +3666,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) { - const LayerTypeInfo *typeInfo; int offset = data->layers[n].offset; - - typeInfo = layerType_getInfo(data->layers[n].type); + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); if (typeInfo->set_default) { typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); @@ -4050,7 +4033,6 @@ void CustomData_bmesh_interp(CustomData *data, return; } - int i, j; void *source_buf[SOURCE_BUF_SIZE]; const void **sources = (const void **)source_buf; @@ -4071,11 +4053,11 @@ void CustomData_bmesh_interp(CustomData *data, } /* interpolates a layer at a time */ - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->interp) { - for (j = 0; j < count; j++) { + for (int j = 0; j < count; j++) { sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset); } CustomData_bmesh_interp_n( @@ -4453,7 +4435,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons void CustomData_layers__print(CustomData *data) { - printf("{\n"); int i; @@ -4508,10 +4489,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int { CustomDataExternal *external = data->external; CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; char filename[FILE_MAX]; - const LayerTypeInfo *typeInfo; int update = 0; if (!external) { @@ -4520,7 +4498,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4539,7 +4517,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); if (!cdf_read_open(cdf, filename)) { cdf_free(cdf); CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename); @@ -4548,7 +4526,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4557,7 +4535,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int /* pass */ } else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (blay) { if (cdf_read_layer(cdf, blay)) { @@ -4584,10 +4562,6 @@ void CustomData_external_write( CustomData *data, ID *id, CustomDataMask mask, int totelem, int free) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; - const LayerTypeInfo *typeInfo; int update = 0; char filename[FILE_MAX]; @@ -4597,8 +4571,8 @@ void CustomData_external_write( /* test if there is anything to write */ for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4616,11 +4590,11 @@ void CustomData_external_write( CustomData_external_read(data, id, mask, totelem); customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) { if (layer->flag & CD_FLAG_IN_MEMORY) { @@ -4642,11 +4616,11 @@ void CustomData_external_write( int i; for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (cdf_write_layer(cdf, blay)) { if (typeInfo->write(cdf, layer->data, totelem)) { @@ -4670,8 +4644,8 @@ void CustomData_external_write( } for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { if (free) { @@ -4691,15 +4665,13 @@ void CustomData_external_add( CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - int layer_index; - layer_index = CustomData_get_active_layer_index(data, type); + int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return; } - layer = &data->layers[layer_index]; + CustomDataLayer *layer = &data->layers[layer_index]; if (layer->flag & CD_FLAG_EXTERNAL) { return; @@ -4823,8 +4795,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye cd_interp interp_cd = NULL; cd_copy copy_cd = NULL; - void *tmp_dst; - if (!sources) { /* Not supported here, abort. */ return; @@ -4841,7 +4811,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye copy_cd = type_info->copy; } - tmp_dst = MEM_mallocN(data_size, __func__); + void *tmp_dst = MEM_mallocN(data_size, __func__); if (count > 1 && !interp_cd) { if (data_flag) { @@ -5104,6 +5074,10 @@ void CustomData_blend_write(BlendWriter *writer, const int *layer_data = 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; + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); + } else { const char *structname; int structnum; @@ -5193,6 +5167,16 @@ 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) { + /* 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."); + const LayerTypeInfo *info = layerType_getInfo(layer->type); + layer->data = MEM_calloc_arrayN((size_t)count, info->size, layerType_getName(layer->type)); + if (info->set_default) { + info->set_default(layer->data, count); + } + } if (layer->type == CD_MDISPS) { blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); } diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 7a3239babd4..833e1dd3719 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -26,6 +26,7 @@ #include "MEM_guardedalloc.h" using blender::float3; +using blender::float4x4; using blender::MutableSpan; using blender::Span; using blender::StringRef; @@ -482,9 +483,7 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentTy GeometryComponent *InstancesComponent::copy() const { InstancesComponent *new_component = new InstancesComponent(); - new_component->positions_ = positions_; - new_component->rotations_ = rotations_; - new_component->scales_ = scales_; + new_component->transforms_ = transforms_; new_component->instanced_data_ = instanced_data_; return new_component; } @@ -492,45 +491,29 @@ GeometryComponent *InstancesComponent::copy() const void InstancesComponent::clear() { instanced_data_.clear(); - positions_.clear(); - rotations_.clear(); - scales_.clear(); + transforms_.clear(); } -void InstancesComponent::add_instance(Object *object, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) { InstancedData data; data.type = INSTANCE_DATA_TYPE_OBJECT; data.data.object = object; - this->add_instance(data, position, rotation, scale, id); + this->add_instance(data, transform, id); } -void InstancesComponent::add_instance(Collection *collection, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) { InstancedData data; data.type = INSTANCE_DATA_TYPE_COLLECTION; data.data.collection = collection; - this->add_instance(data, position, rotation, scale, id); + this->add_instance(data, transform, id); } -void InstancesComponent::add_instance(InstancedData data, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) { instanced_data_.append(data); - positions_.append(position); - rotations_.append(rotation); - scales_.append(scale); + transforms_.append(transform); ids_.append(id); } @@ -539,19 +522,9 @@ Span InstancesComponent::instanced_data() const return instanced_data_; } -Span InstancesComponent::positions() const +Span InstancesComponent::transforms() const { - return positions_; -} - -Span InstancesComponent::rotations() const -{ - return rotations_; -} - -Span InstancesComponent::scales() const -{ - return scales_; + return transforms_; } Span InstancesComponent::ids() const @@ -559,33 +532,21 @@ Span InstancesComponent::ids() const return ids_; } -MutableSpan InstancesComponent::positions() +MutableSpan InstancesComponent::transforms() { - return positions_; -} - -MutableSpan InstancesComponent::rotations() -{ - return rotations_; -} - -MutableSpan InstancesComponent::scales() -{ - return scales_; + return transforms_; } int InstancesComponent::instances_amount() const { const int size = instanced_data_.size(); - BLI_assert(positions_.size() == size); - BLI_assert(rotations_.size() == size); - BLI_assert(scales_.size() == size); + BLI_assert(transforms_.size() == size); return size; } bool InstancesComponent::is_empty() const { - return positions_.size() == 0; + return transforms_.size() == 0; } /** \} */ @@ -684,9 +645,7 @@ bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set) } int BKE_geometry_set_instances(const GeometrySet *geometry_set, - float (**r_positions)[3], - float (**r_rotations)[3], - float (**r_scales)[3], + float (**r_transforms)[4][4], int **r_ids, InstancedData **r_instanced_data) { @@ -694,9 +653,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, if (component == nullptr) { return 0; } - *r_positions = (float(*)[3])component->positions().data(); - *r_rotations = (float(*)[3])component->rotations().data(); - *r_scales = (float(*)[3])component->scales().data(); + *r_transforms = (float(*)[4][4])component->transforms().data(); *r_ids = (int *)component->ids().data(); *r_instanced_data = (InstancedData *)component->instanced_data().data(); *r_instanced_data = (InstancedData *)component->instanced_data().data(); diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b0991f1d343..6b164e6bc50 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -92,11 +92,9 @@ IDProperty *IDP_NewIDPArray(const char *name) IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) { /* don't use MEM_dupallocN because this may be part of an array */ - IDProperty *narray, *tmp; - BLI_assert(array->type == IDP_IDPARRAY); - narray = MEM_mallocN(sizeof(IDProperty), __func__); + IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__); *narray = *array; narray->data.pointer = MEM_dupallocN(array->data.pointer); @@ -107,7 +105,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) * then free it. this makes for more maintainable * code than simply re-implementing the copy functions * in this loop.*/ - tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); + IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); MEM_freeN(tmp); } @@ -131,15 +129,13 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) /* shallow copies item */ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) { - IDProperty *old; - BLI_assert(prop->type == IDP_IDPARRAY); if (index >= prop->len || index < 0) { return; } - old = GETPROP(prop, index); + IDProperty *old = GETPROP(prop, index); if (item != old) { IDP_FreePropertyContent(old); @@ -164,8 +160,6 @@ void IDP_AppendArray(IDProperty *prop, IDProperty *item) void IDP_ResizeIDPArray(IDProperty *prop, int newlen) { - int newsize; - BLI_assert(prop->type == IDP_IDPARRAY); /* first check if the array buffer size has room */ @@ -200,7 +194,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); prop->len = newlen; @@ -218,9 +212,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /* bigger */ IDProperty **array = newarr; IDPropertyTemplate val; - int a; - for (a = prop->len; a < newlen; a++) { + for (int a = prop->len; a < newlen; a++) { val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group"); } @@ -228,9 +221,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) else { /* smaller */ IDProperty **array = prop->data.pointer; - int a; - for (a = newlen; a < prop->len; a++) { + for (int a = newlen; a < prop->len; a++) { IDP_FreeProperty(array[a]); } } @@ -239,7 +231,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /*this function works for strings too!*/ void IDP_ResizeArray(IDProperty *prop, int newlen) { - int newsize; const bool is_grow = newlen >= prop->len; /* first check if the array buffer size has room */ @@ -257,7 +248,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; if (is_grow == false) { @@ -362,10 +353,8 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_STRING); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); if (prop->data.pointer) { newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -379,10 +368,8 @@ static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) { - int stlen; - BLI_assert(prop->type == IDP_STRING); - stlen = (int)strlen(st); + int stlen = (int)strlen(st); if (maxlen > 0 && maxlen < stlen) { stlen = maxlen; } @@ -400,11 +387,9 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) void IDP_ConcatStringC(IDProperty *prop, const char *st) { - int newlen; - BLI_assert(prop->type == IDP_STRING); - newlen = prop->len + (int)strlen(st); + int newlen = prop->len + (int)strlen(st); /* we have to remember that prop->len includes the null byte for strings. * so there's no need to add +1 to the resize function.*/ IDP_ResizeArray(prop, newlen); @@ -413,13 +398,11 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st) void IDP_ConcatString(IDProperty *str1, IDProperty *append) { - int newlen; - BLI_assert(append->type == IDP_STRING); /* since ->len for strings includes the NULL byte, we have to subtract one or * we'll get an extra null byte after each concatenation operation.*/ - newlen = str1->len + append->len - 1; + int newlen = str1->len + append->len - 1; IDP_ResizeArray(str1, newlen); strcat(str1->data.pointer, append->data.pointer); } @@ -440,10 +423,8 @@ void IDP_FreeString(IDProperty *prop) static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_ID); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->data.pointer = prop->data.pointer; if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -479,14 +460,12 @@ void IDP_AssignID(IDProperty *prop, ID *id, const int flag) */ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) { - IDProperty *newp, *link; - BLI_assert(prop->type == IDP_GROUP); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->len = prop->len; newp->subtype = prop->subtype; - for (link = prop->data.group.first; link; link = link->next) { + LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) { BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); } @@ -497,13 +476,11 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) * When values name and types match, copy the values, else ignore */ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) { - IDProperty *other, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { - other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); if (other && prop->type == other->type) { switch (prop->type) { case IDP_INT: @@ -526,12 +503,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen) { - IDProperty *prop_dst, *prop_dst_next; - const IDProperty *prop_src; - - for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) { - prop_dst_next = prop_dst->next; - if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) { + LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) { + const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name); + if (prop_src != NULL) { /* check of we should replace? */ if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && @@ -554,12 +528,11 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a */ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) { - IDProperty *loop, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *loop; for (loop = dest->data.group.first; loop; loop = loop->next) { if (STREQ(loop->name, prop->name)) { BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); @@ -612,13 +585,11 @@ void IDP_MergeGroup_ex(IDProperty *dest, const bool do_overwrite, const int flag) { - IDProperty *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); if (do_overwrite) { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { if (prop->type == IDP_GROUP) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); @@ -633,7 +604,7 @@ void IDP_MergeGroup_ex(IDProperty *dest, } } else { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); if (prop_exist != NULL) { if (prop->type == IDP_GROUP) { @@ -741,10 +712,9 @@ IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *nam * direct data. */ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) { - IDProperty *loop; - BLI_assert(prop->type == IDP_GROUP); - for (loop = prop->data.group.first; loop; loop = loop->next) { + + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_FreePropertyContent_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); @@ -863,14 +833,12 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is } return false; case IDP_GROUP: { - IDProperty *link1, *link2; - if (is_strict && prop1->len != prop2->len) { return false; } - for (link1 = prop1->data.group.first; link1; link1 = link1->next) { - link2 = IDP_GetPropertyFromGroup(prop2, link1->name); + LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) { + IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name); if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) { return false; @@ -1158,11 +1126,10 @@ static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { const IDProperty *array = prop->data.pointer; - int a; BLO_write_struct_array(writer, IDProperty, prop->len, array); - for (a = 0; a < prop->len; a++) { + for (int a = 0; a < prop->len; a++) { IDP_WriteProperty_OnlyData(&array[a], writer); } } @@ -1176,9 +1143,7 @@ static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) { - IDProperty *loop; - - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_BlendWrite(writer, loop); } } @@ -1212,13 +1177,11 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty *array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; BLO_read_data_address(reader, &prop->data.pointer); - array = (IDProperty *)prop->data.pointer; + IDProperty *array = (IDProperty *)prop->data.pointer; /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared * there's not really anything we can do to correct this, at least don't crash */ @@ -1234,14 +1197,12 @@ static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty **array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; if (prop->subtype == IDP_GROUP) { BLO_read_pointer_array(reader, &prop->data.pointer); - array = prop->data.pointer; + IDProperty **array = prop->data.pointer; for (int i = 0; i < prop->len; i++) { IDP_DirectLinkProperty(array[i], reader); @@ -1266,12 +1227,11 @@ static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader) { ListBase *lb = &prop->data.group; - IDProperty *loop; BLO_read_list(reader, lb); /*Link child id properties now*/ - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_DirectLinkProperty(loop, reader); } } diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index b0438500413..7df0e08d405 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -422,7 +422,7 @@ static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_NOP; } -/* Tag all IDs in dependency relationships whithin an override hierarchy/group. +/* Tag all IDs in dependency relationships within an override hierarchy/group. * * Note: this is typically called to complete `lib_override_linked_group_tag()`. * Note: BMain's relations mapping won't be valid anymore after that call. @@ -464,8 +464,8 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain, /* This will tag at least all 'boundary' linked IDs for a potential override group. * - * Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to - * complete tagging of all dependencies whitin theoverride group. + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. * * We currently only consider Collections and Objects (that are not used as bone shapes) as valid * boundary IDs to define an override group. @@ -483,7 +483,7 @@ static void lib_override_linked_group_tag(Main *bmain, BKE_library_foreach_ID_link( bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE); - /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitely + /* 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 & tag)) { @@ -559,8 +559,8 @@ static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data) /* This will tag at least all 'boundary' linked IDs for a potential override group. * - * Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to - * complete tagging of all dependencies whitin theoverride group. + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. * * We currently only consider Collections and Objects (that are not used as bone shapes) as valid * boundary IDs to define an override group. diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 441da8b134a..45ac20ef154 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -781,7 +781,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene, smd.levels = smd.renderLevels = lvl; smd.quality = 3; if (!is_plain_uv) { - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; } else { smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index f121f34d772..247bfafc099 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3574,7 +3574,7 @@ typedef struct bNodeClipboard { static bNodeClipboard node_clipboard = {{NULL}}; -void BKE_node_clipboard_init(struct bNodeTree *ntree) +void BKE_node_clipboard_init(const struct bNodeTree *ntree) { node_clipboard.type = ntree->type; } @@ -3718,11 +3718,11 @@ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str return hash; } -bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node) +bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, + const bNodeTree *ntree, + const bNode *node) { - bNodeInstanceKey key; - - key = node_hash_int_str(parent_key, ntree->id.name + 2); + bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2); if (node) { key = node_hash_int_str(key, node->name); @@ -4750,6 +4750,7 @@ static void registerGeometryNodes(void) register_node_type_geo_point_rotate(); register_node_type_geo_align_rotation_to_vector(); register_node_type_geo_sample_texture(); + register_node_type_geo_points_to_volume(); } static void registerFunctionNodes(void) diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index d5317864480..6c8a57f8599 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -813,40 +813,26 @@ static const DupliGenerator gen_dupli_verts_pointcloud = { static void make_duplis_instances_component(const DupliContext *ctx) { - float(*positions)[3]; - float(*rotations)[3]; - float(*scales)[3]; + float(*instance_offset_matrices)[4][4]; int *ids; InstancedData *instanced_data; - const int amount = BKE_geometry_set_instances(ctx->object->runtime.geometry_set_eval, - &positions, - &rotations, - &scales, - &ids, - &instanced_data); + const int amount = BKE_geometry_set_instances( + ctx->object->runtime.geometry_set_eval, &instance_offset_matrices, &ids, &instanced_data); for (int i = 0; i < amount; i++) { InstancedData *data = &instanced_data[i]; - float scale_matrix[4][4]; - size_to_mat4(scale_matrix, scales[i]); - float rotation_matrix[4][4]; - eul_to_mat4(rotation_matrix, rotations[i]); - float instance_offset_matrix[4][4]; - mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix); - copy_v3_v3(instance_offset_matrix[3], positions[i]); - const int id = ids[i] != -1 ? ids[i] : i; if (data->type == INSTANCE_DATA_TYPE_OBJECT) { Object *object = data->data.object; if (object != NULL) { float matrix[4][4]; - mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix); + mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i]); make_dupli(ctx, object, matrix, id); float space_matrix[4][4]; - mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat); + mul_m4_m4m4(space_matrix, instance_offset_matrices[i], object->imat); mul_m4_m4_pre(space_matrix, ctx->object->obmat); make_recursive_duplis(ctx, object, space_matrix, id); } @@ -857,7 +843,7 @@ static void make_duplis_instances_component(const DupliContext *ctx) float collection_matrix[4][4]; unit_m4(collection_matrix); sub_v3_v3(collection_matrix[3], collection->instance_offset); - mul_m4_m4_pre(collection_matrix, instance_offset_matrix); + mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i]); mul_m4_m4_pre(collection_matrix, ctx->object->obmat); eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index e78576206de..5f99f629f42 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -586,7 +586,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack, BLI_strncpy(us->name, name, sizeof(us->name)); } us->type = ut; - /* True by default, code needs to explicitely set it to false if necessary. */ + /* True by default, code needs to explicitly set it to false if necessary. */ us->use_old_bmain_data = true; /* Initialized, not added yet. */ diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh index 0433197b22a..d6d759ccfe4 100644 --- a/source/blender/blenlib/BLI_float4x4.hh +++ b/source/blender/blenlib/BLI_float4x4.hh @@ -45,6 +45,17 @@ struct float4x4 { return &values[0][0]; } + using c_style_float4x4 = float[4][4]; + c_style_float4x4 &ptr() + { + return values; + } + + const c_style_float4x4 &ptr() const + { + return values; + } + friend float4x4 operator*(const float4x4 &a, const float4x4 &b) { float4x4 result; diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 21e7b2b92d4..c3ddcc098b1 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1505,7 +1505,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 292, 10)) { if (!DNA_struct_find(fd->filesdna, "NodeSetAlpha")) { - LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { if (ntree->type != NTREE_COMPOSIT) { continue; } @@ -1518,6 +1518,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) node->storage = storage; } } + FOREACH_NODETREE_END; } LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { @@ -1636,6 +1637,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) { + /* Add support for all operations to the "Attribute Math" node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == GEO_NODE_ATTRIBUTE_MATH) { + NodeAttributeMath *data = (NodeAttributeMath *)node->storage; + data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + } + } + } + } + FOREACH_NODETREE_END; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index ec98969b223..a0d5bc2953b 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -68,7 +68,8 @@ class RenderLayersProg : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; /** * retrieve the reference to the float buffer of the renderer. @@ -118,9 +119,9 @@ class RenderLayersProg : public NodeOperation { { return this->m_viewName; } - void initExecution(); - void deinitExecution(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void initExecution() override; + void deinitExecution() override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; std::unique_ptr getMetaData() const override; }; diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h index 435083f5008..712347a8ea2 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.h +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h @@ -24,11 +24,11 @@ class SocketProxyOperation : public NodeOperation { public: SocketProxyOperation(DataType type, bool use_conversion); - bool isProxyOperation() const + bool isProxyOperation() const override { return true; } - bool useDatatypeConversion() const + bool useDatatypeConversion() const override { return m_use_conversion; } diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index c566b35cd34..4f689fd55a5 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -137,6 +137,15 @@ static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBE wd->use_specular = workbench_is_specular_highlight_enabled(wpd); } +void workbench_private_data_alloc(WORKBENCH_StorageList *stl) +{ + if (!stl->wpd) { + stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); + stl->wpd->taa_sample_len_previous = -1; + stl->wpd->view_updated = true; + } +} + void workbench_private_data_init(WORKBENCH_PrivateData *wpd) { const DRWContextState *draw_ctx = DRW_context_state_get(); diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index fcee8c270dd..73cd501190f 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -133,14 +133,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); RegionView3D *rv3d = draw_ctx->rv3d; View3D *v3d = draw_ctx->v3d; - Scene *scene = draw_ctx->scene; + Object *camera; if (v3d && rv3d) { camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; } else { - camera = scene->camera; + camera = wpd->cam_original_ob; } Camera *cam = camera != NULL ? camera->data : NULL; diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 37dbfe4d2a6..bd5b61b26e9 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -53,12 +53,7 @@ void workbench_engine_init(void *ved) workbench_shader_library_ensure(); - if (!stl->wpd) { - stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); - stl->wpd->taa_sample_len_previous = -1; - stl->wpd->view_updated = true; - } - + workbench_private_data_alloc(stl); WORKBENCH_PrivateData *wpd = stl->wpd; workbench_private_data_init(wpd); workbench_update_world_ubo(wpd); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index f3ff0616668..d157c260fbd 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -70,6 +70,7 @@ extern struct DrawEngineType draw_engine_workbench; #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) +struct Object; struct RenderEngine; struct RenderLayer; struct rcti; @@ -351,6 +352,9 @@ typedef struct WORKBENCH_PrivateData { float dof_rotation; float dof_ratio; + /* Camera override for rendering. */ + struct Object *cam_original_ob; + /** True if any volume needs to be rendered. */ bool volumes_do; /** Convenience boolean. */ @@ -504,6 +508,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR) /* workbench_data.c */ +void workbench_private_data_alloc(WORKBENCH_StorageList *stl); void workbench_private_data_init(WORKBENCH_PrivateData *wpd); void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd); void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 2c3b5a5f935..cec372ba732 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -175,6 +175,8 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer return; } + workbench_private_data_alloc(data->stl); + data->stl->wpd->cam_original_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); workbench_engine_init(data); workbench_cache_init(data); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1115d819659..f474ae542d9 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1715,8 +1715,8 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph, GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); - - GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management); + const bool do_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management, do_overlays); if (draw_background) { /* Reset default. */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index a6e96a4d919..7afb03b833d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -393,7 +393,11 @@ static void anim_channels_select_set(bAnimContext *ac, FCurve *fcu = (FCurve *)ale->data; ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); - fcu->flag &= ~FCURVE_ACTIVE; + if ((fcu->flag & FCURVE_SELECTED) == 0) { + /* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves" + * retains the currently active curve. */ + fcu->flag &= ~FCURVE_ACTIVE; + } break; } case ANIMTYPE_SHAPEKEY: { @@ -1197,7 +1201,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn rearrange_animchannel_islands( &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); - /* Add back non-local NLA tracks at the begining of the animation data's list. */ + /* Add back non-local NLA tracks at the beginning of the animation data's list. */ if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) { BLI_assert(is_liboverride); ((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first; diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index f5240d67cca..034378399b9 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -124,29 +124,22 @@ static void draw_current_frame(const Scene *scene, UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_3fv_alpha( - &(const rctf){ - .xmin = frame_x - box_width / 2 + U.pixelsize / 2, - .xmax = frame_x + box_width / 2 + U.pixelsize / 2, - .ymin = scrub_region_rect->ymin + box_padding, - .ymax = scrub_region_rect->ymax - box_padding, - }, - true, - 4 * UI_DPI_FAC, - bg_color, - 1.0f); + float outline_color[4]; + UI_GetThemeColorShade4fv(TH_CFRAME, 5, outline_color); - UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color); - UI_draw_roundbox_aa( + UI_draw_roundbox_4fv_ex( &(const rctf){ .xmin = frame_x - box_width / 2 + U.pixelsize / 2, .xmax = frame_x + box_width / 2 + U.pixelsize / 2, .ymin = scrub_region_rect->ymin + box_padding, .ymax = scrub_region_rect->ymax - box_padding, }, - true, - 4 * UI_DPI_FAC, - bg_color); + bg_color, + NULL, + 1.0f, + outline_color, + U.pixelsize, + 4 * UI_DPI_FAC); uchar text_color[4]; UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color); diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 84447059884..8e17816dcc1 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1154,8 +1154,8 @@ static int gpencil_points_from_stack(tGPDfill *tgpf) static void gpencil_stroke_from_buffer(tGPDfill *tgpf) { ToolSettings *ts = tgpf->scene->toolsettings; - const char *align_flag = &ts->gpencil_v3d_align; - const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); + const char align_flag = ts->gpencil_v3d_align; + const bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) && (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth); Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); @@ -1284,8 +1284,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 7571f7cded8..b55e47d74f3 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1086,8 +1086,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } } @@ -1235,8 +1235,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ gpencil_apply_parent(depsgraph, obact, gpl, gps); - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index ef86b19cc66..3a0e1ce3d15 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -715,8 +715,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) bGPDstroke *gps = tgpi->gpf->strokes.first; GP_Sculpt_Settings *gset = &ts->gp_sculpt; int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; - const char *align_flag = &ts->gpencil_v3d_align; - bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); + const char align_flag = ts->gpencil_v3d_align; + bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth); @@ -1081,8 +1081,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps); } diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 0a66c439f79..56494f87bfe 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -99,6 +99,30 @@ void ED_space_clip_set_clip(struct bContext *C, struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc); void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask); +/* Locked state is used to preserve current clip editor viewport upon changes. Example usage: + * + * ... + * + * ClipViewLockState lock_state; + * ED_clip_view_lock_state_store(C, &lock_state); + * + * + * + * ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + * + * These function are to be used from space clip editor context only. Otherwise debug builds will + * assert, release builds will crash. */ + +typedef struct ClipViewLockState { + float offset_x, offset_y; + float lock_offset_x, lock_offset_y; + float zoom; +} ClipViewLockState; + +void ED_clip_view_lock_state_store(const struct bContext *C, ClipViewLockState *state); +void ED_clip_view_lock_state_restore_no_jump(const struct bContext *C, + const ClipViewLockState *state); + /* ** clip_ops.c ** */ void ED_operatormacros_clip(void); diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index bcf52da3f69..b20dae694fc 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -63,7 +63,10 @@ void ED_mask_point_pos__reverse( struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr); void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]); -bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]); +bool ED_mask_selected_minmax(const struct bContext *C, + float min[2], + float max[2], + bool include_handles); /* mask_draw.c */ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 991e8aaf89a..f4e68ca3909 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -991,12 +991,26 @@ extern void ui_draw_but(const struct bContext *C, uiBut *but, rcti *rect); +/** + * Info about what the separator character separates, used to decide between different drawing + * styles. E.g. we never want a shortcut string to be clipped, but other hint strings can be + * clipped. + */ +typedef enum { + UI_MENU_ITEM_SEPARATOR_NONE, + /** Separator is used to indicate shortcut string of this item. Shortcut string will not get + * clipped. */ + UI_MENU_ITEM_SEPARATOR_SHORTCUT, + /** Separator is used to indicate some additional hint to display for this item. Hint string will + * get clipped before the normal text. */ + UI_MENU_ITEM_SEPARATOR_HINT, +} uiMenuItemSeparatorType; void ui_draw_menu_item(const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, - bool use_sep, + uiMenuItemSeparatorType separator_type, int *r_xmax); void ui_draw_preview_item( const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state); diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 7a665909c76..816162e9aa2 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -610,7 +610,15 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) char *name = data->items.names[a]; int icon = data->items.icons[a]; char *name_sep_test = NULL; - const bool use_sep_char = data->use_sep || (state & UI_BUT_HAS_SEP_CHAR); + + uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE; + if (data->use_sep) { + separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT; + } + /* Only set for displaying additional hint (e.g. library name of a linked data-block). */ + else if (state & UI_BUT_HAS_SEP_CHAR) { + separator_type = UI_MENU_ITEM_SEPARATOR_HINT; + } ui_searchbox_butrect(&rect, data, a); @@ -623,7 +631,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) } /* Simple menu item. */ - ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, use_sep_char, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL); } else { /* Split menu item, faded text before the separator. */ @@ -637,8 +645,13 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) const char name_sep_prev = *name_sep; *name_sep = '\0'; int name_width = 0; - ui_draw_menu_item( - &data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width); + ui_draw_menu_item(&data->fstyle, + &rect, + name, + 0, + state | UI_BUT_INACTIVE, + UI_MENU_ITEM_SEPARATOR_NONE, + &name_width); *name_sep = name_sep_prev; rect.xmin += name_width; rect.xmin += UI_UNIT_X / 4; @@ -650,7 +663,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) /* The previous menu item draws the active selection. */ ui_draw_menu_item( - &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, use_sep_char, NULL); + &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, separator_type, NULL); } } /* indicate more */ @@ -943,10 +956,16 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre), data->items.icons[a], state, - false, + UI_MENU_ITEM_SEPARATOR_NONE, + NULL); + ui_draw_menu_item(&data->fstyle, + &rect_post, + data->items.names[a], + 0, + state, + data->use_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT : + UI_MENU_ITEM_SEPARATOR_NONE, NULL); - ui_draw_menu_item( - &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL); } } /* indicate more */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a99f05730bb..89720cbf17e 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1533,27 +1533,24 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle, { BLI_assert(str[0]); - /* If the trailing ellipsis takes more than 20% of all available width, just cut the string - * (as using the ellipsis would remove even more useful chars, and we cannot show much - * already!). - */ - if (sep_strwidth / okwidth > 0.2f) { - float tmp; - const int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp); - str[l_end] = '\0'; - if (r_final_len) { - *r_final_len = (size_t)l_end; - } - } - else { - float tmp; - const int l_end = BLF_width_to_strlen( - fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp); + /* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */ + int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, NULL); + + if (l_end > 0) { + /* At least one character, so clip and add the ellipsis. */ memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */ if (r_final_len) { *r_final_len = (size_t)(l_end) + sep_len; } } + else { + /* Otherwise fit as much as we can without adding an ellipsis. */ + l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, NULL); + str[l_end] = '\0'; + if (r_final_len) { + *r_final_len = (size_t)l_end; + } + } } /** @@ -5211,8 +5208,7 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl * * \param state: The state of the button, * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE. - * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned, - * use for displaying key shortcuts. + * \param separator_type: The kind of separator which controls if and how the string is clipped. * \param r_xmax: The right hand position of the text, this takes into the icon, * padding and text clipping when there is not enough room to display the full text. */ @@ -5221,11 +5217,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, const char *name, int iconid, int state, - bool use_sep, + uiMenuItemSeparatorType separator_type, int *r_xmax) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); const rcti _rect = *rect; + int max_hint_width = INT_MAX; + int padding = 0.25f * UI_UNIT_X; char *cpoin = NULL; wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED); @@ -5234,13 +5232,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, UI_fontstyle_set(fstyle); /* text location offset */ - rect->xmin += 0.25f * UI_UNIT_X; + rect->xmin += padding; if (iconid) { rect->xmin += UI_DPI_ICON_SIZE; } /* cut string in 2 parts? */ - if (use_sep) { + if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) { cpoin = strrchr(name, UI_SEP_CHAR); if (cpoin) { *cpoin = 0; @@ -5253,7 +5251,30 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); } - rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; + if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) { + /* Shrink rect to exclude the shortcut string. */ + rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; + } + else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) { + /* Determine max-width for the hint string to leave the name string un-clipped (if there's + * enough space to display it). */ + + const int available_width = BLI_rcti_size_x(rect) - padding; + const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX); + const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding; + + if ((name_width + hint_width) > available_width) { + /* Clipping width for hint string. */ + max_hint_width = available_width * 0.40f; + /* Clipping xmax for clipping of item name. */ + rect->xmax = (hint_width < max_hint_width) ? + (rect->xmax - hint_width) : + (rect->xmin + (available_width - max_hint_width)); + } + } + else { + BLI_assert(!"Unknwon menu item separator type"); + } if (fstyle->kerning == 1) { BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); @@ -5308,15 +5329,26 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, } /* part text right aligned */ - if (use_sep) { + if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) { if (cpoin) { /* Set inactive state for grayed out text. */ wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED); + char hint_drawstr[UI_MAX_DRAW_STR]; + { + const size_t max_len = sizeof(hint_drawstr); + const float minwidth = (float)(UI_DPI_ICON_SIZE); + + BLI_strncpy(hint_drawstr, cpoin + 1, sizeof(hint_drawstr)); + if (hint_drawstr[0] && (max_hint_width < INT_MAX)) { + UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0'); + } + } + rect->xmax = _rect.xmax - 5; UI_fontstyle_draw(fstyle, rect, - cpoin + 1, + hint_drawstr, wt->wcol.text, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_RIGHT, diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index d7b3d74bc7e..1226cc57359 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -507,6 +507,9 @@ static int add_vertex_handle_cyclic( static int add_vertex_exec(bContext *C, wmOperator *op) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + Mask *mask = CTX_data_edit_mask(C); if (mask == NULL) { /* if there's no active mask, create one */ @@ -548,6 +551,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -690,6 +695,9 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) static int create_primitive_from_points( bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ScrArea *area = CTX_wm_area(C); int size = RNA_float_get(op->ptr, "size"); @@ -752,6 +760,8 @@ static int create_primitive_from_points( DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 663ae0097ad..e6c6424e5f0 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -184,3 +184,39 @@ void ED_operatormacros_mask(void) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lock-to-selection viewport preservation + * \{ */ + +void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + ED_clip_view_lock_state_store(C, &state->space_clip_state); + } +} + +void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + /* Early output if the editor is not locked to selection. + * Avoids forced dependency graph evaluation here. */ + return; + } + + /* Mask's lock-to-selection requres deformed splines to be evaluated to calculate bounds of + * points after animation has been evaluated. The restore-no-jump type of function does + * calculation of new offset for the view for an updated state of mask to cancel the offset out + * by modifying locked offset. In order to do such calculation mask needs to be evaluated after + * modification by an operator. */ + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + (void)depsgraph; + + ED_clip_view_lock_state_restore_no_jump(C, &state->space_clip_state); + } +} + +/** \} */ diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index f6990583383..ee1784011ea 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -23,6 +23,8 @@ #pragma once +#include "ED_clip.h" + struct Mask; struct bContext; struct wmOperatorType; @@ -92,6 +94,19 @@ void ED_mask_select_flush_all(struct Mask *mask); bool ED_maskedit_poll(struct bContext *C); bool ED_maskedit_mask_poll(struct bContext *C); +/* Generalized solution for preserving editor viewport when making changes while lock-to-selection + * is enabled. + * Any mask operator can use this API, without worrying that some editors do not have an idea of + * lock-to-selection. */ + +typedef struct MaskViewLockState { + ClipViewLockState space_clip_state; +} MaskViewLockState; + +void ED_mask_view_lock_state_store(const struct bContext *C, MaskViewLockState *state); +void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C, + const MaskViewLockState *state); + /* mask_query.c */ bool ED_mask_find_nearest_diff_point(const struct bContext *C, struct Mask *mask, diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 25cc39bf9a0..00a1dfb7d87 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -226,6 +226,12 @@ typedef struct SlidePointData { int width, height; float prev_mouse_coord[2]; + + /* Previous clip coordinate which was resolved from mouse position (0, 0). + * Is used to compansate for view offste moving in-between of mouse events when + * lock-to-selection is enabled. */ + float prev_zero_coord[2]; + float no[2]; bool is_curvature_only, is_accurate, is_initial_feather, is_overall_feather; @@ -431,6 +437,9 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * const float threshold = 19; eMaskWhichHandle which_handle; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(area, region, event->mval, co); ED_mask_get_size(area, &width, &height); @@ -530,7 +539,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * } customdata->which_handle = which_handle; + { + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, 0); + + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + } + ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord); + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, customdata->prev_zero_coord); } return customdata; @@ -655,10 +672,24 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_mask_mouse_pos(area, region, event->mval, co); sub_v2_v2v2(delta, co, data->prev_mouse_coord); + copy_v2_v2(data->prev_mouse_coord, co); + + /* Compensate for possibly moved view offset since the last event. + * The idea is to see how mapping of a fixed and known position did change. */ + { + float zero_coord[2]; + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, zero_coord); + + float zero_delta[2]; + sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord); + sub_v2_v2(delta, zero_delta); + + copy_v2_v2(data->prev_zero_coord, zero_coord); + } + if (data->is_accurate) { mul_v2_fl(delta, 0.2f); } - copy_v2_v2(data->prev_mouse_coord, co); if (data->action == SLIDE_ACTION_HANDLE) { float new_handle[2]; @@ -966,6 +997,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, float u, co[2]; BezTriple *next_bezt; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co); if (!ED_mask_find_nearest_diff_point(C, @@ -1047,6 +1081,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, mask_layer->act_point = point; ED_mask_select_flush_all(mask); + DEG_id_tag_update(&mask->id, 0); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return slide_data; } diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c index cfd57ca3477..8f4f14a1ba8 100644 --- a/source/blender/editors/mask/mask_query.c +++ b/source/blender/editors/mask/mask_query.c @@ -604,7 +604,7 @@ void ED_mask_point_pos__reverse( *yr = co[1]; } -bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) +bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool include_handles) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Mask *mask = CTX_data_edit_mask(C); @@ -638,22 +638,29 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) } if (bezt->f2 & SELECT) { minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]); + ok = true; } - if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + + if (!include_handles) { + /* Ignore handles. */ + } + else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } else { if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } } - ok = true; } } } diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index cdc6ece1e84..5c369afc4cd 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -214,12 +214,17 @@ static int select_all_exec(bContext *C, wmOperator *op) Mask *mask = CTX_data_edit_mask(C); int action = RNA_enum_get(op->ptr, "action"); + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_select_toggle_all(mask, action); ED_mask_select_flush_all(mask); DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -261,6 +266,9 @@ static int select_exec(bContext *C, wmOperator *op) eMaskWhichHandle which_handle; const float threshold = 19; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", co); point = ED_mask_point_find_nearest( @@ -324,6 +332,8 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -364,12 +374,15 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } if (deselect_all) { /* For clip editor tracks, leave deselect all to clip editor. */ if (!ED_clip_can_select(C)) { ED_mask_deselect_all(C); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); return OPERATOR_FINISHED; } } diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 51d94e6a533..11ad030f3ae 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -7736,7 +7736,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd, (brush->sculpt_tool == SCULPT_TOOL_FAIRING) || (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) || (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) || - (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS)); + (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) || + (brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR)); } void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush) diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index bd11a746e11..af1d082d317 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -327,118 +327,18 @@ void ED_clip_update_frame(const Main *mainp, int cfra) } } -static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +bool ED_clip_view_selection(const bContext *C, ARegion *UNUSED(region), bool fit) { - MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingTrack *track; - int width, height; - bool ok = false; - ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - INIT_MINMAX2(min, max); - - ED_space_clip_get_size(sc, &width, &height); - - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track)) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - - if (marker) { - float pos[3]; - - pos[0] = marker->pos[0] + track->offset[0]; - pos[1] = marker->pos[1] + track->offset[1]; - pos[2] = 0.0f; - - /* undistortion happens for normalized coords */ - if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { - /* undistortion happens for normalized coords */ - ED_clip_point_undistorted_pos(sc, pos, pos); - } - - pos[0] *= width; - pos[1] *= height; - - mul_v3_m4v3(pos, sc->stabmat, pos); - - minmax_v2v2_v2(min, max, pos); - - ok = true; - } - } - - track = track->next; - } - - return ok; -} - -static bool selected_boundbox(const bContext *C, float min[2], float max[2]) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - if (sc->mode == SC_MODE_TRACKING) { - return selected_tracking_boundbox(sc, min, max); - } - - if (ED_mask_selected_minmax(C, min, max)) { - MovieClip *clip = ED_space_clip_get_clip(sc); - int width, height; - ED_space_clip_get_size(sc, &width, &height); - BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); - BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); - min[0] *= width; - min[1] *= height; - max[0] *= width; - max[1] *= height; - return true; - } - return false; -} - -bool ED_clip_view_selection(const bContext *C, ARegion *region, bool fit) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - int w, h, frame_width, frame_height; - float min[2], max[2]; - - ED_space_clip_get_size(sc, &frame_width, &frame_height); - - if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) { return false; } - if (!selected_boundbox(C, min, max)) { - return false; - } - - /* center view */ - clip_view_center_to_point( - sc, (max[0] + min[0]) / (2 * frame_width), (max[1] + min[1]) / (2 * frame_height)); - - w = max[0] - min[0]; - h = max[1] - min[1]; - - /* set zoom to see all selection */ - if (w > 0 && h > 0) { - int width, height; - float zoomx, zoomy, newzoom, aspx, aspy; - - ED_space_clip_get_aspect(sc, &aspx, &aspy); - - width = BLI_rcti_size_x(®ion->winrct) + 1; - height = BLI_rcti_size_y(®ion->winrct) + 1; - - zoomx = (float)width / w / aspx; - zoomy = (float)height / h / aspy; - - newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); - - if (fit || sc->zoom > newzoom) { - sc->zoom = newzoom; - } - } + SpaceClip *sc = CTX_wm_space_clip(C); + sc->xof = offset_x; + sc->yof = offset_y; + sc->zoom = zoom; return true; } @@ -1177,3 +1077,47 @@ void clip_start_prefetch_job(const bContext *C) /* and finally start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); } + +void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + state->offset_x = space_clip->xof; + state->offset_y = space_clip->yof; + state->zoom = space_clip->zoom; + + state->lock_offset_x = 0.0f; + state->lock_offset_y = 0.0f; + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + if (!clip_view_calculate_view_selection( + C, false, &state->offset_x, &state->offset_y, &state->zoom)) { + return; + } + + state->lock_offset_x = space_clip->xlockof; + state->lock_offset_y = space_clip->ylockof; +} + +void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) { + return; + } + + space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x; + space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y; +} diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 81df8cc8ecd..b9a69204281 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -171,8 +171,13 @@ void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y); void clip_view_center_to_point(SpaceClip *sc, float x, float y); +bool clip_view_calculate_view_selection( + const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom); + void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene); /* tracking_ops.c */ diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index cd4a1ffb526..cb84ea6571c 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1840,8 +1840,16 @@ void CLIP_OT_cursor_set(wmOperatorType *ot) static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceClip *space_clip = CTX_wm_space_clip(C); + + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + space_clip->flag ^= SC_LOCK_SELECTION; + + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index c7f2a027ba8..faa3f18e8c1 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -27,10 +27,12 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rect.h" #include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_context.h" +#include "BKE_mask.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -44,6 +46,7 @@ #include "WM_types.h" #include "ED_clip.h" +#include "ED_mask.h" #include "ED_screen.h" #include "UI_interface.h" @@ -395,16 +398,152 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra DEG_id_tag_update(&clip->id, 0); } -void clip_view_center_to_point(SpaceClip *sc, float x, float y) +/* Calculate space clip offset to be centered at the given point. */ +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y) { int width, height; - float aspx, aspy; - ED_space_clip_get_size(sc, &width, &height); + + float aspx, aspy; ED_space_clip_get_aspect(sc, &aspx, &aspy); - sc->xof = (x - 0.5f) * width * aspx; - sc->yof = (y - 0.5f) * height * aspy; + *r_offset_x = (x - 0.5f) * width * aspx; + *r_offset_y = (y - 0.5f) * height * aspy; +} + +void clip_view_center_to_point(SpaceClip *sc, float x, float y) +{ + clip_view_offset_for_center_to_point(sc, x, y, &sc->xof, &sc->yof); +} + +static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +{ + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingTrack *track; + int width, height; + bool ok = false; + ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + INIT_MINMAX2(min, max); + + ED_space_clip_get_size(sc, &width, &height); + + track = tracksbase->first; + while (track) { + if (TRACK_VIEW_SELECTED(sc, track)) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + + if (marker) { + float pos[3]; + + pos[0] = marker->pos[0] + track->offset[0]; + pos[1] = marker->pos[1] + track->offset[1]; + pos[2] = 0.0f; + + /* undistortion happens for normalized coords */ + if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { + /* undistortion happens for normalized coords */ + ED_clip_point_undistorted_pos(sc, pos, pos); + } + + pos[0] *= width; + pos[1] *= height; + + mul_v3_m4v3(pos, sc->stabmat, pos); + + minmax_v2v2_v2(min, max, pos); + + ok = true; + } + } + + track = track->next; + } + + return ok; +} + +static bool selected_boundbox(const bContext *C, float min[2], float max[2], bool include_handles) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + if (sc->mode == SC_MODE_TRACKING) { + return selected_tracking_boundbox(sc, min, max); + } + + if (ED_mask_selected_minmax(C, min, max, include_handles)) { + MovieClip *clip = ED_space_clip_get_clip(sc); + int width, height; + ED_space_clip_get_size(sc, &width, &height); + BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); + BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); + min[0] *= width; + min[1] *= height; + max[0] *= width; + max[1] *= height; + return true; + } + return false; +} + +bool clip_view_calculate_view_selection( + const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + + int frame_width, frame_height; + ED_space_clip_get_size(sc, &frame_width, &frame_height); + + if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + return false; + } + + /* NOTE: The `fit` argment is set to truth when doing "View to Selected" operator, and it set to + * false when this function is used for Lock-to-Selection functionality. When locking to + * selection the handles are to be ignored. So we can deriver the `include_handles` from `fit`. + * + * TODO(sergey): Make such decision more explicit. Maybe pass usecase for the calculation to tell + * operator from lock-to-selection apart. */ + float min[2], max[2]; + if (!selected_boundbox(C, min, max, fit)) { + return false; + } + + /* center view */ + clip_view_offset_for_center_to_point(sc, + (max[0] + min[0]) / (2 * frame_width), + (max[1] + min[1]) / (2 * frame_height), + r_offset_x, + r_offset_y); + + const int w = max[0] - min[0]; + const int h = max[1] - min[1]; + + /* set zoom to see all selection */ + *r_zoom = sc->zoom; + if (w > 0 && h > 0) { + ARegion *region = CTX_wm_region(C); + + int width, height; + float zoomx, zoomy, newzoom, aspx, aspy; + + ED_space_clip_get_aspect(sc, &aspx, &aspy); + + width = BLI_rcti_size_x(®ion->winrct) + 1; + height = BLI_rcti_size_y(®ion->winrct) + 1; + + zoomx = (float)width / w / aspx; + zoomy = (float)height / h / aspy; + + newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); + + if (fit) { + *r_zoom = newzoom; + } + } + + return true; } void clip_draw_sfra_efra(View2D *v2d, Scene *scene) diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index a5935f06927..33783f19a79 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -994,7 +994,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region) /* callback */ /* TODO(sergey): For being consistent with space image the projection needs to be configured - * the way how the commented out code does it. This works corrent for tracking data, but it + * the way how the commented out code does it. This works correct for tracking data, but it * causes wrong aspect correction for mask editor (see T84990). */ // GPU_matrix_push_projection(); // wmOrtho2(region->v2d.cur.xmin, region->v2d.cur.xmax, region->v2d.cur.ymin, diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 10574063ebd..0f4fc2a2160 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -88,17 +88,16 @@ static int add_marker_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); float pos[2]; + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", pos); if (!add_marker(C, pos[0], pos[1])) { return OPERATOR_CANCELLED; } - /* Reset offset from locked position, so frame jumping wouldn't be so - * confusing. - */ - sc->xlockof = 0; - sc->ylockof = 0; + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 063ea9592aa..ecd73f82e22 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -304,6 +304,9 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const track = find_nearest_track(sc, tracksbase, co, &distance_to_track); plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + /* Do not select beyond some reasonable distance, that is useless and * prevents the 'deselect on nothing' behavior. */ if (distance_to_track > 0.05f) { @@ -377,10 +380,7 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const ED_mask_deselect_all(C); } - if (!extend) { - sc->xlockof = 0.0f; - sc->ylockof = 0.0f; - } + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); BKE_tracking_dopesheet_tag_update(tracking); @@ -867,15 +867,20 @@ static int select_all_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - int action = RNA_enum_get(op->ptr, "action"); + const int action = RNA_enum_get(op->ptr, "action"); + + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); bool has_selection = false; - ED_clip_select_all(sc, action, &has_selection); if (!has_selection) { sc->flag &= ~SC_LOCK_SELECTION; } + else { + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + } BKE_tracking_dopesheet_tag_update(tracking); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 9fe380e382f..d4cd888c662 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -794,7 +794,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C), } } -static const char *file_context_dir[] = {"active_file", "active_id", NULL}; +static const char *file_context_dir[] = {"active_file", "id", NULL}; static int /*eContextResult*/ file_context(const bContext *C, const char *member, diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 86e52814d6f..097e304c893 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -900,7 +900,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) } } else if (ED_space_image_check_show_maskedit(sima, obedit)) { - if (!ED_mask_selected_minmax(C, min, max)) { + if (!ED_mask_selected_minmax(C, min, max, true)) { return OPERATOR_CANCELLED; } } diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index afd19df9f14..7905483fac9 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3166,13 +3166,80 @@ static void node_geometry_buts_random_attribute(uiLayout *layout, uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } +static bool node_attribute_math_operation_use_input_b(const NodeMathOperation operation) +{ + switch (operation) { + case NODE_MATH_ADD: + case NODE_MATH_SUBTRACT: + case NODE_MATH_MULTIPLY: + case NODE_MATH_DIVIDE: + case NODE_MATH_POWER: + case NODE_MATH_LOGARITHM: + case NODE_MATH_MINIMUM: + case NODE_MATH_MAXIMUM: + case NODE_MATH_LESS_THAN: + case NODE_MATH_GREATER_THAN: + case NODE_MATH_MODULO: + case NODE_MATH_ARCTAN2: + case NODE_MATH_SNAP: + case NODE_MATH_WRAP: + case NODE_MATH_COMPARE: + case NODE_MATH_MULTIPLY_ADD: + case NODE_MATH_PINGPONG: + case NODE_MATH_SMOOTH_MIN: + case NODE_MATH_SMOOTH_MAX: + return true; + case NODE_MATH_SINE: + case NODE_MATH_COSINE: + case NODE_MATH_TANGENT: + case NODE_MATH_ARCSINE: + case NODE_MATH_ARCCOSINE: + case NODE_MATH_ARCTANGENT: + case NODE_MATH_ROUND: + case NODE_MATH_ABSOLUTE: + case NODE_MATH_FLOOR: + case NODE_MATH_CEIL: + case NODE_MATH_FRACTION: + case NODE_MATH_SQRT: + case NODE_MATH_INV_SQRT: + case NODE_MATH_SIGN: + case NODE_MATH_EXPONENT: + case NODE_MATH_RADIANS: + case NODE_MATH_DEGREES: + case NODE_MATH_SINH: + case NODE_MATH_COSH: + case NODE_MATH_TANH: + case NODE_MATH_TRUNC: + return false; + } + BLI_assert(false); + return false; +} + static void node_geometry_buts_attribute_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + bNode *node = (bNode *)ptr->data; + NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; + NodeMathOperation operation = (NodeMathOperation)node_storage->operation; + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE); - uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); + + /* These "use input b / c" checks are copied from the node's code. + * They could be de-duplicated if the drawing code was moved to the node's file. */ + if (node_attribute_math_operation_use_input_b(operation)) { + uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); + } + if (ELEM(operation, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX, + NODE_MATH_WRAP, + NODE_MATH_COMPARE)) { + uiItemR(layout, ptr, "input_type_c", DEFAULT_FLAGS, IFACE_("Type C"), ICON_NONE); + } } static void node_geometry_buts_attribute_vector_math(uiLayout *layout, @@ -3297,6 +3364,16 @@ static void node_geometry_buts_attribute_sample_texture(uiLayout *layout, uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); } +static void node_geometry_buts_points_to_volume(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "resolution_mode", DEFAULT_FLAGS, IFACE_("Resolution"), ICON_NONE); + uiItemR(layout, ptr, "input_type_radius", DEFAULT_FLAGS, IFACE_("Radius"), ICON_NONE); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3354,6 +3431,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE: ntype->draw_buttons = node_geometry_buts_attribute_sample_texture; break; + case GEO_NODE_POINTS_TO_VOLUME: + ntype->draw_buttons = node_geometry_buts_points_to_volume; + break; } } diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index f470d1913dc..7474f8034de 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1395,6 +1395,10 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) SEQ_prefetch_stop(scene); + LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { + seq->tmp = NULL; + } + LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) { if (use_cursor_position && seq->machine != split_channel) { continue; diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index b208f320591..b9698492aa5 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -168,13 +168,13 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) } SEQ_CURRENT_END; + BLI_gset_free(file_list, MEM_freeN); + if (!selected) { BKE_reportf(reports, RPT_WARNING, "Select movie or image strips"); return; } - BLI_gset_free(file_list, MEM_freeN); - if (selected && !WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 2b7b8255068..a6a77ecd5f7 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -224,13 +224,11 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region) */ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) { - float viewdist; - if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { return; } - viewdist = rv3d->dist; + float viewdist = rv3d->dist; /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ if (dist != 0.0f) { @@ -248,7 +246,6 @@ bool ED_view3d_context_activate(bContext *C) { bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); - ARegion *region; /* area can be NULL when called from python */ if (area == NULL || area->spacetype != SPACE_VIEW3D) { @@ -259,7 +256,7 @@ bool ED_view3d_context_activate(bContext *C) return false; } - region = BKE_area_find_region_active_win(area); + ARegion *region = BKE_area_find_region_active_win(area); if (region == NULL) { return false; } @@ -282,9 +279,7 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) { - int val; - - for (val = 0; val < 4; val++) { + for (int val = 0; val < 4; val++) { normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); if (UNLIKELY(is_flip)) { negate_v3(clip[val]); @@ -752,14 +747,12 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d, static void view3d_boxview_clip(ScrArea *area) { - ARegion *region; BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); float clip[6][4]; float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; - int val; /* create bounding box */ - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -794,7 +787,7 @@ static void view3d_boxview_clip(ScrArea *area) } } - for (val = 0; val < 8; val++) { + for (int val = 0; val < 8; val++) { if (ELEM(val, 0, 3, 4, 7)) { bb->vec[val][0] = -x1 - ofs[0]; } @@ -826,12 +819,12 @@ static void view3d_boxview_clip(ScrArea *area) normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); /* then plane equations */ - for (val = 0; val < 6; val++) { + for (int val = 0; val < 6; val++) { clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); } /* create bounding box */ - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -950,11 +943,10 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) { ARegion *region_sync = NULL; RegionView3D *rv3d = region->regiondata; - short viewlock; /* this function copies flags from the first of the 3 other quadview * regions to the 2 other, so it assumes this is the region whose * properties are always being edited, weak */ - viewlock = rv3d->viewlock; + short viewlock = rv3d->viewlock; if ((viewlock & RV3D_LOCK_ROTATION) == 0) { do_clip = (viewlock & RV3D_BOXCLIP) != 0; @@ -1015,10 +1007,7 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin) { - ViewDepths depth_temp = {0}; rcti rect; - float depth_close; - if (margin == 0) { /* Get Z Depths, needed for perspective, nice for ortho */ rect.xmin = mval[0]; @@ -1030,8 +1019,9 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int BLI_rcti_init_pt_radius(&rect, mval, margin); } + ViewDepths depth_temp = {0}; view3d_update_depths_rect(region, &depth_temp, &rect); - depth_close = view3d_depth_near(&depth_temp); + float depth_close = view3d_depth_near(&depth_temp); MEM_SAFE_FREE(depth_temp.depths); return depth_close; } @@ -1053,14 +1043,13 @@ bool ED_view3d_autodist(Depsgraph *depsgraph, { float depth_close; int margin_arr[] = {0, 2, 4}; - int i; bool depth_ok = false; /* Get Z Depths, needed for perspective, nice for ortho */ ED_view3d_draw_depth(depsgraph, region, v3d, alphaoverride); /* Attempt with low margin's first */ - i = 0; + int i = 0; do { depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize); depth_ok = (depth_close != FLT_MAX); @@ -1104,9 +1093,8 @@ bool ED_view3d_autodist_simple(ARegion *region, int margin, const float *force_depth) { - float depth; - /* Get Z Depths, needed for perspective, nice for ortho */ + float depth; if (force_depth) { depth = *force_depth; } @@ -1237,7 +1225,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d, } else { float lens, sensor_size, zoom; - float angle; if (persp == RV3D_CAMOB) { CameraParams params; @@ -1259,7 +1246,7 @@ float ED_view3d_radius_to_dist(const View3D *v3d, zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; } - angle = focallength_to_fov(lens, sensor_size); + float angle = focallength_to_fov(lens, sensor_size); /* zoom influences lens, correct this by scaling the angle as a distance * (by the zoom-level) */ @@ -1319,14 +1306,13 @@ float ED_view3d_offset_distance(const float mat[4][4], { float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float dist; mul_m4_v4(mat, pos); add_v3_v3(pos, ofs); mul_m4_v4(mat, dir); normalize_v3(dir); - dist = dot_v3v3(pos, dir); + float dist = dot_v3v3(pos, dir); if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { dist = fallback_dist; diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 860eaa37816..883c13f20db 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -77,8 +77,6 @@ static CLG_LogRef LOG = {"ed.undo"}; enum eUndoStepDir { STEP_REDO = 1, STEP_UNDO = -1, - /** Only used when the undo step name or index is passed to #ed_undo_step_impl. */ - STEP_NONE = 0, }; /* -------------------------------------------------------------------- */ @@ -180,19 +178,16 @@ void ED_undo_push(bContext *C, const char *str) } /** - * \note Also check #undo_history_exec in bottom if you change notifiers. + * Common pre management of undo/redo (killing all running jobs, calling pre handlers, etc.). */ -static int ed_undo_step_impl(bContext *C, - enum eUndoStepDir step, - const char *undo_name, - const int undo_index, +static void ed_undo_step_pre(bContext *C, + wmWindowManager *wm, + const enum eUndoStepDir undo_dir, ReportList *reports) { - /* Mutually exclusives, ensure correct input. */ - BLI_assert(((undo_name || undo_index != -1) && (step == STEP_NONE)) || - (!(undo_name || undo_index != -1) && (step != STEP_NONE))); - CLOG_INFO(&LOG, 1, "name='%s', index=%d, step=%d", undo_name, undo_index, step); - wmWindowManager *wm = CTX_wm_manager(C); + BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO)); + + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ScrArea *area = CTX_wm_area(C); @@ -201,22 +196,12 @@ static int ed_undo_step_impl(bContext *C, WM_jobs_kill_all(wm); if (G.debug & G_DEBUG_IO) { - Main *bmain = CTX_data_main(C); if (bmain->lock != NULL) { BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step"); BLO_main_validate_libraries(bmain, reports); } } - /* TODO(campbell): undo_system: use undo system */ - /* grease pencil can be can be used in plenty of spaces, so check it first */ - /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name - * or index is fully not implemented. - * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems - * to always return false). */ - if (ED_gpencil_session_active()) { - return ED_undo_gpencil_step(C, (int)step); - } if (area && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); if (obact && (obact->type == OB_GPENCIL)) { @@ -224,89 +209,40 @@ static int ed_undo_step_impl(bContext *C, } } - UndoStep *step_data_from_name = NULL; - enum eUndoStepDir step_for_callback = step; - if (undo_name != NULL) { - step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name); - if (step_data_from_name == NULL) { - return OPERATOR_CANCELLED; - } - - /* TODO(campbell), could use simple optimization. */ - /* Pointers match on redo. */ - step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) < - BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? - STEP_UNDO : - STEP_REDO; - } - else if (undo_index != -1) { - step_for_callback = (undo_index < - BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? - STEP_UNDO : - STEP_REDO; - } - /* App-Handlers (pre). */ { /* Note: ignore grease pencil for now. */ - Main *bmain = CTX_data_main(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); + bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); wm->op_undo_depth--; } +} - /* Undo System */ - { - if (undo_name) { - BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name); - } - else if (undo_index != -1) { - BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index); - } - else { - if (step == STEP_UNDO) { - BKE_undosys_step_undo(wm->undo_stack, C); - } - else { - BKE_undosys_step_redo(wm->undo_stack, C); - } - } +/** + * Common post management of undo/redo (calling post handlers, adding notifiers etc.). + * + * \note Also check #undo_history_exec in bottom if you change notifiers. + */ +static void ed_undo_step_post(bContext *C, + wmWindowManager *wm, + const enum eUndoStepDir undo_dir, + ReportList *reports) +{ + BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO)); - /* Set special modes for grease pencil */ - if (area && (area->spacetype == SPACE_VIEW3D)) { - Object *obact = CTX_data_active_object(C); - if (obact && (obact->type == OB_GPENCIL)) { - /* set cursor */ - if (ELEM(obact->mode, - OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, - OB_MODE_WEIGHT_GPENCIL, - OB_MODE_VERTEX_GPENCIL)) { - ED_gpencil_toggle_brush_cursor(C, true, NULL); - } - else { - ED_gpencil_toggle_brush_cursor(C, false, NULL); - } - /* set workspace mode */ - Base *basact = CTX_data_active_base(C); - ED_object_base_activate(C, basact); - } - } - } + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); /* App-Handlers (post). */ { - Main *bmain = CTX_data_main(C); - scene = CTX_data_scene(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); + bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); wm->op_undo_depth--; } if (G.debug & G_DEBUG_IO) { - Main *bmain = CTX_data_main(C); if (bmain->lock != NULL) { BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step"); BLO_main_validate_libraries(bmain, reports); @@ -317,30 +253,125 @@ static int ed_undo_step_impl(bContext *C, WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL); WM_toolsystem_refresh_active(C); - - Main *bmain = CTX_data_main(C); WM_toolsystem_refresh_screen_all(bmain); if (CLOG_CHECK(&LOG, 1)) { BKE_undosys_print(wm->undo_stack); } +} + +/** Undo or redo one step from current active one. + * May undo or redo several steps at once only if the target step is a 'skipped' one. + * The target step will be the one immediately before or after the active one. */ +static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports) +{ + BLI_assert(ELEM(step, STEP_UNDO, STEP_REDO)); + + CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO"); + + /* TODO(campbell): undo_system: use undo system */ + /* grease pencil can be can be used in plenty of spaces, so check it first */ + /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name + * or index is fully not implemented. + * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems + * to always return false). */ + if (ED_gpencil_session_active()) { + return ED_undo_gpencil_step(C, (int)step); + } + + wmWindowManager *wm = CTX_wm_manager(C); + + ed_undo_step_pre(C, wm, step, reports); + + if (step == STEP_UNDO) { + BKE_undosys_step_undo(wm->undo_stack, C); + } + else { + BKE_undosys_step_redo(wm->undo_stack, C); + } + + ed_undo_step_post(C, wm, step, reports); return OPERATOR_FINISHED; } -static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports) -{ - return ed_undo_step_impl(C, step, NULL, -1, reports); -} - +/** Undo the step matching given name. + * May undo several steps at once. + * The target step will be the one immediately before given named one. + * Only supposed to undo (will assert in case given named step is after current active one). */ static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports) { - return ed_undo_step_impl(C, STEP_NONE, undo_name, -1, reports); + BLI_assert(undo_name != NULL); + + /* FIXME: See comments in `ed_undo_step_direction`. */ + if (ED_gpencil_session_active()) { + BLI_assert(!"Not implemented currently."); + } + + wmWindowManager *wm = CTX_wm_manager(C); + UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name); + if (undo_step_from_name == NULL) { + CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name); + + return OPERATOR_CANCELLED; + } + + /* TODO(campbell), could use simple optimization. */ + /* Pointers match on redo. */ + const int target_step_index = BLI_findindex(&wm->undo_stack->steps, undo_step_from_name); + const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active); + const enum eUndoStepDir undo_dir = (target_step_index < active_step_index) ? STEP_UNDO : + STEP_REDO; + + CLOG_INFO(&LOG, + 1, + "name='%s', found direction=%s, index=%d", + undo_name, + (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO", + target_step_index); + + /* This function is currently not supposed to redo ever. + * TODO: Will be fixed in future in continuing undo code refactor effort. */ + BLI_assert(undo_dir == STEP_UNDO); + + ed_undo_step_pre(C, wm, undo_dir, reports); + + BKE_undosys_step_undo_with_data(wm->undo_stack, C, undo_step_from_name); + + ed_undo_step_post(C, wm, undo_dir, reports); + + return OPERATOR_FINISHED; } +/** Load the step matching given index in the stack. + * May undo or redo several steps at once. + * The target step will be the one indicated by the given index. */ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports) { - return ed_undo_step_impl(C, STEP_NONE, NULL, undo_index, reports); + BLI_assert(undo_index >= 0); + + /* FIXME: See comments in `ed_undo_step_direction`. */ + if (ED_gpencil_session_active()) { + BLI_assert(!"Not implemented currently."); + } + + wmWindowManager *wm = CTX_wm_manager(C); + const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active); + const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO; + + CLOG_INFO(&LOG, + 1, + "index='%d', found direction=%s", + undo_index, + (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO"); + + ed_undo_step_pre(C, wm, undo_dir, reports); + + BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index); + + ed_undo_step_post(C, wm, undo_dir, reports); + + return OPERATOR_FINISHED; } void ED_undo_grouped_push(bContext *C, const char *str) diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index d8e4c5377b0..095e17f344e 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -114,7 +114,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, - bool display_colorspace); + bool display_colorspace, + bool do_overlay_merge); void GPU_viewport_free(GPUViewport *viewport); void GPU_viewport_colorspace_set(GPUViewport *viewport, @@ -125,7 +126,8 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport, void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs); void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs, - bool display_colorspace); + bool display_colorspace, + bool do_overlay_merge); ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport); struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index a83654d31e7..205ba1d06d6 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -749,7 +749,8 @@ static void gpu_viewport_batch_free(GPUViewport *viewport) static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, const rctf *rect_pos, const rctf *rect_uv, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { DefaultTextureList *dtxl = viewport->txl; GPUTexture *color = dtxl->color; @@ -771,7 +772,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, NULL, viewport->dither, false, - true); + do_overlay_merge); } GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv); @@ -780,6 +781,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, } else { GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE); + GPU_batch_uniform_1i(batch, "overlay", do_overlay_merge); GPU_batch_uniform_1i(batch, "display_transform", display_colorspace); GPU_batch_uniform_1i(batch, "image_texture", 0); GPU_batch_uniform_1i(batch, "overlays_texture", 1); @@ -803,7 +805,8 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { gpu_viewport_framebuffer_view_set(viewport, view); DefaultFramebufferList *dfbl = viewport->fbl; @@ -850,7 +853,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, SWAP(float, uv_rect.ymin, uv_rect.ymax); } - gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace); + gpu_viewport_draw_colormanaged( + viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); } /** @@ -862,7 +866,7 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, */ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect) { - GPU_viewport_draw_to_screen_ex(viewport, view, rect, true); + GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true); } /** @@ -870,7 +874,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re */ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { DefaultFramebufferList *dfbl = viewport->fbl; DefaultTextureList *dtxl = viewport->txl; @@ -896,7 +901,8 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, .ymax = 1.0f, }; - gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace); + gpu_viewport_draw_colormanaged( + viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); /* This one is from the offscreen. Don't free it with the viewport. */ dtxl->depth = NULL; diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 29ff1b3e81a..1d76b07c966 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -34,28 +34,6 @@ namespace blender::gpu { -/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the - * `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags. - * The work around uses `GPU_RGBA16I` but that is only possible for loop normals. - * - * Vertex and Face normals would still render resulting in undefined behavior during selection and - * rendering. */ -static bool is_faulty_T82856_platform(const char *version, const char *renderer) -{ - /* On Linux the driver does not report its version. Test the OpenGL version in stead. */ - if (strstr(version, "4.5.14756") || strstr(version, "4.5.14757")) { - if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") || - strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || - strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || - strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") || - strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") || - strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") || - strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) { - return true; - } - } - return false; -} /* -------------------------------------------------------------------- */ /** \name Platform * \{ */ @@ -294,9 +272,17 @@ static void detect_workarounds() GCaps.broken_amd_driver = true; } /* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the - * `GL_INT_2_10_10_10_REV` data type. */ + * `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags. + * The work around uses `GPU_RGBA16I`. + */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) { - if (is_faulty_T82856_platform(version, renderer)) { + if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") || + strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || + strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || + strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") || + strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") || + strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") || + strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) { GCaps.use_hq_normals_workaround = true; } } diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl index 73f40c693ae..7f3fe2f5252 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -4,6 +4,7 @@ uniform sampler2D image_texture; uniform sampler2D overlays_texture; uniform bool display_transform; +uniform bool overlay; in vec2 texCoord_interp; @@ -30,12 +31,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) void main() { fragColor = texture(image_texture, texCoord_interp.st); - vec4 overlay_col = texture(overlays_texture, texCoord_interp.st); - fragColor = clamp(fragColor, 0.0, 1.0); - fragColor *= 1.0 - overlay_col.a; - fragColor += overlay_col; + if (overlay) { + fragColor = clamp(fragColor, 0.0, 1.0); + fragColor *= 1.0 - overlay_col.a; + fragColor += overlay_col; + } if (display_transform) { linearrgb_to_srgb(fragColor, fragColor); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 2c7e82e6587..26824216337 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -453,7 +453,7 @@ typedef enum ID_Type { ID_TXT = MAKE_ID2('T', 'X'), /* Text */ ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */ ID_SO = MAKE_ID2('S', 'O'), /* Sound */ - ID_GR = MAKE_ID2('G', 'R'), /* Group */ + ID_GR = MAKE_ID2('G', 'R'), /* Collection */ ID_AR = MAKE_ID2('A', 'R'), /* bArmature */ ID_AC = MAKE_ID2('A', 'C'), /* bAction */ ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */ @@ -472,7 +472,7 @@ typedef enum ID_Type { ID_HA = MAKE_ID2('H', 'A'), /* Hair */ ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */ ID_VO = MAKE_ID2('V', 'O'), /* Volume */ - ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (currently unused) */ + ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (geometry node groups) */ } ID_Type; /* Only used as 'placeholder' in .blend files for directly linked data-blocks. */ diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index 8601dcf76ac..860a9affb3e 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -440,7 +440,7 @@ .renderlvl = 0, \ .totlvl = 0, \ .flags = eMultiresModifierFlag_UseCrease | eMultiresModifierFlag_ControlEdges, \ - .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \ + .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \ .quality = 4, \ .boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \ } @@ -622,7 +622,7 @@ .levels = 1, \ .renderLevels = 2, \ .flags = eSubsurfModifierFlag_UseCrease | eSubsurfModifierFlag_ControlEdges, \ - .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \ + .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \ .quality = 3, \ .boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \ .emCache = NULL, \ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4dba856b87b..0c92099e23b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1089,14 +1089,15 @@ typedef struct NodeAttributeCompare { } NodeAttributeCompare; typedef struct NodeAttributeMath { - /* e.g. NODE_MATH_ADD. */ + /* NodeMathOperation. */ uint8_t operation; /* GeometryNodeAttributeInputMode */ uint8_t input_type_a; uint8_t input_type_b; + uint8_t input_type_c; - char _pad[5]; + char _pad[4]; } NodeAttributeMath; typedef struct NodeAttributeMix { @@ -1183,6 +1184,15 @@ typedef struct NodeGeometryPointInstance { char _pad[6]; } NodeGeometryPointInstance; +typedef struct NodeGeometryPointsToVolume { + /* GeometryNodePointsToVolumeResolutionMode */ + uint8_t resolution_mode; + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_radius; + + char _pad[6]; +} NodeGeometryPointsToVolume; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1378,7 +1388,7 @@ enum { #define SHD_MATH_CLAMP 1 /* Math node operations. */ -enum { +typedef enum NodeMathOperation { NODE_MATH_ADD = 0, NODE_MATH_SUBTRACT = 1, NODE_MATH_MULTIPLY = 2, @@ -1419,7 +1429,7 @@ enum { NODE_MATH_PINGPONG = 37, NODE_MATH_SMOOTH_MIN = 38, NODE_MATH_SMOOTH_MAX = 39, -}; +} NodeMathOperation; /* Vector Math node operations. */ typedef enum NodeVectorMathOperation { @@ -1633,6 +1643,11 @@ typedef enum GeometryNodeTransformSpace { GEO_NODE_TRANSFORM_SPACE_RELATIVE = 1, } GeometryNodeTransformSpace; +typedef enum GeometryNodePointsToVolumeResolutionMode { + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT = 0, + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1, +} GeometryNodePointsToVolumeResolutionMode; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index e02e47745b0..c13f592f7fb 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1632,33 +1632,35 @@ static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create) static void rna_def_property_subdivision_common(StructRNA *srna) { static const EnumPropertyItem prop_uv_smooth_items[] = { - {SUBSURF_UV_SMOOTH_NONE, "NONE", 0, "None", "UVs are not smoothed, boundaries are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, - "PRESERVE_CORNERS", - 0, - "Keep Corners", - "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, -# if 0 - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, - "PRESERVE_CORNERS_AND_JUNCTIONS", - 0, - "Smooth, keep corners+junctions", - "UVs are smoothed, corners on discontinuous boundary and " - "junctions of 3 or more regions are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, - "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", - 0, - "Smooth, keep corners+junctions+concave", - "UVs are smoothed, corners on discontinuous boundary, " - "junctions of 3 or more regions and darts and concave corners are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, - "PRESERVE_BOUNDARIES", - 0, - "Smooth, keep corners", - "UVs are smoothed, boundaries are kept sharp"}, -# endif - {SUBSURF_UV_SMOOTH_ALL, "PRESERVE_BOUNDARIES", 0, "All", "UVs and boundaries are smoothed"}, - {0, NULL, 0, NULL, NULL}, + {SUBSURF_UV_SMOOTH_NONE, + "NONE", + 0, + "None", + "UVs are not smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, + "PRESERVE_CORNERS", + 0, + "Keep Corners", + "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, + "PRESERVE_CORNERS_AND_JUNCTIONS", + 0, + "Keep Corners, Junctions", + "UVs are smoothed, corners on discontinuous boundary and " + "junctions of 3 or more regions are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, + "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", + 0, + "Keep Corners, Junctions, Concave", + "UVs are smoothed, corners on discontinuous boundary, " + "junctions of 3 or more regions and darts and concave corners are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, + "PRESERVE_BOUNDARIES", + 0, + "Keep boundaries", + "UVs are smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, + {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_boundary_smooth_items[] = { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 355b1360ab0..90badae2e8e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1980,22 +1980,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf( return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported); } -static bool attribute_math_operation_supported(const EnumPropertyItem *item) -{ - return ELEM(item->value, - NODE_MATH_ADD, - NODE_MATH_SUBTRACT, - NODE_MATH_MULTIPLY, - NODE_MATH_DIVIDE) && - (item->identifier[0] != '\0'); -} -static const EnumPropertyItem *rna_GeometryNodeAttributeMath_operation_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - *r_free = true; - return itemf_function_check(rna_enum_node_math_items, attribute_math_operation_supported); -} - /** * This bit of ugly code makes sure the float / attribute option shows up instead of * vector / attribute if the node uses an operation that uses a float for input B. @@ -8579,10 +8563,9 @@ static void def_geo_attribute_math(StructRNA *srna) prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "operation"); RNA_def_property_enum_items(prop, rna_enum_node_math_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf"); RNA_def_property_enum_default(prop, NODE_MATH_ADD); RNA_def_property_ui_text(prop, "Operation", ""); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a"); @@ -8595,6 +8578,12 @@ static void def_geo_attribute_math(StructRNA *srna) RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); RNA_def_property_ui_text(prop, "Input Type B", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c"); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type C", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_attribute_vector_math(StructRNA *srna) @@ -8889,6 +8878,37 @@ static void def_geo_object_info(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_points_to_volume(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem resolution_mode_items[] = { + {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT, + "VOXEL_AMOUNT", + 0, + "Amount", + "Specify the approximate number of voxels along the diagonal"}, + {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE, + "VOXEL_SIZE", + 0, + "Size", + "Specify the voxel side length"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage"); + + prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, resolution_mode_items); + RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_radius", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Radius Input Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index faa20e642cf..c418c8eb4dc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -85,16 +85,16 @@ const EnumPropertyItem rna_enum_object_mode_items[] = { ICON_GREASEPENCIL, "Draw", "Paint Grease Pencil Strokes"}, - {OB_MODE_VERTEX_GPENCIL, - "VERTEX_GPENCIL", - ICON_VPAINT_HLT, - "Vertex Paint", - "Grease Pencil Vertex Paint Strokes"}, {OB_MODE_WEIGHT_GPENCIL, "WEIGHT_GPENCIL", ICON_WPAINT_HLT, "Weight Paint", "Grease Pencil Weight Paint Strokes"}, + {OB_MODE_VERTEX_GPENCIL, + "VERTEX_GPENCIL", + ICON_VPAINT_HLT, + "Vertex Paint", + "Grease Pencil Vertex Paint Strokes"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 217321b4991..01b083dc3c8 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -927,9 +927,10 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin rna_Sequence_invalidate_raw_update(bmain, scene, ptr); } -static void rna_Sequence_sound_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) +static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO); + DEG_relations_tag_update(bmain); } static int seqproxy_seq_cmp_fn(Sequence *seq, void *arg_pt) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d796c7c309c..405a8dcbf46 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -160,6 +160,7 @@ set(SRC geometry/nodes/node_geo_point_scale.cc geometry/nodes/node_geo_point_separate.cc geometry/nodes/node_geo_point_translate.cc + geometry/nodes/node_geo_points_to_volume.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 1b3a8200beb..d78f76e0b52 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -48,6 +48,7 @@ void register_node_type_geo_attribute_color_ramp(void); void register_node_type_geo_point_rotate(void); void register_node_type_geo_align_rotation_to_vector(void); void register_node_type_geo_sample_texture(void); +void register_node_type_geo_points_to_volume(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 4c300916357..cc2f6a294f2 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -290,6 +290,7 @@ DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_ DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "") DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "") +DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 53af6073793..daaccf4450b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -54,6 +54,8 @@ static int attribute_data_type_complexity(const CustomDataType data_type) return 1; case CD_PROP_FLOAT: return 2; + case CD_PROP_FLOAT2: + return 3; case CD_PROP_FLOAT3: return 4; case CD_PROP_COLOR: diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index f8ec9124db3..f3fc45fc1be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -34,6 +34,8 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = { {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_STRING, N_("B")}, {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("C")}, + {SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_STRING, N_("Result")}, {-1, ""}, }; @@ -51,45 +53,132 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) data->operation = NODE_MATH_ADD; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; node->storage = data; } +static bool operation_use_input_c(const NodeMathOperation operation) +{ + return ELEM(operation, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX, + NODE_MATH_WRAP, + NODE_MATH_COMPARE); +} + +static bool operation_use_input_b(const NodeMathOperation operation) +{ + switch (operation) { + case NODE_MATH_ADD: + case NODE_MATH_SUBTRACT: + case NODE_MATH_MULTIPLY: + case NODE_MATH_DIVIDE: + case NODE_MATH_POWER: + case NODE_MATH_LOGARITHM: + case NODE_MATH_MINIMUM: + case NODE_MATH_MAXIMUM: + case NODE_MATH_LESS_THAN: + case NODE_MATH_GREATER_THAN: + case NODE_MATH_MODULO: + case NODE_MATH_ARCTAN2: + case NODE_MATH_SNAP: + case NODE_MATH_WRAP: + case NODE_MATH_COMPARE: + case NODE_MATH_MULTIPLY_ADD: + case NODE_MATH_PINGPONG: + case NODE_MATH_SMOOTH_MIN: + case NODE_MATH_SMOOTH_MAX: + return true; + case NODE_MATH_SINE: + case NODE_MATH_COSINE: + case NODE_MATH_TANGENT: + case NODE_MATH_ARCSINE: + case NODE_MATH_ARCCOSINE: + case NODE_MATH_ARCTANGENT: + case NODE_MATH_ROUND: + case NODE_MATH_ABSOLUTE: + case NODE_MATH_FLOOR: + case NODE_MATH_CEIL: + case NODE_MATH_FRACTION: + case NODE_MATH_SQRT: + case NODE_MATH_INV_SQRT: + case NODE_MATH_SIGN: + case NODE_MATH_EXPONENT: + case NODE_MATH_RADIANS: + case NODE_MATH_DEGREES: + case NODE_MATH_SINH: + case NODE_MATH_COSH: + case NODE_MATH_TANH: + case NODE_MATH_TRUNC: + return false; + } + BLI_assert(false); + return false; +} + namespace blender::nodes { static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; + NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; + NodeMathOperation operation = static_cast(node_storage.operation); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *node, + "B", + (GeometryNodeAttributeInputMode)node_storage.input_type_b, + operation_use_input_b(operation)); + update_attribute_input_socket_availabilities( + *node, + "C", + (GeometryNodeAttributeInputMode)node_storage.input_type_c, + operation_use_input_c(operation)); } -static void do_math_operation(const FloatReadAttribute &input_a, - const FloatReadAttribute &input_b, - FloatWriteAttribute result, - const int operation) +static void do_math_operation(Span span_a, + Span span_b, + Span span_c, + MutableSpan span_result, + const NodeMathOperation operation) { - const int size = input_a.size(); - - Span span_a = input_a.get_span(); - Span span_b = input_b.get_span(); - MutableSpan span_result = result.get_span_for_write_only(); - - bool success = try_dispatch_float_math_fl_fl_to_fl( + bool success = try_dispatch_float_math_fl_fl_fl_to_fl( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { - for (const int i : IndexRange(size)) { - const float in1 = span_a[i]; - const float in2 = span_b[i]; - const float out = math_function(in1, in2); - span_result[i] = out; + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_a[i], span_b[i], span_c[i]); } }); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} - result.apply_span(); +static void do_math_operation(Span span_a, + Span span_b, + MutableSpan span_result, + const NodeMathOperation operation) +{ + bool success = try_dispatch_float_math_fl_fl_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_a[i], span_b[i]); + } + }); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} - /* The operation is not supported by this node currently. */ +static void do_math_operation(Span span_input, + MutableSpan span_result, + const NodeMathOperation operation) +{ + bool success = try_dispatch_float_math_fl_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_input[i]); + } + }); BLI_assert(success); UNUSED_VARS_NDEBUG(success); } @@ -98,7 +187,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP { const bNode &node = params.node(); const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage; - const int operation = node_storage->operation; + const NodeMathOperation operation = static_cast(node_storage->operation); /* The result type of this node is always float. */ const CustomDataType result_type = CD_PROP_FLOAT; @@ -115,15 +204,44 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP ReadAttributePtr attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - ReadAttributePtr attribute_b = params.get_input_attribute( - "B", component, result_domain, result_type, nullptr); - if (!attribute_a || !attribute_b) { - /* Attribute wasn't found. */ + if (!attribute_a) { return; } - do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation); - attribute_result.save(); + /* Note that passing the data with `get_span()` works + * because the attributes were accessed with #CD_PROP_FLOAT. */ + if (operation_use_input_b(operation)) { + ReadAttributePtr attribute_b = params.get_input_attribute( + "B", component, result_domain, result_type, nullptr); + if (!attribute_b) { + return; + } + if (operation_use_input_c(operation)) { + ReadAttributePtr attribute_c = params.get_input_attribute( + "C", component, result_domain, result_type, nullptr); + if (!attribute_c) { + return; + } + do_math_operation(attribute_a->get_span(), + attribute_b->get_span(), + attribute_c->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + else { + do_math_operation(attribute_a->get_span(), + attribute_b->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + } + else { + do_math_operation(attribute_a->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + + attribute_result.apply_span_and_save(); } static void geo_node_attribute_math_exec(GeoNodeExecParams params) 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 b9c9e5bd02a..7549305aedb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -43,18 +43,32 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Spanget_for_read(); totverts += mesh->totvert; totloops += mesh->totloop; totedges += mesh->totedge; totpolys += mesh->totpoly; + cd_dirty_vert |= mesh->runtime.cd_dirty_vert; + cd_dirty_poly |= mesh->runtime.cd_dirty_poly; + cd_dirty_edge |= mesh->runtime.cd_dirty_edge; + cd_dirty_loop |= mesh->runtime.cd_dirty_loop; } const Mesh *first_input_mesh = src_components[0]->get_for_read(); Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys); BKE_mesh_copy_settings(new_mesh, first_input_mesh); + new_mesh->runtime.cd_dirty_vert = cd_dirty_vert; + new_mesh->runtime.cd_dirty_poly = cd_dirty_poly; + new_mesh->runtime.cd_dirty_edge = cd_dirty_edge; + new_mesh->runtime.cd_dirty_loop = cd_dirty_loop; + int vert_offset = 0; int loop_offset = 0; int edge_offset = 0; @@ -124,17 +138,17 @@ static void determine_final_data_type_and_domain(Span CustomDataType *r_type, AttributeDomain *r_domain) { + Vector data_types; for (const GeometryComponent *component : components) { ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name); if (attribute) { - /* TODO: Use data type with most information. */ - *r_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type()); + data_types.append(attribute->custom_data_type()); /* TODO: Use highest priority domain. */ *r_domain = attribute->domain(); - return; } } - BLI_assert(false); + + *r_type = attribute_data_type_highest_complexity(data_types); } static void fill_new_attribute(Span src_components, @@ -219,11 +233,9 @@ static void join_components(Span src_components, Geo for (const InstancesComponent *component : src_components) { const int size = component->instances_amount(); Span instanced_data = component->instanced_data(); - Span positions = component->positions(); - Span rotations = component->rotations(); - Span scales = component->scales(); + Span transforms = component->transforms(); for (const int i : IndexRange(size)) { - dst_component.add_instance(instanced_data[i], positions[i], rotations[i], scales[i]); + dst_component.add_instance(instanced_data[i], transforms[i]); } } } 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 fe0303a5f1c..d713c191d5d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -91,10 +91,12 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) InstancesComponent &instances = geometry_set.get_component_for_write(); if (transform_space_relative) { - instances.add_instance(object, location, rotation, scale); + instances.add_instance(object, transform); } else { - instances.add_instance(object, {0, 0, 0}); + float unit_transform[4][4]; + unit_m4(unit_transform); + instances.add_instance(object, unit_transform); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index 54d37661d35..3bd8c355124 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -171,7 +171,9 @@ static void add_instances_from_geometry_component(InstancesComponent &instances, for (const int i : IndexRange(domain_size)) { if (instances_data[i].has_value()) { - instances.add_instance(*instances_data[i], positions[i], rotations[i], scales[i], ids[i]); + float transform[4][4]; + loc_eul_size_to_mat4(transform, positions[i], rotations[i], scales[i]); + instances.add_instance(*instances_data[i], transform, ids[i]); } } } 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 new file mode 100644 index 00000000000..b90ef2034a8 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -0,0 +1,259 @@ +/* + * 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. + */ + +#ifdef WITH_OPENVDB +# include +# include +# include +#endif + +#include "node_geometry_util.hh" + +#include "BKE_lib_id.h" +#include "BKE_volume.h" + +static bNodeSocketTemplate geo_node_points_to_volume_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX}, + {SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {SOCK_STRING, N_("Radius")}, + {SOCK_FLOAT, N_("Radius"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_point_translate_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +#ifdef WITH_OPENVDB +namespace { +/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */ +struct ParticleList { + using PosType = openvdb::Vec3R; + + Span positions; + Span radii; + + size_t size() const + { + return (size_t)positions.size(); + } + + void getPos(size_t n, openvdb::Vec3R &xyz) const + { + xyz = &positions[n].x; + } + + void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const + { + xyz = &positions[n].x; + radius = radii[n]; + } +}; +} // namespace + +static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span positions, + const Span radii, + const float density) +{ + /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to + * be positive. It will be set to zero later on. */ + openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f); + + /* Create a narrow-band level set grid based on the positions and radii. */ + openvdb::tools::ParticlesToLevelSet op{*new_grid}; + /* Don't ignore particles based on their radius. */ + op.setRmin(0.0f); + op.setRmax(FLT_MAX); + ParticleList particles{positions, radii}; + op.rasterizeSpheres(particles); + op.finalize(); + + /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the + * fog there will be a density of 1. */ + openvdb::tools::sdfToFogVolume(*new_grid); + + /* Take the desired density into account. */ + openvdb::tools::foreach (new_grid->beginValueOn(), + [&](const openvdb::FloatGrid::ValueOnIter &iter) { + iter.modifyValue([&](float &value) { value *= density; }); + }); + return new_grid; +} + +static float compute_voxel_size(const GeoNodeExecParams ¶ms, + Span positions, + const float radius) +{ + const NodeGeometryPointsToVolume &storage = + *(const NodeGeometryPointsToVolume *)params.node().storage; + + if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) { + return params.get_input("Voxel Size"); + } + + if (positions.is_empty()) { + return 0.0f; + } + + float3 min, max; + INIT_MINMAX(min, max); + minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size()); + + const float voxel_amount = params.get_input("Voxel Amount"); + if (voxel_amount <= 1) { + return 0.0f; + } + + /* The voxel size adapts to the final size of the volume. */ + const float diagonal = float3::distance(min, max); + const float extended_diagonal = diagonal + 2.0f * radius; + const float voxel_size = extended_diagonal / voxel_amount; + return voxel_size; +} + +static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, + const GeometryComponent &component, + Vector &r_positions, + Vector &r_radii) +{ + Float3ReadAttribute positions = component.attribute_get_for_read( + "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + FloatReadAttribute radii = params.get_input_attribute( + "Radius", component, ATTR_DOMAIN_POINT, 0.0f); + + r_positions.extend(positions.get_span()); + r_radii.extend(radii.get_span()); +} + +static void convert_to_grid_index_space(const float voxel_size, + MutableSpan positions, + MutableSpan radii) +{ + const float voxel_size_inv = 1.0f / voxel_size; + for (const int i : positions.index_range()) { + positions[i] *= voxel_size_inv; + /* Better align generated grid with source points. */ + positions[i] -= float3(0.5f); + radii[i] *= voxel_size_inv; + } +} + +static void initialize_volume_component_from_points(const GeometrySet &geometry_set_in, + GeometrySet &geometry_set_out, + const GeoNodeExecParams ¶ms) +{ + Vector positions; + Vector radii; + + if (geometry_set_in.has()) { + gather_point_data_from_component( + params, *geometry_set_in.get_component_for_read(), positions, radii); + } + if (geometry_set_in.has()) { + gather_point_data_from_component( + params, *geometry_set_in.get_component_for_read(), positions, radii); + } + + const float max_radius = *std::max_element(radii.begin(), radii.end()); + const float voxel_size = compute_voxel_size(params, positions, max_radius); + if (voxel_size == 0.0f || positions.is_empty()) { + return; + } + + Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr); + BKE_volume_init_grids(volume); + + VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT); + openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast( + BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false)); + + const float density = params.get_input("Density"); + convert_to_grid_index_space(voxel_size, positions, radii); + openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density); + /* This merge is cheap, because the #density_grid is empty. */ + density_grid->merge(*new_grid); + density_grid->transform().postScale(voxel_size); + + VolumeComponent &volume_component = geometry_set_out.get_component_for_write(); + volume_component.replace(volume); +} +#endif + +static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set_in = params.extract_input("Geometry"); + GeometrySet geometry_set_out; + +#ifdef WITH_OPENVDB + initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params); +#endif + + params.set_output("Geometry", std::move(geometry_set_out)); +} + +static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( + sizeof(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; + + bNodeSocket *radius_attribute_socket = nodeFindSocket(node, SOCK_IN, "Radius"); + bNodeSocketValueString *radius_attribute_socket_value = + (bNodeSocketValueString *)radius_attribute_socket->default_value; + STRNCPY(radius_attribute_socket_value->value, "radius"); +} + +static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; + bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); + bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); + nodeSetSocketAvailability(voxel_amount_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); + nodeSetSocketAvailability( + voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + + update_attribute_input_socket_availabilities( + *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); +} + +} // namespace blender::nodes + +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); + node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out); + node_type_storage(&ntype, + "NodeGeometryPointsToVolume", + node_free_standard_storage, + node_copy_standard_storage); + node_type_size(&ntype, 170, 120, 700); + node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); + node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); + ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index cd71a477d69..539a7551be9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -99,27 +99,20 @@ static void transform_instances(InstancesComponent &instances, const float3 rotation, const float3 scale) { - MutableSpan positions = instances.positions(); - MutableSpan rotations = instances.rotations(); - MutableSpan scales = instances.scales(); + MutableSpan transforms = instances.transforms(); /* Use only translation if rotation and scale don't apply. */ if (use_translate(rotation, scale)) { - for (float3 &position : positions) { - add_v3_v3(position, translation); + for (float4x4 &transform : transforms) { + add_v3_v3(transform.ptr()[3], translation); } } else { float mat[4][4]; - float instance_mat[4][4]; - float quaternion[4]; loc_eul_size_to_mat4(mat, translation, rotation, scale); - for (int i = 0; i < positions.size(); i++) { - loc_eul_size_to_mat4(instance_mat, positions[i], rotations[i], scales[i]); - mul_m4_m4_pre(instance_mat, mat); - mat4_decompose(positions[i], quaternion, scales[i], instance_mat); - quat_to_eul(rotations[i], quaternion); + for (float4x4 &transform : transforms) { + mul_m4_m4_pre(transform.ptr(), mat); } } } diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index a4f68419c67..1859886f563 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -768,7 +768,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) if (ss_lvl > 0) { smd.levels = smd.renderLevels = ss_lvl; - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; smd.quality = 3; height_data->ssdm = subsurf_make_derived_from_derived( diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 18ae21e3a65..1a2ff08bd08 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -127,17 +127,49 @@ static void sequence_invalidate_cache(Scene *scene, SEQ_prefetch_stop(scene); } +/* Find metastrips that contain invalidated_seq and invalidate them. */ +static bool seq_relations_find_and_invalidate_metas(Scene *scene, + Sequence *invalidated_seq, + Sequence *meta_seq) +{ + ListBase *seqbase; + + if (meta_seq == NULL) { + Editing *ed = SEQ_editing_get(scene, false); + seqbase = &ed->seqbase; + } + else { + seqbase = &meta_seq->seqbase; + } + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type == SEQ_TYPE_META) { + if (seq_relations_find_and_invalidate_metas(scene, invalidated_seq, seq)) { + sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES); + return true; + } + } + if (seq == invalidated_seq && meta_seq != NULL) { + sequence_invalidate_cache(scene, meta_seq, true, SEQ_CACHE_ALL_TYPES); + return true; + } + } + return false; +} + void SEQ_relations_invalidate_cache_in_range(Scene *scene, Sequence *seq, Sequence *range_mask, int invalidate_types) { seq_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_raw(Scene *scene, Sequence *seq) { sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) @@ -147,6 +179,7 @@ void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) true, SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq) @@ -157,6 +190,7 @@ void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq) sequence_invalidate_cache( scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq) @@ -167,6 +201,7 @@ void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq) sequence_invalidate_cache( scene, seq, false, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index fd4535ff94f..69177f39c04 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -188,7 +188,7 @@ bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); void WM_file_autoexec_init(const char *filepath); bool WM_file_read(struct bContext *C, const char *filepath, struct ReportList *reports); void WM_autosave_init(struct wmWindowManager *wm); -void WM_recover_last_session(struct bContext *C, struct ReportList *reports); +bool WM_recover_last_session(struct bContext *C, struct ReportList *reports); void WM_file_tag_modified(void); struct ID *WM_file_append_datablock(struct Main *bmain, diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index d179cc456f4..7680a786634 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -143,6 +143,8 @@ static void wm_history_file_free(RecentFile *recent); static void wm_history_file_update(void); static void wm_history_file_write(void); +static void wm_test_autorun_revert_action_exec(bContext *C); + /* -------------------------------------------------------------------- */ /** \name Misc Utility Functions * \{ */ @@ -669,6 +671,9 @@ static void wm_file_read_post(bContext *C, * won't be set to a valid value again */ CTX_wm_window_set(C, NULL); /* exits queues */ + /* Ensure auto-run action is not used from a previous blend file load. */ + wm_test_autorun_revert_action_set(NULL, NULL); + /* Ensure tools are registered. */ WM_toolsystem_init(C); } @@ -2167,10 +2172,7 @@ void WM_OT_read_factory_settings(wmOperatorType *ot) /** * Wrap #WM_file_read, shared by file reading operators. */ -static bool wm_file_read_opwrap(bContext *C, - const char *filepath, - ReportList *reports, - const bool autoexec_init) +static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports) { bool success; @@ -2178,7 +2180,8 @@ static bool wm_file_read_opwrap(bContext *C, /* do it before for now, but is this correct with multiple windows? */ WM_event_add_notifier(C, NC_WINDOW, NULL); - if (autoexec_init) { + /* Set by the "use_scripts" property on file load. */ + if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) { WM_file_autoexec_init(filepath); } @@ -2308,21 +2311,9 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op) wm_open_init_load_ui(op, false); wm_open_init_use_scripts(op, false); - if (RNA_boolean_get(op->ptr, "load_ui")) { - G.fileflags &= ~G_FILE_NO_UI; - } - else { - G.fileflags |= G_FILE_NO_UI; - } - - if (RNA_boolean_get(op->ptr, "use_scripts")) { - G.f |= G_FLAG_SCRIPT_AUTOEXEC; - } - else { - G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; - } - - success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC)); + SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); + success = wm_file_read_opwrap(C, filepath, op->reports); /* for file open also popup for warnings, not only errors */ BKE_report_print_level_set(op->reports, RPT_WARNING); @@ -2453,6 +2444,16 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op) uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE); } +static void wm_open_mainfile_def_property_use_scripts(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, + "use_scripts", + true, + "Trusted Source", + "Allow .blend file to execute scripts automatically, default available from " + "system preferences"); +} + void WM_OT_open_mainfile(wmOperatorType *ot) { ot->name = "Open"; @@ -2476,12 +2477,8 @@ void WM_OT_open_mainfile(wmOperatorType *ot) RNA_def_boolean( ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file"); - RNA_def_boolean(ot->srna, - "use_scripts", - true, - "Trusted Source", - "Allow .blend file to execute scripts automatically, default available from " - "system preferences"); + + wm_open_mainfile_def_property_use_scripts(ot); PropertyRNA *prop = RNA_def_boolean( ot->srna, "display_file_selector", true, "Display File Selector", ""); @@ -2504,15 +2501,10 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) wm_open_init_use_scripts(op, false); - if (RNA_boolean_get(op->ptr, "use_scripts")) { - G.f |= G_FLAG_SCRIPT_AUTOEXEC; - } - else { - G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; - } + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); - success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC)); + success = wm_file_read_opwrap(C, filepath, op->reports); if (success) { return OPERATOR_FINISHED; @@ -2535,12 +2527,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) ot->exec = wm_revert_mainfile_exec; ot->poll = wm_revert_mainfile_poll; - RNA_def_boolean(ot->srna, - "use_scripts", - true, - "Trusted Source", - "Allow .blend file to execute scripts automatically, default available from " - "system preferences"); + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ @@ -2549,35 +2536,39 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) /** \name Recover Last Session Operator * \{ */ -void WM_recover_last_session(bContext *C, ReportList *reports) +bool WM_recover_last_session(bContext *C, ReportList *reports) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - /* if reports==NULL, it's called directly without operator, we add a quick check here */ - if (reports || BLI_exists(filepath)) { - G.fileflags |= G_FILE_RECOVER; - - wm_file_read_opwrap(C, filepath, reports, true); - - G.fileflags &= ~G_FILE_RECOVER; - - /* XXX bad global... fixme */ - Main *bmain = CTX_data_main(C); - if (BKE_main_blendfile_path(bmain)[0] != '\0') { - G.file_loaded = 1; /* prevents splash to show */ - } - else { - G.relbase_valid = 0; - G.save_over = 0; /* start with save preference untitled.blend */ - } - } + G.fileflags |= G_FILE_RECOVER; + const bool success = wm_file_read_opwrap(C, filepath, reports); + G.fileflags &= ~G_FILE_RECOVER; + return success; } static int wm_recover_last_session_exec(bContext *C, wmOperator *op) { - WM_recover_last_session(C, op->reports); - return OPERATOR_FINISHED; + wm_open_init_use_scripts(op, true); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); + if (WM_recover_last_session(C, op->reports)) { + if (!G.background) { + wmOperatorType *ot = op->type; + PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(props_ptr, ot); + RNA_boolean_set(props_ptr, "use_scripts", true); + wm_test_autorun_revert_action_set(ot, props_ptr); + } + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; +} + +static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* Keep the current setting instead of using the preferences since a file selector + * doesn't give us the option to change the setting. */ + wm_open_init_use_scripts(op, false); + return WM_operator_confirm(C, op, event); } void WM_OT_recover_last_session(wmOperatorType *ot) @@ -2586,8 +2577,10 @@ void WM_OT_recover_last_session(wmOperatorType *ot) ot->idname = "WM_OT_recover_last_session"; ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")"; - ot->invoke = WM_operator_confirm; + ot->invoke = wm_recover_last_session_invoke; ot->exec = wm_recover_last_session_exec; + + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ @@ -2603,13 +2596,23 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", filepath); + wm_open_init_use_scripts(op, true); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); + G.fileflags |= G_FILE_RECOVER; - success = wm_file_read_opwrap(C, filepath, op->reports, true); + success = wm_file_read_opwrap(C, filepath, op->reports); G.fileflags &= ~G_FILE_RECOVER; if (success) { + if (!G.background) { + wmOperatorType *ot = op->type; + PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(props_ptr, ot); + RNA_boolean_set(props_ptr, "use_scripts", true); + wm_test_autorun_revert_action_set(ot, props_ptr); + } return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -2621,6 +2624,7 @@ static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEven wm_autosave_location(filename); RNA_string_set(op->ptr, "filepath", filename); + wm_open_init_use_scripts(op, true); WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; @@ -2642,6 +2646,8 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) WM_FILESEL_FILEPATH, FILE_VERTICALDISPLAY, FILE_SORT_TIME); + + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ @@ -2907,6 +2913,9 @@ static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void * { wmWindow *win = CTX_wm_window(C); UI_popup_block_close(C, win, arg_block); + + /* Free the data as it's no longer needed. */ + wm_test_autorun_revert_action_set(NULL, NULL); } static void wm_block_autorun_warning_reload_with_scripts(bContext *C, @@ -2924,13 +2933,7 @@ static void wm_block_autorun_warning_reload_with_scripts(bContext *C, /* Load file again with scripts enabled. * The reload is necessary to allow scripts to run when the files loads. */ - wmOperatorType *ot = WM_operatortype_find("WM_OT_revert_mainfile", false); - - PointerRNA props_ptr; - WM_operator_properties_create_ptr(&props_ptr, ot); - RNA_boolean_set(&props_ptr, "use_scripts", true); - WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr); - WM_operator_properties_free(&props_ptr); + wm_test_autorun_revert_action_exec(C); } static void wm_block_autorun_warning_enable_scripts(bContext *C, @@ -3068,6 +3071,54 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, return block; } +/** + * Store the action needed if the user needs to reload the file with Python scripts enabled. + * + * When left to NULL, this is simply revert. + * When loading files through the recover auto-save or session, + * we need to revert using other operators. + */ +static struct { + wmOperatorType *ot; + PointerRNA *ptr; +} wm_test_autorun_revert_action_data = { + .ot = NULL, + .ptr = NULL, +}; + +void wm_test_autorun_revert_action_set(wmOperatorType *ot, PointerRNA *ptr) +{ + BLI_assert(!G.background); + wm_test_autorun_revert_action_data.ot = NULL; + if (wm_test_autorun_revert_action_data.ptr != NULL) { + WM_operator_properties_free(wm_test_autorun_revert_action_data.ptr); + MEM_freeN(wm_test_autorun_revert_action_data.ptr); + wm_test_autorun_revert_action_data.ptr = NULL; + } + wm_test_autorun_revert_action_data.ot = ot; + wm_test_autorun_revert_action_data.ptr = ptr; +} + +void wm_test_autorun_revert_action_exec(bContext *C) +{ + wmOperatorType *ot = wm_test_autorun_revert_action_data.ot; + PointerRNA *ptr = wm_test_autorun_revert_action_data.ptr; + + /* Use regular revert. */ + if (ot == NULL) { + ot = WM_operatortype_find("WM_OT_revert_mainfile", false); + ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(ptr, ot); + RNA_boolean_set(ptr, "use_scripts", true); + + /* Set state, so it's freed correctly */ + wm_test_autorun_revert_action_set(ot, ptr); + } + + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, ptr); + wm_test_autorun_revert_action_set(NULL, NULL); +} + void wm_test_autorun_warning(bContext *C) { /* Test if any auto-execution of scripts failed. */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index d513598cf19..608aa116239 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -517,6 +517,9 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_blendfile_userdef_write_all(NULL); } } + /* Free the callback data used on file-open + * (will be set when a recover operation has run). */ + wm_test_autorun_revert_action_set(NULL, NULL); } } diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 336db7edb50..0ac67b987d7 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -86,6 +86,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_ int wm_window_new_exec(bContext *C, struct wmOperator *op); int wm_window_new_main_exec(bContext *C, struct wmOperator *op); +void wm_test_autorun_revert_action_set(struct wmOperatorType *ot, struct PointerRNA *ptr); void wm_test_autorun_warning(bContext *C); #ifdef __cplusplus diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 1b1ea6c1e61..499ec136e03 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -92,7 +92,8 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( if (is_upside_down) { SWAP(int, rect.ymin, rect.ymax); } - GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer); + GPU_viewport_draw_to_screen_ex( + surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); } /**