diff options
746 files changed, 17383 insertions, 11631 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index d2e2d02dcde..a9c29101123 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,6 +411,7 @@ option(WITH_CYCLES "Enable Cycles Render Engine" ON) option(WITH_CYCLES_OSL "Build Cycles with OpenShadingLanguage support" ON) option(WITH_CYCLES_EMBREE "Build Cycles with Embree support" ON) option(WITH_CYCLES_LOGGING "Build Cycles with logging support" ON) +option(WITH_CYCLES_DEBUG "Build Cycles with options useful for debugging (e.g., MIS)" OFF) option(WITH_CYCLES_STANDALONE "Build Cycles standalone application" OFF) option(WITH_CYCLES_STANDALONE_GUI "Build Cycles standalone with GUI" OFF) @@ -1069,7 +1070,7 @@ if(MSVC) add_definitions(-D__LITTLE_ENDIAN__) # OSX-Note: as we do cross-compiling with specific set architecture, - # endianess-detection and auto-setting is counterproductive + # endianness-detection and auto-setting is counterproductive # so we just set endianness according CMAKE_OSX_ARCHITECTURES elseif(CMAKE_OSX_ARCHITECTURES MATCHES i386 OR CMAKE_OSX_ARCHITECTURES MATCHES x86_64 OR CMAKE_OSX_ARCHITECTURES MATCHES arm64) @@ -1759,7 +1760,7 @@ endif() set(CMAKE_CXX_STANDARD 17) # If C++17 is not available, downgrading to an earlier standard is NOT OK. set(CMAKE_CXX_STANDARD_REQUIRED ON) -# Do not enable compiler specific language extentions. +# Do not enable compiler specific language extensions. set(CMAKE_CXX_EXTENSIONS OFF) # Make MSVC properly report the value of the __cplusplus preprocessor macro diff --git a/GNUmakefile b/GNUmakefile index 57892959d2a..e4703973384 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -51,7 +51,7 @@ Other Convenience Targets * config: Run cmake configuration tool to set build options. * deps: Build library dependencies (intended only for platform maintainers). - The existance of locally build dependancies overrides the pre-built dependencies from subversion. + The existance of locally build dependencies overrides the pre-built dependencies from subversion. These must be manually removed from '../lib/' to go back to using the pre-compiled libraries. Project Files diff --git a/build_files/build_environment/cmake/harvest.cmake b/build_files/build_environment/cmake/harvest.cmake index a3740559adc..4d06430ea49 100644 --- a/build_files/build_environment/cmake/harvest.cmake +++ b/build_files/build_environment/cmake/harvest.cmake @@ -17,7 +17,7 @@ # ***** END GPL LICENSE BLOCK ***** ######################################################################## -# Copy all generated files to the proper strucure as blender prefers +# Copy all generated files to the proper structure as blender prefers ######################################################################## if(NOT DEFINED HARVEST_TARGET) diff --git a/build_files/build_environment/cmake/options.cmake b/build_files/build_environment/cmake/options.cmake index 8930bd70fab..b37971be2a6 100644 --- a/build_files/build_environment/cmake/options.cmake +++ b/build_files/build_environment/cmake/options.cmake @@ -39,7 +39,7 @@ endif() set(DOWNLOAD_DIR "${CMAKE_CURRENT_BINARY_DIR}/downloads" CACHE STRING "Path for downloaded files") # This path must be hard-coded like this, so that the GNUmakefile knows where it is and can pass it to make_source_archive.py: set(PACKAGE_DIR "${CMAKE_CURRENT_BINARY_DIR}/packages") -option(PACKAGE_USE_UPSTREAM_SOURCES "Use soures upstream to download the package sources, when OFF the blender mirror will be used" ON) +option(PACKAGE_USE_UPSTREAM_SOURCES "Use sources upstream to download the package sources, when OFF the blender mirror will be used" ON) file(TO_CMAKE_PATH ${DOWNLOAD_DIR} DOWNLOAD_DIR) file(TO_CMAKE_PATH ${PACKAGE_DIR} PACKAGE_DIR) diff --git a/build_files/build_environment/cmake/package_python.cmake b/build_files/build_environment/cmake/package_python.cmake index 03184c783df..f5bf05dc024 100644 --- a/build_files/build_environment/cmake/package_python.cmake +++ b/build_files/build_environment/cmake/package_python.cmake @@ -24,7 +24,7 @@ if(MSVC) add_custom_command( OUTPUT ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe COMMAND echo packaging python - COMMAND echo this should ouput at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND echo this should output at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTARGET}/libs COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}.lib COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python.exe ${PYTARGET}/bin/python.exe @@ -43,7 +43,7 @@ if(MSVC) add_custom_command( OUTPUT ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe COMMAND echo packaging python - COMMAND echo this should ouput at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe + COMMAND echo this should output at ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe COMMAND ${CMAKE_COMMAND} -E make_directory ${PYTARGET}/libs COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib ${PYTARGET}/libs/python${PYTHON_SHORT_VERSION_NO_DOTS}${PYTHON_POSTFIX}.lib COMMAND ${CMAKE_COMMAND} -E copy ${PYSRC}/python${PYTHON_POSTFIX}.exe ${PYTARGET}/bin/python${PYTHON_POSTFIX}.exe diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index 2bb7175da00..24294df14ed 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -1826,7 +1826,7 @@ compile_OCIO() { # Force linking against static libs #rm -f $_inst/lib/*.so* - # Additional depencencies + # Additional dependencies #cp ext/dist/lib/libtinyxml.a $_inst/lib #cp ext/dist/lib/libyaml-cpp.a $_inst/lib diff --git a/build_files/cmake/cmake_netbeans_project.py b/build_files/cmake/cmake_netbeans_project.py index a16fc42c9b7..162fe1e2c06 100755 --- a/build_files/cmake/cmake_netbeans_project.py +++ b/build_files/cmake/cmake_netbeans_project.py @@ -180,7 +180,7 @@ def create_nb_project_main(): f.write(' </logicalFolder>\n') f.write(' </logicalFolder>\n') - # default, but this dir is infact not in blender dir so we can ignore it + # default, but this dir is in fact not in blender dir so we can ignore it # f.write(' <sourceFolderFilter>^(nbproject)$</sourceFolderFilter>\n') f.write(r' <sourceFolderFilter>^(nbproject|__pycache__|.*\.py|.*\.html|.*\.blend)$</sourceFolderFilter>\n') diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index 1471aa21505..34c2c9a684d 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -529,7 +529,7 @@ function(SETUP_LIBDIRS) # NOTE: For all new libraries, use absolute library paths. # This should eventually be phased out. - # APPLE plaform uses full paths for linking libraries, and avoids link_directories. + # APPLE platform uses full paths for linking libraries, and avoids link_directories. if(NOT MSVC AND NOT APPLE) link_directories(${JPEG_LIBPATH} ${PNG_LIBPATH} ${ZLIB_LIBPATH} ${FREETYPE_LIBPATH}) diff --git a/build_files/cmake/platform/platform_win32_bundle_crt.cmake b/build_files/cmake/platform/platform_win32_bundle_crt.cmake index 7b2e1edb1b3..699c89e29de 100644 --- a/build_files/cmake/platform/platform_win32_bundle_crt.cmake +++ b/build_files/cmake/platform/platform_win32_bundle_crt.cmake @@ -27,7 +27,7 @@ if(WITH_WINDOWS_BUNDLE_CRT) # Install the CRT to the blender.crt Sub folder. install(FILES ${CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS} DESTINATION ./blender.crt COMPONENT Libraries) - # Generating the manifest is a relativly expensive operation since + # Generating the manifest is a relatively expensive operation since # it is collecting an sha1 hash for every file required. so only do # this work when the libs have either changed or the manifest does # not exist yet. diff --git a/build_files/config/pipeline_config.yaml b/build_files/config/pipeline_config.yaml index a56d7c4a85c..8222f2ff0b9 100644 --- a/build_files/config/pipeline_config.yaml +++ b/build_files/config/pipeline_config.yaml @@ -5,38 +5,38 @@ update-code: git: submodules: - - branch: blender-v3.0-release + - branch: master commit_id: HEAD path: release/scripts/addons - - branch: blender-v3.0-release + - branch: master commit_id: HEAD path: release/scripts/addons_contrib - - branch: blender-v3.0-release + - branch: master commit_id: HEAD path: release/datafiles/locale - - branch: blender-v3.0-release + - branch: master commit_id: HEAD path: source/tools svn: libraries: darwin-arm64: - branch: tags/blender-3.0-release + branch: trunk commit_id: HEAD path: lib/darwin_arm64 darwin-x86_64: - branch: tags/blender-3.0-release + branch: trunk commit_id: HEAD path: lib/darwin linux-x86_64: - branch: tags/blender-3.0-release + branch: trunk commit_id: HEAD path: lib/linux_centos7_x86_64 windows-amd64: - branch: tags/blender-3.0-release + branch: trunk commit_id: HEAD path: lib/win64_vc15 tests: - branch: tags/blender-3.0-release + branch: trunk commit_id: HEAD path: lib/tests benchmarks: diff --git a/doc/doxygen/Doxyfile b/doc/doxygen/Doxyfile index 96eb30a852e..89954d8a155 100644 --- a/doc/doxygen/Doxyfile +++ b/doc/doxygen/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = Blender # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = V3.0 +PROJECT_NUMBER = V3.1 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/doc/python_api/examples/bpy.app.timers.5.py b/doc/python_api/examples/bpy.app.timers.5.py index dda5ea12e73..ddda0576f05 100644 --- a/doc/python_api/examples/bpy.app.timers.5.py +++ b/doc/python_api/examples/bpy.app.timers.5.py @@ -11,7 +11,7 @@ import queue execution_queue = queue.Queue() -# This function can savely be called in another thread. +# This function can safely be called in another thread. # The function will be executed when the timer runs the next time. def run_in_main_thread(function): execution_queue.put(function) diff --git a/doc/python_api/rst/info_gotcha.rst b/doc/python_api/rst/info_gotcha.rst index df6e7297e26..7361f3e9ade 100644 --- a/doc/python_api/rst/info_gotcha.rst +++ b/doc/python_api/rst/info_gotcha.rst @@ -728,7 +728,7 @@ Abusing RNA property callbacks ------------------------------ Python-defined RNA properties can have custom callbacks. Trying to perform complex operations -from there, like calling an operator, may work, but is not officialy recommended nor supported. +from there, like calling an operator, may work, but is not officially recommended nor supported. Main reason is that those callback should be very fast, but additionally, it may for example create issues with undo/redo system (most operators store an history step, and editing an RNA diff --git a/doc/python_api/sphinx_doc_gen.py b/doc/python_api/sphinx_doc_gen.py index f8638b97270..7e2be8ddf75 100644 --- a/doc/python_api/sphinx_doc_gen.py +++ b/doc/python_api/sphinx_doc_gen.py @@ -1224,7 +1224,10 @@ def pycontext2sphinx(basepath): while char_array[i] is not None: member = ctypes.string_at(char_array[i]).decode(encoding="ascii") fw(".. data:: %s\n\n" % member) - member_type, is_seq = context_type_map[member] + try: + member_type, is_seq = context_type_map[member] + except KeyError: + raise SystemExit("Error: context key %r not found in context_type_map; update %s" % (member, __file__)) from None fw(" :type: %s :class:`bpy.types.%s`\n\n" % ("sequence of " if is_seq else "", member_type)) unique.add(member) i += 1 @@ -2251,7 +2254,7 @@ def main(): # First monkey patch to load in fake members. setup_monkey_patch() - # Perform changes to Blender it's self. + # Perform changes to Blender itself. setup_data = setup_blender() # eventually, create the dirs diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 1500743763b..8854170c642 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -226,6 +226,9 @@ add_definitions( -DCCL_NAMESPACE_END=} ) +if(WITH_CYCLES_DEBUG) + add_definitions(-DWITH_CYCLES_DEBUG) +endif() if(WITH_CYCLES_STANDALONE_GUI) add_definitions(-DWITH_CYCLES_STANDALONE_GUI) endif() @@ -334,7 +337,7 @@ else() endif() # Warnings -if(CMAKE_COMPILER_IS_GNUCXX) +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_C_COMPILER_ID MATCHES "Clang") ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_float_conversion "-Werror=float-conversion") ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_cxxflag_double_promotion "-Werror=double-promotion") ADD_CHECK_CXX_COMPILER_FLAG(CMAKE_CXX_FLAGS _has_no_error_unused_macros "-Wno-error=unused-macros") diff --git a/intern/cycles/blender/CMakeLists.txt b/intern/cycles/blender/CMakeLists.txt index 149967ad331..f0540486656 100644 --- a/intern/cycles/blender/CMakeLists.txt +++ b/intern/cycles/blender/CMakeLists.txt @@ -138,11 +138,6 @@ endif() blender_add_lib(bf_intern_cycles "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") -# avoid link failure with clang 3.4 debug -if(CMAKE_C_COMPILER_ID MATCHES "Clang" AND NOT ${CMAKE_C_COMPILER_VERSION} VERSION_LESS '3.4') - string(APPEND CMAKE_CXX_FLAGS_DEBUG " -gline-tables-only") -endif() - add_dependencies(bf_intern_cycles bf_rna) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${ADDON_FILES}" ${CYCLES_INSTALL_PATH}) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index e74619d0c4b..645f370c000 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -218,6 +218,12 @@ enum_denoising_prefilter = ( ('ACCURATE', "Accurate", "Prefilter noisy guiding passes before denoising color. Improves quality when guiding passes are noisy using extra processing time", 3), ) +enum_direct_light_sampling_type = ( + ('MULTIPLE_IMPORTANCE_SAMPLING', "Multiple Importance Sampling", "Multiple importance sampling is used to combine direct light contributions from next-event estimation and forward path tracing", 0), + ('FORWARD_PATH_TRACING', "Forward Path Tracing", "Direct light contributions are only sampled using forward path tracing", 1), + ('NEXT_EVENT_ESTIMATION', "Next-Event Estimation", "Direct light contributions are only sampled using next-event estimation", 2), +) + def update_render_passes(self, context): scene = context.scene view_layer = context.view_layer @@ -325,6 +331,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=1024, ) + sample_offset: IntProperty( + name="Sample Offset", + description="Number of samples to skip when starting render", + min=0, max=(1 << 24), + default=0, + ) + time_limit: FloatProperty( name="Time Limit", description="Limit the render time (excluding synchronization time)." @@ -415,6 +428,13 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): default=0, ) + direct_light_sampling_type: EnumProperty( + name="Direct Light Sampling Type", + description="The type of strategy used for sampling direct light contributions", + items=enum_direct_light_sampling_type, + default='MULTIPLE_IMPORTANCE_SAMPLING', + ) + min_light_bounces: IntProperty( name="Min Light Bounces", description="Minimum number of light bounces. Setting this higher reduces noise in the first bounces, " diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 397823103c8..57741447608 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -290,6 +290,9 @@ class CYCLES_RENDER_PT_sampling_advanced(CyclesButtonsPanel, Panel): col.active = not (cscene.use_adaptive_sampling and cscene.use_preview_adaptive_sampling) col.prop(cscene, "sampling_pattern", text="Pattern") + col = layout.column(align=True) + col.prop(cscene, "sample_offset") + layout.separator() heading = layout.column(align=True, heading="Scrambling Distance") diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp index ffe0c553738..c96d01a8ffb 100644 --- a/intern/cycles/blender/curves.cpp +++ b/intern/cycles/blender/curves.cpp @@ -199,7 +199,7 @@ static bool ObtainCacheParticleUV(Hair *hair, b_mesh->uv_layers.begin(l); float2 uv = zero_float2(); - if (b_mesh->uv_layers.length()) + if (!b_mesh->uv_layers.empty()) b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.x); CData->curve_uv.push_back_slow(uv); @@ -261,7 +261,7 @@ static bool ObtainCacheParticleVcol(Hair *hair, b_mesh->vertex_colors.begin(l); float4 vcol = make_float4(0.0f, 0.0f, 0.0f, 1.0f); - if (b_mesh->vertex_colors.length()) + if (!b_mesh->vertex_colors.empty()) b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x); CData->curve_vcol.push_back_slow(vcol); diff --git a/intern/cycles/blender/display_driver.cpp b/intern/cycles/blender/display_driver.cpp index d5f6d85251e..abf421983b3 100644 --- a/intern/cycles/blender/display_driver.cpp +++ b/intern/cycles/blender/display_driver.cpp @@ -334,7 +334,7 @@ bool BlenderDisplayDriver::update_begin(const Params ¶ms, /* Update PBO dimensions if needed. * - * NOTE: Allocate the PBO for the the size which will fit the final render resolution (as in, + * NOTE: Allocate the PBO for the size which will fit the final render resolution (as in, * at a resolution divider 1. This was we don't need to recreate graphics interoperability * objects which are costly and which are tied to the specific underlying buffer size. * The downside of this approach is that when graphics interoperability is not used we are diff --git a/intern/cycles/blender/mesh.cpp b/intern/cycles/blender/mesh.cpp index b69bf88c213..bb17cfdcb45 100644 --- a/intern/cycles/blender/mesh.cpp +++ b/intern/cycles/blender/mesh.cpp @@ -555,7 +555,7 @@ static void attr_create_vertex_color(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, /* Create uv map attributes. */ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh) { - if (b_mesh.uv_layers.length() != 0) { + if (!b_mesh.uv_layers.empty()) { for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) { const bool active_render = l.active_render(); AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; @@ -619,7 +619,7 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh) static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs) { - if (b_mesh.uv_layers.length() != 0) { + if (!b_mesh.uv_layers.empty()) { BL::Mesh::uv_layers_iterator l; int i = 0; @@ -951,7 +951,7 @@ static void create_mesh(Scene *scene, N = attr_N->data_float3(); /* create generated coordinates from undeformed coordinates */ - const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.length() == 0) && + const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.empty()) && (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) { Attribute *attr = attributes.add(ATTR_STD_GENERATED); diff --git a/intern/cycles/blender/sync.cpp b/intern/cycles/blender/sync.cpp index 43625a2e479..949b7cb1b3b 100644 --- a/intern/cycles/blender/sync.cpp +++ b/intern/cycles/blender/sync.cpp @@ -392,6 +392,12 @@ void BlenderSync::sync_integrator(BL::ViewLayer &b_view_layer, bool background) integrator->set_ao_bounces(0); } +#ifdef WITH_CYCLES_DEBUG + DirectLightSamplingType direct_light_sampling_type = (DirectLightSamplingType)get_enum( + cscene, "direct_light_sampling_type", DIRECT_LIGHT_SAMPLING_NUM, DIRECT_LIGHT_SAMPLING_MIS); + integrator->set_direct_light_sampling_type(direct_light_sampling_type); +#endif + const DenoiseParams denoise_params = get_denoise_params(b_scene, b_view_layer, background); integrator->set_use_denoise(denoise_params.use); @@ -835,18 +841,25 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, /* samples */ int samples = get_int(cscene, "samples"); int preview_samples = get_int(cscene, "preview_samples"); + int sample_offset = get_int(cscene, "sample_offset"); if (background) { params.samples = samples; + params.sample_offset = sample_offset; } else { params.samples = preview_samples; - if (params.samples == 0) + if (params.samples == 0) { params.samples = INT_MAX; + } + params.sample_offset = 0; } + /* Clamp sample offset. */ + params.sample_offset = clamp(params.sample_offset, 0, Integrator::MAX_SAMPLES); + /* Clamp samples. */ - params.samples = min(params.samples, Integrator::MAX_SAMPLES); + params.samples = clamp(params.samples, 0, Integrator::MAX_SAMPLES - params.sample_offset); /* Viewport Performance */ params.pixel_size = b_engine.get_preview_pixel_size(b_scene); @@ -865,7 +878,7 @@ SessionParams BlenderSync::get_session_params(BL::RenderEngine &b_engine, /* Time limit. */ if (background) { - params.time_limit = get_float(cscene, "time_limit"); + params.time_limit = (double)get_float(cscene, "time_limit"); } else { /* For the viewport it kind of makes more sense to think in terms of the noise floor, which is diff --git a/intern/cycles/blender/util.h b/intern/cycles/blender/util.h index 33fd2c416c8..be36bcdaaa8 100644 --- a/intern/cycles/blender/util.h +++ b/intern/cycles/blender/util.h @@ -303,7 +303,7 @@ static inline string image_user_file_path(BL::ImageUser &iuser, string filepath_str = string(filepath); if (load_tiled && ima.source() == BL::Image::source_TILED) { string udim; - if (ima.tiles.length() > 0) { + if (!ima.tiles.empty()) { udim = to_string(ima.tiles[0].number()); } string_replace(filepath_str, udim, "<UDIM>"); @@ -647,7 +647,7 @@ static inline Mesh::SubdivisionType object_subdivision_type(BL::Object &b_ob, { PointerRNA cobj = RNA_pointer_get(&b_ob.ptr, "cycles"); - if (cobj.data && b_ob.modifiers.length() > 0 && experimental) { + if (cobj.data && !b_ob.modifiers.empty() && experimental) { BL::Modifier mod = b_ob.modifiers[b_ob.modifiers.length() - 1]; bool enabled = preview ? mod.show_viewport() : mod.show_render(); diff --git a/intern/cycles/bvh/embree.cpp b/intern/cycles/bvh/embree.cpp index 944a84ce0da..b54b38f2798 100644 --- a/intern/cycles/bvh/embree.cpp +++ b/intern/cycles/bvh/embree.cpp @@ -303,7 +303,7 @@ static void rtc_error_func(void *, enum RTCError, const char *str) VLOG(1) << str; } -static double progress_start_time = 0.0f; +static double progress_start_time = 0.0; static bool rtc_progress_func(void *user_ptr, const double n) { diff --git a/intern/cycles/bvh/node.cpp b/intern/cycles/bvh/node.cpp index d3a665adfe7..60b0843bde2 100644 --- a/intern/cycles/bvh/node.cpp +++ b/intern/cycles/bvh/node.cpp @@ -153,7 +153,7 @@ void BVHNode::update_time() namespace { struct DumpTraversalContext { - /* Descriptor of wile where writing is happening. */ + /* Descriptor of while where writing is happening. */ FILE *stream; /* Unique identifier of the node current. */ int id; diff --git a/intern/cycles/bvh/node.h b/intern/cycles/bvh/node.h index d5de9e062fc..1fd9efdb75e 100644 --- a/intern/cycles/bvh/node.h +++ b/intern/cycles/bvh/node.h @@ -178,7 +178,7 @@ class InnerNode : public BVHNode { reset_unused_children(); } - /* NOTE: This function is only used during binary BVH builder, and it + /* NOTE: This function is only used during binary BVH builder, and it's * supposed to be configured to have 2 children which will be filled-in in a * bit. But this is important to have children reset to NULL. */ explicit InnerNode(const BoundBox &bounds) : BVHNode(bounds), num_children_(0) diff --git a/intern/cycles/cmake/macros.cmake b/intern/cycles/cmake/macros.cmake index a470fb9c574..957b702fd3a 100644 --- a/intern/cycles/cmake/macros.cmake +++ b/intern/cycles/cmake/macros.cmake @@ -88,7 +88,7 @@ endmacro() function(cycles_link_directories) if(APPLE) - # APPLE plaform uses full paths for linking libraries, and avoids link_directories. + # APPLE platform uses full paths for linking libraries, and avoids link_directories. return() endif() diff --git a/intern/cycles/device/cpu/device.cpp b/intern/cycles/device/cpu/device.cpp index f11b49ef65f..5aabed8702a 100644 --- a/intern/cycles/device/cpu/device.cpp +++ b/intern/cycles/device/cpu/device.cpp @@ -38,7 +38,6 @@ void device_cpu_info(vector<DeviceInfo> &devices) info.id = "CPU"; info.num = 0; info.has_osl = true; - info.has_half_images = true; info.has_nanovdb = true; info.has_profiling = true; if (openimagedenoise_supported()) { diff --git a/intern/cycles/device/cpu/device_impl.cpp b/intern/cycles/device/cpu/device_impl.cpp index 68dec7f0af2..2ad76de70ca 100644 --- a/intern/cycles/device/cpu/device_impl.cpp +++ b/intern/cycles/device/cpu/device_impl.cpp @@ -93,11 +93,6 @@ CPUDevice::~CPUDevice() texture_info.free(); } -bool CPUDevice::show_samples() const -{ - return (info.cpu_threads == 1); -} - BVHLayoutMask CPUDevice::get_bvh_layout_mask() const { BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_BVH2; diff --git a/intern/cycles/device/cpu/device_impl.h b/intern/cycles/device/cpu/device_impl.h index 90d217bb624..6f9452a6378 100644 --- a/intern/cycles/device/cpu/device_impl.h +++ b/intern/cycles/device/cpu/device_impl.h @@ -60,8 +60,6 @@ class CPUDevice : public Device { CPUDevice(const DeviceInfo &info_, Stats &stats_, Profiler &profiler_); ~CPUDevice(); - virtual bool show_samples() const override; - virtual BVHLayoutMask get_bvh_layout_mask() const override; /* Returns true if the texture info was copied to the device (meaning, some more diff --git a/intern/cycles/device/cuda/device.cpp b/intern/cycles/device/cuda/device.cpp index af2bdc6e29c..0d9e6c72466 100644 --- a/intern/cycles/device/cuda/device.cpp +++ b/intern/cycles/device/cuda/device.cpp @@ -144,7 +144,6 @@ void device_cuda_info(vector<DeviceInfo> &devices) info.description = string(name); info.num = num; - info.has_half_images = (major >= 3); info.has_nanovdb = true; info.denoisers = 0; diff --git a/intern/cycles/device/cuda/device_impl.cpp b/intern/cycles/device/cuda/device_impl.cpp index 20945796a2d..e05fef3897c 100644 --- a/intern/cycles/device/cuda/device_impl.cpp +++ b/intern/cycles/device/cuda/device_impl.cpp @@ -46,12 +46,6 @@ bool CUDADevice::have_precompiled_kernels() return path_exists(cubins_path); } -bool CUDADevice::show_samples() const -{ - /* The CUDADevice only processes one tile at a time, so showing samples is fine. */ - return true; -} - BVHLayoutMask CUDADevice::get_bvh_layout_mask() const { return BVH_LAYOUT_BVH2; @@ -242,6 +236,10 @@ string CUDADevice::compile_kernel_get_common_cflags(const uint kernel_features) cflags += " -DWITH_NANOVDB"; # endif +# ifdef WITH_CYCLES_DEBUG + cflags += " -DWITH_CYCLES_DEBUG"; +# endif + return cflags; } @@ -932,7 +930,6 @@ void CUDADevice::tex_alloc(device_texture &mem) { CUDAContextScope scope(this); - /* General variables for both architectures */ string bind_name = mem.name; size_t dsize = datatype_size(mem.data_type); size_t size = mem.memory_size(); @@ -1095,7 +1092,6 @@ void CUDADevice::tex_alloc(device_texture &mem) if (mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT && mem.info.data_type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3) { - /* Kepler+, bindless textures. */ CUDA_RESOURCE_DESC resDesc; memset(&resDesc, 0, sizeof(resDesc)); diff --git a/intern/cycles/device/cuda/device_impl.h b/intern/cycles/device/cuda/device_impl.h index 72d4108d1bf..4c357d0b5ab 100644 --- a/intern/cycles/device/cuda/device_impl.h +++ b/intern/cycles/device/cuda/device_impl.h @@ -76,8 +76,6 @@ class CUDADevice : public Device { static bool have_precompiled_kernels(); - virtual bool show_samples() const override; - virtual BVHLayoutMask get_bvh_layout_mask() const override; void set_error(const string &error) override; diff --git a/intern/cycles/device/device.cpp b/intern/cycles/device/device.cpp index 63d0a49d3eb..bfbcdb20d5e 100644 --- a/intern/cycles/device/device.cpp +++ b/intern/cycles/device/device.cpp @@ -286,7 +286,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, info.description = "Multi Device"; info.num = 0; - info.has_half_images = true; info.has_nanovdb = true; info.has_osl = true; info.has_profiling = true; @@ -333,7 +332,6 @@ DeviceInfo Device::get_multi_device(const vector<DeviceInfo> &subdevices, } /* Accumulate device info. */ - info.has_half_images &= device.has_half_images; info.has_nanovdb &= device.has_nanovdb; info.has_osl &= device.has_osl; info.has_profiling &= device.has_profiling; diff --git a/intern/cycles/device/device.h b/intern/cycles/device/device.h index 65188459c2c..346632de314 100644 --- a/intern/cycles/device/device.h +++ b/intern/cycles/device/device.h @@ -73,7 +73,6 @@ class DeviceInfo { int num; bool display_device; /* GPU is used as a display device. */ bool has_nanovdb; /* Support NanoVDB volumes. */ - bool has_half_images; /* Support half-float textures. */ bool has_osl; /* Support Open Shading Language. */ bool has_profiling; /* Supports runtime collection of profiling info. */ bool has_peer_memory; /* GPU has P2P access to memory of another GPU. */ @@ -90,7 +89,6 @@ class DeviceInfo { num = 0; cpu_threads = 0; display_device = false; - has_half_images = false; has_nanovdb = false; has_osl = false; has_profiling = false; @@ -151,10 +149,6 @@ class Device { fprintf(stderr, "%s\n", error.c_str()); fflush(stderr); } - virtual bool show_samples() const - { - return false; - } virtual BVHLayoutMask get_bvh_layout_mask() const = 0; /* statistics */ diff --git a/intern/cycles/device/hip/device.cpp b/intern/cycles/device/hip/device.cpp index ecc109b2bb9..a9c7b1ba841 100644 --- a/intern/cycles/device/hip/device.cpp +++ b/intern/cycles/device/hip/device.cpp @@ -148,7 +148,6 @@ void device_hip_info(vector<DeviceInfo> &devices) info.description = string(name); info.num = num; - info.has_half_images = true; info.has_nanovdb = true; info.denoisers = 0; diff --git a/intern/cycles/device/hip/device_impl.cpp b/intern/cycles/device/hip/device_impl.cpp index 42dd5382ae5..53c4f3f0b3f 100644 --- a/intern/cycles/device/hip/device_impl.cpp +++ b/intern/cycles/device/hip/device_impl.cpp @@ -47,12 +47,6 @@ bool HIPDevice::have_precompiled_kernels() return path_exists(fatbins_path); } -bool HIPDevice::show_samples() const -{ - /* The HIPDevice only processes one tile at a time, so showing samples is fine. */ - return true; -} - BVHLayoutMask HIPDevice::get_bvh_layout_mask() const { return BVH_LAYOUT_BVH2; @@ -243,7 +237,7 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c hipGetDeviceProperties(&props, hipDevId); /* gcnArchName can contain tokens after the arch name with features, ie. - "gfx1010:sramecc-:xnack-" so we tokenize it to get the first part. */ + * `gfx1010:sramecc-:xnack-` so we tokenize it to get the first part. */ char *arch = strtok(props.gcnArchName, ":"); if (arch == NULL) { arch = props.gcnArchName; @@ -374,10 +368,9 @@ string HIPDevice::compile_kernel(const uint kernel_features, const char *name, c bool HIPDevice::load_kernels(const uint kernel_features) { - /* TODO(sergey): Support kernels re-load for CUDA devices adaptive compile. + /* TODO(sergey): Support kernels re-load for HIP devices adaptive compile. * - * Currently re-loading kernel will invalidate memory pointers, - * causing problems in cuCtxSynchronize. + * Currently re-loading kernels will invalidate memory pointers. */ if (hipModule) { if (use_adaptive_compilation()) { @@ -899,7 +892,6 @@ void HIPDevice::tex_alloc(device_texture &mem) { HIPContextScope scope(this); - /* General variables for both architectures */ string bind_name = mem.name; size_t dsize = datatype_size(mem.data_type); size_t size = mem.memory_size(); diff --git a/intern/cycles/device/hip/device_impl.h b/intern/cycles/device/hip/device_impl.h index eb832ad828c..08a7be57e9c 100644 --- a/intern/cycles/device/hip/device_impl.h +++ b/intern/cycles/device/hip/device_impl.h @@ -75,8 +75,6 @@ class HIPDevice : public Device { static bool have_precompiled_kernels(); - virtual bool show_samples() const override; - virtual BVHLayoutMask get_bvh_layout_mask() const override; void set_error(const string &error) override; @@ -93,9 +91,7 @@ class HIPDevice : public Device { virtual string compile_kernel_get_common_cflags(const uint kernel_features); - string compile_kernel(const uint kernel_features, - const char *name, - const char *base = "hip"); + string compile_kernel(const uint kernel_features, const char *name, const char *base = "hip"); virtual bool load_kernels(const uint kernel_features) override; void reserve_local_memory(const uint kernel_features); diff --git a/intern/cycles/device/hip/graphics_interop.h b/intern/cycles/device/hip/graphics_interop.h index 8314405e670..71c6893edbd 100644 --- a/intern/cycles/device/hip/graphics_interop.h +++ b/intern/cycles/device/hip/graphics_interop.h @@ -48,7 +48,7 @@ class HIPDeviceGraphicsInterop : public DeviceGraphicsInterop { HIPDeviceQueue *queue_ = nullptr; HIPDevice *device_ = nullptr; - /* OpenGL PBO which is currently registered as the destination for the CUDA buffer. */ + /* OpenGL PBO which is currently registered as the destination for the HIP buffer. */ uint opengl_pbo_id_ = 0; /* Buffer area in pixels of the corresponding PBO. */ int64_t buffer_area_ = 0; diff --git a/intern/cycles/device/memory.cpp b/intern/cycles/device/memory.cpp index 86bf2542c92..ba2d993fb9e 100644 --- a/intern/cycles/device/memory.cpp +++ b/intern/cycles/device/memory.cpp @@ -23,7 +23,7 @@ CCL_NAMESPACE_BEGIN device_memory::device_memory(Device *device, const char *name, MemoryType type) : data_type(device_type_traits<uchar>::data_type), - data_elements(device_type_traits<uchar>::num_elements_cpu), + data_elements(device_type_traits<uchar>::num_elements), data_size(0), device_size(0), data_width(0), diff --git a/intern/cycles/device/memory.h b/intern/cycles/device/memory.h index e04142117aa..cb22c191656 100644 --- a/intern/cycles/device/memory.h +++ b/intern/cycles/device/memory.h @@ -81,155 +81,140 @@ static constexpr size_t datatype_size(DataType datatype) template<typename T> struct device_type_traits { static const DataType data_type = TYPE_UNKNOWN; - static const size_t num_elements_cpu = sizeof(T); - static const size_t num_elements_gpu = sizeof(T); + static const size_t num_elements = sizeof(T); }; template<> struct device_type_traits<uchar> { static const DataType data_type = TYPE_UCHAR; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(uchar) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(uchar) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uchar2> { static const DataType data_type = TYPE_UCHAR; - static const size_t num_elements_cpu = 2; - static const size_t num_elements_gpu = 2; - static_assert(sizeof(uchar2) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 2; + static_assert(sizeof(uchar2) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uchar3> { static const DataType data_type = TYPE_UCHAR; - static const size_t num_elements_cpu = 3; - static const size_t num_elements_gpu = 3; - static_assert(sizeof(uchar3) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 3; + static_assert(sizeof(uchar3) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uchar4> { static const DataType data_type = TYPE_UCHAR; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(uchar4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(uchar4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint> { static const DataType data_type = TYPE_UINT; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(uint) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(uint) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint2> { static const DataType data_type = TYPE_UINT; - static const size_t num_elements_cpu = 2; - static const size_t num_elements_gpu = 2; - static_assert(sizeof(uint2) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 2; + static_assert(sizeof(uint2) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint3> { static const DataType data_type = TYPE_UINT; - static const size_t num_elements_cpu = 3; - static const size_t num_elements_gpu = 3; - static_assert(sizeof(uint3) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 3; + static_assert(sizeof(uint3) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint4> { static const DataType data_type = TYPE_UINT; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(uint4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(uint4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<int> { static const DataType data_type = TYPE_INT; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(int) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(int) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<int2> { static const DataType data_type = TYPE_INT; - static const size_t num_elements_cpu = 2; - static const size_t num_elements_gpu = 2; - static_assert(sizeof(int2) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 2; + static_assert(sizeof(int2) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<int3> { static const DataType data_type = TYPE_INT; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 3; - static_assert(sizeof(int3) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(int3) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<int4> { static const DataType data_type = TYPE_INT; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(int4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(int4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<float> { static const DataType data_type = TYPE_FLOAT; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(float) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(float) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<float2> { static const DataType data_type = TYPE_FLOAT; - static const size_t num_elements_cpu = 2; - static const size_t num_elements_gpu = 2; - static_assert(sizeof(float2) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 2; + static_assert(sizeof(float2) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<float3> { + /* float3 has different size depending on the device, can't use it for interchanging + * memory between CPU and GPU. + * + * Leave body empty to trigger a compile error if used. */ +}; + +template<> struct device_type_traits<packed_float3> { static const DataType data_type = TYPE_FLOAT; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 3; - static_assert(sizeof(float3) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 3; + static_assert(sizeof(packed_float3) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<float4> { static const DataType data_type = TYPE_FLOAT; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(float4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(float4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<half> { static const DataType data_type = TYPE_HALF; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(half) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(half) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<ushort4> { static const DataType data_type = TYPE_UINT16; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(ushort4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(ushort4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint16_t> { static const DataType data_type = TYPE_UINT16; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(uint16_t) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(uint16_t) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<half4> { static const DataType data_type = TYPE_HALF; - static const size_t num_elements_cpu = 4; - static const size_t num_elements_gpu = 4; - static_assert(sizeof(half4) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 4; + static_assert(sizeof(half4) == num_elements * datatype_size(data_type)); }; template<> struct device_type_traits<uint64_t> { static const DataType data_type = TYPE_UINT64; - static const size_t num_elements_cpu = 1; - static const size_t num_elements_gpu = 1; - static_assert(sizeof(uint64_t) == num_elements_cpu * datatype_size(data_type)); + static const size_t num_elements = 1; + static_assert(sizeof(uint64_t) == num_elements * datatype_size(data_type)); }; /* Device Memory @@ -325,9 +310,7 @@ template<typename T> class device_only_memory : public device_memory { : device_memory(device, name, allow_host_memory_fallback ? MEM_READ_WRITE : MEM_DEVICE_ONLY) { data_type = device_type_traits<T>::data_type; - data_elements = max(device_is_cpu() ? device_type_traits<T>::num_elements_cpu : - device_type_traits<T>::num_elements_gpu, - 1); + data_elements = max(device_type_traits<T>::num_elements, 1); } device_only_memory(device_only_memory &&other) noexcept : device_memory(std::move(other)) @@ -383,15 +366,11 @@ template<typename T> class device_only_memory : public device_memory { template<typename T> class device_vector : public device_memory { public: - /* Can only use this for types that have the same size on CPU and GPU. */ - static_assert(device_type_traits<T>::num_elements_cpu == - device_type_traits<T>::num_elements_gpu); - device_vector(Device *device, const char *name, MemoryType type) : device_memory(device, name, type) { data_type = device_type_traits<T>::data_type; - data_elements = device_type_traits<T>::num_elements_cpu; + data_elements = device_type_traits<T>::num_elements; modified = true; need_realloc_ = true; diff --git a/intern/cycles/device/multi/device.cpp b/intern/cycles/device/multi/device.cpp index 56efec3e131..e319246d4f4 100644 --- a/intern/cycles/device/multi/device.cpp +++ b/intern/cycles/device/multi/device.cpp @@ -109,14 +109,6 @@ class MultiDevice : public Device { return error_msg; } - virtual bool show_samples() const override - { - if (devices.size() > 1) { - return false; - } - return devices.front().device->show_samples(); - } - virtual BVHLayoutMask get_bvh_layout_mask() const override { BVHLayoutMask bvh_layout_mask = BVH_LAYOUT_ALL; diff --git a/intern/cycles/doc/license/readme.txt b/intern/cycles/doc/license/readme.txt index cc5476e3511..f610d800ebc 100644 --- a/intern/cycles/doc/license/readme.txt +++ b/intern/cycles/doc/license/readme.txt @@ -3,7 +3,7 @@ This program uses code from various sources, the default license is Apache 2.0 for all code, with the following exceptions. Modified BSD License -* Code adapated from Open Shading Language +* Code adapted from Open Shading Language * Sobol direction vectors * Matrix inversion code from OpenEXR * MD5 Hash code diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp index 92bf8e69d19..ec90681b78a 100644 --- a/intern/cycles/integrator/path_trace.cpp +++ b/intern/cycles/integrator/path_trace.cpp @@ -380,7 +380,10 @@ void PathTrace::path_trace(RenderWork &render_work) PathTraceWork *path_trace_work = path_trace_works_[i].get(); PathTraceWork::RenderStatistics statistics; - path_trace_work->render_samples(statistics, render_work.path_trace.start_sample, num_samples); + path_trace_work->render_samples(statistics, + render_work.path_trace.start_sample, + num_samples, + render_work.path_trace.sample_offset); const double work_time = time_dt() - work_start_time; work_balance_infos_[i].time_spent += work_time; @@ -850,7 +853,8 @@ void PathTrace::progress_update_if_needed(const RenderWork &render_work) const uint64_t num_samples_added = uint64_t(tile_size.x) * tile_size.y * render_work.path_trace.num_samples; const int current_sample = render_work.path_trace.start_sample + - render_work.path_trace.num_samples; + render_work.path_trace.num_samples - + render_work.path_trace.sample_offset; progress_->add_samples(num_samples_added, current_sample); } diff --git a/intern/cycles/integrator/path_trace_display.h b/intern/cycles/integrator/path_trace_display.h index b69ee85fbbc..47014f43afa 100644 --- a/intern/cycles/integrator/path_trace_display.h +++ b/intern/cycles/integrator/path_trace_display.h @@ -76,7 +76,7 @@ class PathTraceDisplay { /* Copy buffer of rendered pixels of a given size into a given position of the texture. * - * This function does not acquire a lock. The reason for this is is to allow use of this function + * This function does not acquire a lock. The reason for this is to allow use of this function * for partial updates from different devices. In this case the caller will acquire the lock * once, update all the slices and release * the lock once. This will ensure that draw() will never use partially updated texture. */ diff --git a/intern/cycles/integrator/path_trace_work.h b/intern/cycles/integrator/path_trace_work.h index 0dc7cd2f896..2ebfc913580 100644 --- a/intern/cycles/integrator/path_trace_work.h +++ b/intern/cycles/integrator/path_trace_work.h @@ -75,7 +75,10 @@ class PathTraceWork { /* Render given number of samples as a synchronous blocking call. * The samples are added to the render buffer associated with this work. */ - virtual void render_samples(RenderStatistics &statistics, int start_sample, int samples_num) = 0; + virtual void render_samples(RenderStatistics &statistics, + int start_sample, + int samples_num, + int sample_offset) = 0; /* Copy render result from this work to the corresponding place of the GPU display. * diff --git a/intern/cycles/integrator/path_trace_work_cpu.cpp b/intern/cycles/integrator/path_trace_work_cpu.cpp index 12dcc899dbb..2f6c3cf5aca 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.cpp +++ b/intern/cycles/integrator/path_trace_work_cpu.cpp @@ -71,7 +71,8 @@ void PathTraceWorkCPU::init_execution() void PathTraceWorkCPU::render_samples(RenderStatistics &statistics, int start_sample, - int samples_num) + int samples_num, + int sample_offset) { const int64_t image_width = effective_buffer_params_.width; const int64_t image_height = effective_buffer_params_.height; @@ -99,6 +100,7 @@ void PathTraceWorkCPU::render_samples(RenderStatistics &statistics, work_tile.w = 1; work_tile.h = 1; work_tile.start_sample = start_sample; + work_tile.sample_offset = sample_offset; work_tile.num_samples = 1; work_tile.offset = effective_buffer_params_.offset; work_tile.stride = effective_buffer_params_.stride; diff --git a/intern/cycles/integrator/path_trace_work_cpu.h b/intern/cycles/integrator/path_trace_work_cpu.h index 6e734690811..63ab686588c 100644 --- a/intern/cycles/integrator/path_trace_work_cpu.h +++ b/intern/cycles/integrator/path_trace_work_cpu.h @@ -48,7 +48,8 @@ class PathTraceWorkCPU : public PathTraceWork { virtual void render_samples(RenderStatistics &statistics, int start_sample, - int samples_num) override; + int samples_num, + int sample_offset) override; virtual void copy_to_display(PathTraceDisplay *display, PassMode pass_mode, diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp index b9784f68f56..956aa6a8c90 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.cpp +++ b/intern/cycles/integrator/path_trace_work_gpu.cpp @@ -250,7 +250,8 @@ void PathTraceWorkGPU::init_execution() void PathTraceWorkGPU::render_samples(RenderStatistics &statistics, int start_sample, - int samples_num) + int samples_num, + int sample_offset) { /* Limit number of states for the tile and rely on a greedy scheduling of tiles. This allows to * add more work (because tiles are smaller, so there is higher chance that more paths will @@ -261,6 +262,7 @@ void PathTraceWorkGPU::render_samples(RenderStatistics &statistics, work_tile_scheduler_.reset(effective_buffer_params_, start_sample, samples_num, + sample_offset, device_scene_->data.integrator.scrambling_distance); enqueue_reset(); diff --git a/intern/cycles/integrator/path_trace_work_gpu.h b/intern/cycles/integrator/path_trace_work_gpu.h index c5e291e72db..5aa497c26e7 100644 --- a/intern/cycles/integrator/path_trace_work_gpu.h +++ b/intern/cycles/integrator/path_trace_work_gpu.h @@ -46,7 +46,8 @@ class PathTraceWorkGPU : public PathTraceWork { virtual void render_samples(RenderStatistics &statistics, int start_sample, - int samples_num) override; + int samples_num, + int sample_offset) override; virtual void copy_to_display(PathTraceDisplay *display, PassMode pass_mode, diff --git a/intern/cycles/integrator/render_scheduler.cpp b/intern/cycles/integrator/render_scheduler.cpp index 276453f7aec..971173a5e96 100644 --- a/intern/cycles/integrator/render_scheduler.cpp +++ b/intern/cycles/integrator/render_scheduler.cpp @@ -88,6 +88,16 @@ int RenderScheduler::get_num_samples() const return num_samples_; } +void RenderScheduler::set_sample_offset(int sample_offset) +{ + sample_offset_ = sample_offset; +} + +int RenderScheduler::get_sample_offset() const +{ + return sample_offset_; +} + void RenderScheduler::set_time_limit(double time_limit) { time_limit_ = time_limit; @@ -110,13 +120,15 @@ int RenderScheduler::get_num_rendered_samples() const return state_.num_rendered_samples; } -void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples) +void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples, int sample_offset) { buffer_params_ = buffer_params; update_start_resolution_divider(); set_num_samples(num_samples); + set_start_sample(sample_offset); + set_sample_offset(sample_offset); /* In background mode never do lower resolution render preview, as it is not really supported * by the software. */ @@ -171,7 +183,7 @@ void RenderScheduler::reset(const BufferParams &buffer_params, int num_samples) void RenderScheduler::reset_for_next_tile() { - reset(buffer_params_, num_samples_); + reset(buffer_params_, num_samples_, sample_offset_); } bool RenderScheduler::render_work_reschedule_on_converge(RenderWork &render_work) @@ -317,6 +329,7 @@ RenderWork RenderScheduler::get_render_work() render_work.path_trace.start_sample = get_start_sample_to_path_trace(); render_work.path_trace.num_samples = get_num_samples_to_path_trace(); + render_work.path_trace.sample_offset = get_sample_offset(); render_work.init_render_buffers = (render_work.path_trace.start_sample == get_start_sample()); @@ -835,7 +848,7 @@ int RenderScheduler::get_num_samples_to_path_trace() const * When time limit is not used the number of samples per render iteration is either increasing * or stays the same, so there is no need to clamp number of samples calculated for occupancy. */ - if (time_limit_ && state_.start_render_time) { + if (time_limit_ != 0.0 && state_.start_render_time != 0.0) { const double remaining_render_time = max( 0.0, time_limit_ - (time_dt() - state_.start_render_time)); const double time_per_sample_average = path_trace_time_.get_average(); diff --git a/intern/cycles/integrator/render_scheduler.h b/intern/cycles/integrator/render_scheduler.h index d7b7413ae31..28f563c46e3 100644 --- a/intern/cycles/integrator/render_scheduler.h +++ b/intern/cycles/integrator/render_scheduler.h @@ -39,6 +39,7 @@ class RenderWork { struct { int start_sample = 0; int num_samples = 0; + int sample_offset = 0; } path_trace; struct { @@ -125,6 +126,9 @@ class RenderScheduler { void set_num_samples(int num_samples); int get_num_samples() const; + void set_sample_offset(int sample_offset); + int get_sample_offset() const; + /* Time limit for the path tracing tasks, in minutes. * Zero disables the limit. */ void set_time_limit(double time_limit); @@ -150,7 +154,7 @@ class RenderScheduler { /* Reset scheduler, indicating that rendering will happen from scratch. * Resets current rendered state, as well as scheduling information. */ - void reset(const BufferParams &buffer_params, int num_samples); + void reset(const BufferParams &buffer_params, int num_samples, int sample_offset); /* Reset scheduler upon switching to a next tile. * Will keep the same number of samples and full-frame render parameters, but will reset progress @@ -419,6 +423,8 @@ class RenderScheduler { int start_sample_ = 0; int num_samples_ = 0; + int sample_offset_ = 0; + /* Limit in seconds for how long path tracing is allowed to happen. * Zero means no limit is applied. */ double time_limit_ = 0.0; diff --git a/intern/cycles/integrator/work_tile_scheduler.cpp b/intern/cycles/integrator/work_tile_scheduler.cpp index 2d1ac07db7f..d60f7149bf4 100644 --- a/intern/cycles/integrator/work_tile_scheduler.cpp +++ b/intern/cycles/integrator/work_tile_scheduler.cpp @@ -36,6 +36,7 @@ void WorkTileScheduler::set_max_num_path_states(int max_num_path_states) void WorkTileScheduler::reset(const BufferParams &buffer_params, int sample_start, int samples_num, + int sample_offset, float scrambling_distance) { /* Image buffer parameters. */ @@ -51,6 +52,7 @@ void WorkTileScheduler::reset(const BufferParams &buffer_params, /* Samples parameters. */ sample_start_ = sample_start; samples_num_ = samples_num; + sample_offset_ = sample_offset; /* Initialize new scheduling. */ reset_scheduler_state(); @@ -111,6 +113,7 @@ bool WorkTileScheduler::get_work(KernelWorkTile *work_tile_, const int max_work_ work_tile.h = tile_size_.height; work_tile.start_sample = sample_start_ + start_sample; work_tile.num_samples = min(tile_size_.num_samples, samples_num_ - start_sample); + work_tile.sample_offset = sample_offset_; work_tile.offset = offset_; work_tile.stride = stride_; diff --git a/intern/cycles/integrator/work_tile_scheduler.h b/intern/cycles/integrator/work_tile_scheduler.h index d9fa7e84431..2d6395799f7 100644 --- a/intern/cycles/integrator/work_tile_scheduler.h +++ b/intern/cycles/integrator/work_tile_scheduler.h @@ -41,6 +41,7 @@ class WorkTileScheduler { void reset(const BufferParams &buffer_params, int sample_start, int samples_num, + int sample_offset, float scrambling_distance); /* Get work for a device. @@ -79,6 +80,7 @@ class WorkTileScheduler { * (splitting into a smaller work tiles). */ int sample_start_ = 0; int samples_num_ = 0; + int sample_offset_ = 0; /* Tile size which be scheduled for rendering. */ TileSize tile_size_; diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 1a254f5eddc..d759399b04d 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -39,6 +39,10 @@ set(SRC_KERNEL_DEVICE_HIP device/hip/kernel.cpp ) +set(SRC_KERNEL_DEVICE_METAL + device/metal/kernel.metal +) + set(SRC_KERNEL_DEVICE_OPTIX device/optix/kernel.cu device/optix/kernel_shader_raytrace.cu @@ -79,6 +83,13 @@ set(SRC_KERNEL_DEVICE_OPTIX_HEADERS device/optix/globals.h ) +set(SRC_KERNEL_DEVICE_METAL_HEADERS + device/metal/compat.h + device/metal/context_begin.h + device/metal/context_end.h + device/metal/globals.h +) + set(SRC_KERNEL_CLOSURE_HEADERS closure/alloc.h closure/bsdf.h @@ -262,6 +273,7 @@ set(SRC_KERNEL_UTIL_HEADERS ) set(SRC_KERNEL_TYPES_HEADERS + tables.h textures.h types.h ) @@ -399,12 +411,8 @@ if(WITH_CYCLES_CUDA_BINARIES) -I ${CMAKE_CURRENT_SOURCE_DIR}/.. -I ${CMAKE_CURRENT_SOURCE_DIR}/device/cuda --use_fast_math - -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file}) - - if(${experimental}) - set(cuda_flags ${cuda_flags} -D __KERNEL_EXPERIMENTAL__) - set(name ${name}_experimental) - endif() + -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_file} + -Wno-deprecated-gpu-targets) if(WITH_NANOVDB) set(cuda_flags ${cuda_flags} @@ -412,6 +420,10 @@ if(WITH_CYCLES_CUDA_BINARIES) -I "${NANOVDB_INCLUDE_DIR}") endif() + if(WITH_CYCLES_DEBUG) + set(cuda_flags ${cuda_flags} -D WITH_CYCLES_DEBUG) + endif() + if(WITH_CYCLES_CUBIN_COMPILER) string(SUBSTRING ${arch} 3 -1 CUDA_ARCH) @@ -560,11 +572,6 @@ if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) -ffast-math -o ${CMAKE_CURRENT_BINARY_DIR}/${hip_file}) - if(${experimental}) - set(hip_flags ${hip_flags} -D __KERNEL_EXPERIMENTAL__) - set(name ${name}_experimental) - endif() - if(WITH_NANOVDB) set(hip_flags ${hip_flags} -D WITH_NANOVDB @@ -572,7 +579,7 @@ if(WITH_CYCLES_HIP_BINARIES AND WITH_CYCLES_DEVICE_HIP) endif() if(WITH_CYCLES_DEBUG) - set(hip_flags ${hip_flags} -D __KERNEL_DEBUG__) + set(hip_flags ${hip_flags} -D WITH_CYCLES_DEBUG) endif() add_custom_command( @@ -613,6 +620,10 @@ if(WITH_CYCLES_DEVICE_OPTIX AND WITH_CYCLES_CUDA_BINARIES) -I "${NANOVDB_INCLUDE_DIR}") endif() + if(WITH_CYCLES_DEBUG) + set(cuda_flags ${cuda_flags} -D WITH_CYCLES_DEBUG) + endif() + if(WITH_CYCLES_CUBIN_COMPILER) # Needed to find libnvrtc-builtins.so. Can't do it from inside # cycles_cubin_cc since the env variable is read before main() @@ -701,7 +712,7 @@ if(WITH_COMPILER_ASAN) string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-sanitize=all") string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-sanitize=vptr") elseif(CMAKE_C_COMPILER_ID MATCHES "Clang") - # With OSL, Cycles disables rtti in some modules, wich then breaks at linking + # With OSL, Cycles disables rtti in some modules, which then breaks at linking # when trying to use vptr sanitizer (included into 'undefined' general option). string(APPEND CMAKE_CXX_FLAGS_RELWITHDEBINFO " -fno-sanitize=vptr") string(APPEND CMAKE_CXX_FLAGS_DEBUG " -fno-sanitize=vptr") @@ -729,12 +740,14 @@ cycles_add_library(cycles_kernel "${LIB}" ${SRC_KERNEL_DEVICE_CUDA} ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_OPTIX} + ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_HEADERS} ${SRC_KERNEL_DEVICE_CPU_HEADERS} ${SRC_KERNEL_DEVICE_GPU_HEADERS} ${SRC_KERNEL_DEVICE_CUDA_HEADERS} ${SRC_KERNEL_DEVICE_HIP_HEADERS} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS} + ${SRC_KERNEL_DEVICE_METAL_HEADERS} ) source_group("bake" FILES ${SRC_KERNEL_BAKE_HEADERS}) @@ -746,6 +759,7 @@ source_group("device\\cuda" FILES ${SRC_KERNEL_DEVICE_CUDA} ${SRC_KERNEL_DEVICE_ source_group("device\\gpu" FILES ${SRC_KERNEL_DEVICE_GPU_HEADERS}) source_group("device\\hip" FILES ${SRC_KERNEL_DEVICE_HIP} ${SRC_KERNEL_DEVICE_HIP_HEADERS}) source_group("device\\optix" FILES ${SRC_KERNEL_DEVICE_OPTIX} ${SRC_KERNEL_DEVICE_OPTIX_HEADERS}) +source_group("device\\metal" FILES ${SRC_KERNEL_DEVICE_METAL} ${SRC_KERNEL_DEVICE_METAL_HEADERS}) source_group("film" FILES ${SRC_KERNEL_FILM_HEADERS}) source_group("geom" FILES ${SRC_KERNEL_GEOM_HEADERS}) source_group("integrator" FILES ${SRC_KERNEL_INTEGRATOR_HEADERS}) @@ -778,6 +792,8 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP}" ${CYCLES_ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_HIP_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/hip) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_OPTIX_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/optix) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_METAL}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_DEVICE_METAL_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/device/metal) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_FILM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/film) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/geom) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_KERNEL_INTEGRATOR_HEADERS}" ${CYCLES_INSTALL_PATH}/source/kernel/integrator) diff --git a/intern/cycles/kernel/bvh/util.h b/intern/cycles/kernel/bvh/util.h index 8686f887021..26ba136dd79 100644 --- a/intern/cycles/kernel/bvh/util.h +++ b/intern/cycles/kernel/bvh/util.h @@ -97,7 +97,7 @@ ccl_device_inline void sort_intersections_and_normals(ccl_private Intersection * swapped = false; for (int j = 0; j < num_hits - 1; ++j) { if (hits[j].t > hits[j + 1].t) { - struct Intersection tmp_hit = hits[j]; + Intersection tmp_hit = hits[j]; float3 tmp_Ng = Ng[j]; hits[j] = hits[j + 1]; Ng[j] = Ng[j + 1]; diff --git a/intern/cycles/kernel/device/cpu/globals.h b/intern/cycles/kernel/device/cpu/globals.h index dd0327b3f94..746e48b9880 100644 --- a/intern/cycles/kernel/device/cpu/globals.h +++ b/intern/cycles/kernel/device/cpu/globals.h @@ -18,6 +18,7 @@ #pragma once +#include "kernel/tables.h" #include "kernel/types.h" #include "kernel/util/profiling.h" diff --git a/intern/cycles/kernel/device/cuda/compat.h b/intern/cycles/kernel/device/cuda/compat.h index 1ee82e6eb7c..658dec102b1 100644 --- a/intern/cycles/kernel/device/cuda/compat.h +++ b/intern/cycles/kernel/device/cuda/compat.h @@ -52,8 +52,9 @@ typedef unsigned long long uint64_t; #endif #define ccl_device_noinline __device__ __noinline__ #define ccl_device_noinline_cpu ccl_device +#define ccl_device_inline_method ccl_device #define ccl_global -#define ccl_static_constant __constant__ +#define ccl_inline_constant __constant__ #define ccl_device_constant __constant__ __device__ #define ccl_constant const #define ccl_gpu_shared __shared__ @@ -75,6 +76,7 @@ typedef unsigned long long uint64_t; #define ccl_gpu_block_idx_x (blockIdx.x) #define ccl_gpu_grid_dim_x (gridDim.x) #define ccl_gpu_warp_size (warpSize) +#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) #define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x) #define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x) @@ -84,7 +86,6 @@ typedef unsigned long long uint64_t; #define ccl_gpu_syncthreads() __syncthreads() #define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate) #define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla) -#define ccl_gpu_popc(x) __popc(x) /* GPU texture objects */ diff --git a/intern/cycles/kernel/device/cuda/config.h b/intern/cycles/kernel/device/cuda/config.h index 46196dcdb51..003881d7912 100644 --- a/intern/cycles/kernel/device/cuda/config.h +++ b/intern/cycles/kernel/device/cuda/config.h @@ -92,12 +92,29 @@ /* Compute number of threads per block and minimum blocks per multiprocessor * given the maximum number of registers per thread. */ - #define ccl_gpu_kernel(block_num_threads, thread_num_registers) \ extern "C" __global__ void __launch_bounds__(block_num_threads, \ GPU_MULTIPRESSOR_MAX_REGISTERS / \ (block_num_threads * thread_num_registers)) +#define ccl_gpu_kernel_threads(block_num_threads) \ + extern "C" __global__ void __launch_bounds__(block_num_threads) + +#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__) + +#define ccl_gpu_kernel_call(x) x + +/* Define a function object where "func" is the lambda body, and additional parameters are used to + * specify captured state */ +#define ccl_gpu_kernel_lambda(func, ...) \ + struct KernelLambda { \ + __VA_ARGS__; \ + __device__ int operator()(const int state) \ + { \ + return (func); \ + } \ + } ccl_gpu_kernel_lambda_pass + /* sanity checks */ #if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS diff --git a/intern/cycles/kernel/device/gpu/image.h b/intern/cycles/kernel/device/gpu/image.h index 95a37c693ae..0900a45c83d 100644 --- a/intern/cycles/kernel/device/gpu/image.h +++ b/intern/cycles/kernel/device/gpu/image.h @@ -65,7 +65,9 @@ ccl_device float cubic_h1(float a) /* Fast bicubic texture lookup using 4 bilinear lookups, adapted from CUDA samples. */ template<typename T> -ccl_device_noinline T kernel_tex_image_interp_bicubic(const TextureInfo &info, float x, float y) +ccl_device_noinline T kernel_tex_image_interp_bicubic(ccl_global const TextureInfo &info, + float x, + float y) { ccl_gpu_tex_object tex = (ccl_gpu_tex_object)info.data; @@ -94,7 +96,7 @@ ccl_device_noinline T kernel_tex_image_interp_bicubic(const TextureInfo &info, f /* Fast tricubic texture lookup using 8 trilinear lookups. */ template<typename T> ccl_device_noinline T -kernel_tex_image_interp_tricubic(const TextureInfo &info, float x, float y, float z) +kernel_tex_image_interp_tricubic(ccl_global const TextureInfo &info, float x, float y, float z) { ccl_gpu_tex_object tex = (ccl_gpu_tex_object)info.data; @@ -169,7 +171,7 @@ ccl_device T kernel_tex_image_interp_tricubic_nanovdb(S &s, float x, float y, fl template<typename T> ccl_device_noinline T kernel_tex_image_interp_nanovdb( - const TextureInfo &info, float x, float y, float z, uint interpolation) + ccl_global const TextureInfo &info, float x, float y, float z, uint interpolation) { using namespace nanovdb; @@ -191,7 +193,7 @@ ccl_device_noinline T kernel_tex_image_interp_nanovdb( ccl_device float4 kernel_tex_image_interp(KernelGlobals kg, int id, float x, float y) { - const TextureInfo &info = kernel_tex_fetch(__texture_info, id); + ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id); /* float4, byte4, ushort4 and half4 */ const int texture_type = info.data_type; @@ -226,7 +228,7 @@ ccl_device float4 kernel_tex_image_interp_3d(KernelGlobals kg, float3 P, InterpolationType interp) { - const TextureInfo &info = kernel_tex_fetch(__texture_info, id); + ccl_global const TextureInfo &info = kernel_tex_fetch(__texture_info, id); if (info.use_transform_3d) { P = transform_point(&info.transform_3d, P); diff --git a/intern/cycles/kernel/device/gpu/kernel.h b/intern/cycles/kernel/device/gpu/kernel.h index 56fcc38b907..22e2a61a06d 100644 --- a/intern/cycles/kernel/device/gpu/kernel.h +++ b/intern/cycles/kernel/device/gpu/kernel.h @@ -21,6 +21,13 @@ #include "kernel/device/gpu/parallel_sorted_index.h" #include "kernel/device/gpu/work_stealing.h" +/* Include constant tables before entering Metal's context class scope (context_begin.h) */ +#include "kernel/tables.h" + +#ifdef __KERNEL_METAL__ +# include "kernel/device/metal/context_begin.h" +#endif + #include "kernel/integrator/state.h" #include "kernel/integrator/state_flow.h" #include "kernel/integrator/state_util.h" @@ -40,6 +47,11 @@ #include "kernel/bake/bake.h" #include "kernel/film/adaptive_sampling.h" + +#ifdef __KERNEL_METAL__ +# include "kernel/device/metal/context_end.h" +#endif + #include "kernel/film/read.h" /* -------------------------------------------------------------------- @@ -47,7 +59,7 @@ */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_reset(int num_states) + ccl_gpu_kernel_signature(integrator_reset, int num_states) { const int state = ccl_gpu_global_id_x(); @@ -58,10 +70,11 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_init_from_camera(KernelWorkTile *tiles, - const int num_tiles, - float *render_buffer, - const int max_tile_work_size) + ccl_gpu_kernel_signature(integrator_init_from_camera, + ccl_global KernelWorkTile *tiles, + const int num_tiles, + ccl_global float *render_buffer, + const int max_tile_work_size) { const int work_index = ccl_gpu_global_id_x(); @@ -72,7 +85,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) const int tile_index = work_index / max_tile_work_size; const int tile_work_index = work_index - tile_index * max_tile_work_size; - const KernelWorkTile *tile = &tiles[tile_index]; + ccl_global const KernelWorkTile *tile = &tiles[tile_index]; if (tile_work_index >= tile->work_size) { return; @@ -83,14 +96,16 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) uint x, y, sample; get_work_pixel(tile, tile_work_index, &x, &y, &sample); - integrator_init_from_camera(nullptr, state, tile, render_buffer, x, y, sample); + ccl_gpu_kernel_call( + integrator_init_from_camera(nullptr, state, tile, render_buffer, x, y, sample)); } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_init_from_bake(KernelWorkTile *tiles, - const int num_tiles, - float *render_buffer, - const int max_tile_work_size) + ccl_gpu_kernel_signature(integrator_init_from_bake, + ccl_global KernelWorkTile *tiles, + const int num_tiles, + ccl_global float *render_buffer, + const int max_tile_work_size) { const int work_index = ccl_gpu_global_id_x(); @@ -101,7 +116,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) const int tile_index = work_index / max_tile_work_size; const int tile_work_index = work_index - tile_index * max_tile_work_size; - const KernelWorkTile *tile = &tiles[tile_index]; + ccl_global const KernelWorkTile *tile = &tiles[tile_index]; if (tile_work_index >= tile->work_size) { return; @@ -112,230 +127,264 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) uint x, y, sample; get_work_pixel(tile, tile_work_index, &x, &y, &sample); - integrator_init_from_bake(nullptr, state, tile, render_buffer, x, y, sample); + ccl_gpu_kernel_call( + integrator_init_from_bake(nullptr, state, tile, render_buffer, x, y, sample)); } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_intersect_closest(const int *path_index_array, - ccl_global float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_intersect_closest, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_intersect_closest(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_intersect_closest(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_intersect_shadow(const int *path_index_array, const int work_size) + ccl_gpu_kernel_signature(integrator_intersect_shadow, + ccl_global const int *path_index_array, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_intersect_shadow(NULL, state); + ccl_gpu_kernel_call(integrator_intersect_shadow(NULL, state)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_intersect_subsurface(const int *path_index_array, const int work_size) + ccl_gpu_kernel_signature(integrator_intersect_subsurface, + ccl_global const int *path_index_array, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_intersect_subsurface(NULL, state); + ccl_gpu_kernel_call(integrator_intersect_subsurface(NULL, state)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_intersect_volume_stack(const int *path_index_array, const int work_size) + ccl_gpu_kernel_signature(integrator_intersect_volume_stack, + ccl_global const int *path_index_array, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_intersect_volume_stack(NULL, state); + ccl_gpu_kernel_call(integrator_intersect_volume_stack(NULL, state)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_background(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_background, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_background(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_background(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_light(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_light, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_light(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_light(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_shadow(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_shadow, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_shadow(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_shadow(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_surface(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_surface, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_surface(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_surface(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_surface_raytrace(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_surface_raytrace, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_surface_raytrace(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_surface_raytrace(NULL, state, render_buffer)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shade_volume(const int *path_index_array, - float *render_buffer, - const int work_size) + ccl_gpu_kernel_signature(integrator_shade_volume, + ccl_global const int *path_index_array, + ccl_global float *render_buffer, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); if (global_index < work_size) { const int state = (path_index_array) ? path_index_array[global_index] : global_index; - integrator_shade_volume(NULL, state, render_buffer); + ccl_gpu_kernel_call(integrator_shade_volume(NULL, state, render_buffer)); } } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_queued_paths_array(int num_states, - int *indices, - int *num_indices, - int kernel) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_queued_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int kernel_index) { + ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) == kernel_index, + int kernel_index); + ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index; + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices, num_indices, [kernel](const int state) { - return (INTEGRATOR_STATE(state, path, queued_kernel) == kernel); - }); + num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_queued_shadow_paths_array(int num_states, - int *indices, - int *num_indices, - int kernel) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_queued_shadow_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int kernel_index) { + ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, shadow_path, queued_kernel) == kernel_index, + int kernel_index); + ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index; + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices, num_indices, [kernel](const int state) { - return (INTEGRATOR_STATE(state, shadow_path, queued_kernel) == kernel); - }); + num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_active_paths_array(int num_states, int *indices, int *num_indices) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_active_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices) { + ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) != 0); + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices, num_indices, [](const int state) { - return (INTEGRATOR_STATE(state, path, queued_kernel) != 0); - }); + num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_terminated_paths_array(int num_states, - int *indices, - int *num_indices, - int indices_offset) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_terminated_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int indices_offset) { + ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, path, queued_kernel) == 0); + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices + indices_offset, num_indices, [](const int state) { - return (INTEGRATOR_STATE(state, path, queued_kernel) == 0); - }); + num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_terminated_shadow_paths_array(int num_states, - int *indices, - int *num_indices, - int indices_offset) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_terminated_shadow_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int indices_offset) { + ccl_gpu_kernel_lambda(INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0); + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices + indices_offset, num_indices, [](const int state) { - return (INTEGRATOR_STATE(state, shadow_path, queued_kernel) == 0); - }); -} - -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_sorted_paths_array(int num_states, - int num_states_limit, - int *indices, - int *num_indices, - int *key_counter, - int *key_prefix_sum, - int kernel) -{ - gpu_parallel_sorted_index_array<GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, - num_states_limit, - indices, - num_indices, - key_counter, - key_prefix_sum, - [kernel](const int state) { - return (INTEGRATOR_STATE(state, path, queued_kernel) == kernel) ? - INTEGRATOR_STATE(state, path, shader_sort_key) : - GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY; - }); -} - -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_compact_paths_array(int num_states, - int *indices, - int *num_indices, - int num_active_paths) -{ + num_states, indices + indices_offset, num_indices, ccl_gpu_kernel_lambda_pass); +} + +ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_sorted_paths_array, + int num_states, + int num_states_limit, + ccl_global int *indices, + ccl_global int *num_indices, + ccl_global int *key_counter, + ccl_global int *key_prefix_sum, + int kernel_index) +{ + ccl_gpu_kernel_lambda((INTEGRATOR_STATE(state, path, queued_kernel) == kernel_index) ? + INTEGRATOR_STATE(state, path, shader_sort_key) : + GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY, + int kernel_index); + ccl_gpu_kernel_lambda_pass.kernel_index = kernel_index; + + const uint state_index = ccl_gpu_global_id_x(); + gpu_parallel_sorted_index_array(state_index, + num_states, + num_states_limit, + indices, + num_indices, + key_counter, + key_prefix_sum, + ccl_gpu_kernel_lambda_pass); +} + +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_compact_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int num_active_paths) +{ + ccl_gpu_kernel_lambda((state >= num_active_paths) && + (INTEGRATOR_STATE(state, path, queued_kernel) != 0), + int num_active_paths); + ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths; + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices, num_indices, [num_active_paths](const int state) { - return (state >= num_active_paths) && (INTEGRATOR_STATE(state, path, queued_kernel) != 0); - }); + num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_compact_states(const int *active_terminated_states, - const int active_states_offset, - const int terminated_states_offset, - const int work_size) +ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_compact_states, + ccl_global const int *active_terminated_states, + const int active_states_offset, + const int terminated_states_offset, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); @@ -343,28 +392,32 @@ extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_B const int from_state = active_terminated_states[active_states_offset + global_index]; const int to_state = active_terminated_states[terminated_states_offset + global_index]; - integrator_state_move(NULL, to_state, from_state); + ccl_gpu_kernel_call(integrator_state_move(NULL, to_state, from_state)); } } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_compact_shadow_paths_array(int num_states, - int *indices, - int *num_indices, - int num_active_paths) +ccl_gpu_kernel_threads(GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_compact_shadow_paths_array, + int num_states, + ccl_global int *indices, + ccl_global int *num_indices, + int num_active_paths) { + ccl_gpu_kernel_lambda((state >= num_active_paths) && + (INTEGRATOR_STATE(state, shadow_path, queued_kernel) != 0), + int num_active_paths); + ccl_gpu_kernel_lambda_pass.num_active_paths = num_active_paths; + gpu_parallel_active_index_array<GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE>( - num_states, indices, num_indices, [num_active_paths](const int state) { - return (state >= num_active_paths) && - (INTEGRATOR_STATE(state, shadow_path, queued_kernel) != 0); - }); + num_states, indices, num_indices, ccl_gpu_kernel_lambda_pass); } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) - kernel_gpu_integrator_compact_shadow_states(const int *active_terminated_states, - const int active_states_offset, - const int terminated_states_offset, - const int work_size) +ccl_gpu_kernel_threads(GPU_PARALLEL_SORTED_INDEX_DEFAULT_BLOCK_SIZE) + ccl_gpu_kernel_signature(integrator_compact_shadow_states, + ccl_global const int *active_terminated_states, + const int active_states_offset, + const int terminated_states_offset, + const int work_size) { const int global_index = ccl_gpu_global_id_x(); @@ -372,15 +425,14 @@ extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_SORTED_INDEX_DEFAULT_B const int from_state = active_terminated_states[active_states_offset + global_index]; const int to_state = active_terminated_states[terminated_states_offset + global_index]; - integrator_shadow_state_move(NULL, to_state, from_state); + ccl_gpu_kernel_call(integrator_shadow_state_move(NULL, to_state, from_state)); } } -extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE) - kernel_gpu_prefix_sum(int *counter, int *prefix_sum, int num_values) +ccl_gpu_kernel_threads(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE) ccl_gpu_kernel_signature( + prefix_sum, ccl_global int *counter, ccl_global int *prefix_sum, int num_values) { - gpu_parallel_prefix_sum<GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE>( - counter, prefix_sum, num_values); + gpu_parallel_prefix_sum(ccl_gpu_global_id_x(), counter, prefix_sum, num_values); } /* -------------------------------------------------------------------- @@ -388,16 +440,17 @@ extern "C" __global__ void __launch_bounds__(GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLO */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_adaptive_sampling_convergence_check(float *render_buffer, - int sx, - int sy, - int sw, - int sh, - float threshold, - bool reset, - int offset, - int stride, - uint *num_active_pixels) + ccl_gpu_kernel_signature(adaptive_sampling_convergence_check, + ccl_global float *render_buffer, + int sx, + int sy, + int sw, + int sh, + float threshold, + bool reset, + int offset, + int stride, + ccl_global uint *num_active_pixels) { const int work_index = ccl_gpu_global_id_x(); const int y = work_index / sw; @@ -406,37 +459,51 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) bool converged = true; if (x < sw && y < sh) { - converged = kernel_adaptive_sampling_convergence_check( - nullptr, render_buffer, sx + x, sy + y, threshold, reset, offset, stride); + converged = ccl_gpu_kernel_call(kernel_adaptive_sampling_convergence_check( + nullptr, render_buffer, sx + x, sy + y, threshold, reset, offset, stride)); } /* NOTE: All threads specified in the mask must execute the intrinsic. */ - const uint num_active_pixels_mask = ccl_gpu_ballot(!converged); + const auto num_active_pixels_mask = ccl_gpu_ballot(!converged); const int lane_id = ccl_gpu_thread_idx_x % ccl_gpu_warp_size; if (lane_id == 0) { - atomic_fetch_and_add_uint32(num_active_pixels, __popc(num_active_pixels_mask)); + atomic_fetch_and_add_uint32(num_active_pixels, popcount(num_active_pixels_mask)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_adaptive_sampling_filter_x( - float *render_buffer, int sx, int sy, int sw, int sh, int offset, int stride) + ccl_gpu_kernel_signature(adaptive_sampling_filter_x, + ccl_global float *render_buffer, + int sx, + int sy, + int sw, + int sh, + int offset, + int stride) { const int y = ccl_gpu_global_id_x(); if (y < sh) { - kernel_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride); + ccl_gpu_kernel_call( + kernel_adaptive_sampling_filter_x(NULL, render_buffer, sy + y, sx, sw, offset, stride)); } } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_adaptive_sampling_filter_y( - float *render_buffer, int sx, int sy, int sw, int sh, int offset, int stride) + ccl_gpu_kernel_signature(adaptive_sampling_filter_y, + ccl_global float *render_buffer, + int sx, + int sy, + int sw, + int sh, + int offset, + int stride) { const int x = ccl_gpu_global_id_x(); if (x < sw) { - kernel_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride); + ccl_gpu_kernel_call( + kernel_adaptive_sampling_filter_y(NULL, render_buffer, sx + x, sy, sh, offset, stride)); } } @@ -445,12 +512,14 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_cryptomatte_postprocess(float *render_buffer, int num_pixels) + ccl_gpu_kernel_signature(cryptomatte_postprocess, + ccl_global float *render_buffer, + int num_pixels) { const int pixel_index = ccl_gpu_global_id_x(); if (pixel_index < num_pixels) { - kernel_cryptomatte_post(nullptr, render_buffer, pixel_index); + ccl_gpu_kernel_call(kernel_cryptomatte_post(nullptr, render_buffer, pixel_index)); } } @@ -458,36 +527,6 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) * Film. */ -/* Common implementation for float destination. */ -template<typename Processor> -ccl_device_inline void kernel_gpu_film_convert_common(const KernelFilmConvert *kfilm_convert, - float *pixels, - float *render_buffer, - int num_pixels, - int width, - int offset, - int stride, - int dst_offset, - int dst_stride, - const Processor &processor) -{ - const int render_pixel_index = ccl_gpu_global_id_x(); - if (render_pixel_index >= num_pixels) { - return; - } - - const int x = render_pixel_index % width; - const int y = render_pixel_index / width; - - ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert->pass_stride + - y * stride * kfilm_convert->pass_stride; - - ccl_global float *pixel = pixels + - (render_pixel_index + dst_offset) * kfilm_convert->pixel_stride; - - processor(kfilm_convert, buffer, pixel); -} - ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgba, const int rgba_offset, const int rgba_stride, @@ -508,177 +547,95 @@ ccl_device_inline void kernel_gpu_film_convert_half_write(ccl_global uchar4 *rgb #endif } -/* Common implementation for half4 destination and 4-channel input pass. */ -template<typename Processor> -ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_rgba( - const KernelFilmConvert *kfilm_convert, - uchar4 *rgba, - float *render_buffer, - int num_pixels, - int width, - int offset, - int stride, - int rgba_offset, - int rgba_stride, - const Processor &processor) -{ - const int render_pixel_index = ccl_gpu_global_id_x(); - if (render_pixel_index >= num_pixels) { - return; - } - - const int x = render_pixel_index % width; - const int y = render_pixel_index / width; - - ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert->pass_stride + - y * stride * kfilm_convert->pass_stride; - - float pixel[4]; - processor(kfilm_convert, buffer, pixel); - - film_apply_pass_pixel_overlays_rgba(kfilm_convert, buffer, pixel); - - const half4 half_pixel = float4_to_half4_display( - make_float4(pixel[0], pixel[1], pixel[2], pixel[3])); - kernel_gpu_film_convert_half_write(rgba, rgba_offset, rgba_stride, x, y, half_pixel); -} - -/* Common implementation for half4 destination and 3-channel input pass. */ -template<typename Processor> -ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_rgb( - const KernelFilmConvert *kfilm_convert, - uchar4 *rgba, - float *render_buffer, - int num_pixels, - int width, - int offset, - int stride, - int rgba_offset, - int rgba_stride, - const Processor &processor) -{ - kernel_gpu_film_convert_half_rgba_common_rgba( - kfilm_convert, - rgba, - render_buffer, - num_pixels, - width, - offset, - stride, - rgba_offset, - rgba_stride, - [&processor](const KernelFilmConvert *kfilm_convert, - ccl_global const float *buffer, - float *pixel_rgba) { - processor(kfilm_convert, buffer, pixel_rgba); - pixel_rgba[3] = 1.0f; - }); -} - -/* Common implementation for half4 destination and single channel input pass. */ -template<typename Processor> -ccl_device_inline void kernel_gpu_film_convert_half_rgba_common_value( - const KernelFilmConvert *kfilm_convert, - uchar4 *rgba, - float *render_buffer, - int num_pixels, - int width, - int offset, - int stride, - int rgba_offset, - int rgba_stride, - const Processor &processor) -{ - kernel_gpu_film_convert_half_rgba_common_rgba( - kfilm_convert, - rgba, - render_buffer, - num_pixels, - width, - offset, - stride, - rgba_offset, - rgba_stride, - [&processor](const KernelFilmConvert *kfilm_convert, - ccl_global const float *buffer, - float *pixel_rgba) { - float value; - processor(kfilm_convert, buffer, &value); - - pixel_rgba[0] = value; - pixel_rgba[1] = value; - pixel_rgba[2] = value; - pixel_rgba[3] = 1.0f; - }); -} - -#define KERNEL_FILM_CONVERT_PROC(name) \ - ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) name - -#define KERNEL_FILM_CONVERT_DEFINE(variant, channels) \ - KERNEL_FILM_CONVERT_PROC(kernel_gpu_film_convert_##variant) \ - (const KernelFilmConvert kfilm_convert, \ - float *pixels, \ - float *render_buffer, \ - int num_pixels, \ - int width, \ - int offset, \ - int stride, \ - int rgba_offset, \ - int rgba_stride) \ +#define KERNEL_FILM_CONVERT_VARIANT(variant, input_channel_count) \ + ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \ + ccl_gpu_kernel_signature(film_convert_##variant, \ + const KernelFilmConvert kfilm_convert, \ + ccl_global float *pixels, \ + ccl_global float *render_buffer, \ + int num_pixels, \ + int width, \ + int offset, \ + int stride, \ + int rgba_offset, \ + int rgba_stride) \ { \ - kernel_gpu_film_convert_common(&kfilm_convert, \ - pixels, \ - render_buffer, \ - num_pixels, \ - width, \ - offset, \ - stride, \ - rgba_offset, \ - rgba_stride, \ - film_get_pass_pixel_##variant); \ + const int render_pixel_index = ccl_gpu_global_id_x(); \ + if (render_pixel_index >= num_pixels) { \ + return; \ + } \ +\ + const int x = render_pixel_index % width; \ + const int y = render_pixel_index / width; \ +\ + ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \ + y * stride * kfilm_convert.pass_stride; \ +\ + ccl_global float *pixel = pixels + \ + (render_pixel_index + rgba_offset) * kfilm_convert.pixel_stride; \ +\ + film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel); \ } \ - KERNEL_FILM_CONVERT_PROC(kernel_gpu_film_convert_##variant##_half_rgba) \ - (const KernelFilmConvert kfilm_convert, \ - uchar4 *rgba, \ - float *render_buffer, \ - int num_pixels, \ - int width, \ - int offset, \ - int stride, \ - int rgba_offset, \ - int rgba_stride) \ +\ + ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) \ + ccl_gpu_kernel_signature(film_convert_##variant##_half_rgba, \ + const KernelFilmConvert kfilm_convert, \ + ccl_global uchar4 *rgba, \ + ccl_global float *render_buffer, \ + int num_pixels, \ + int width, \ + int offset, \ + int stride, \ + int rgba_offset, \ + int rgba_stride) \ { \ - kernel_gpu_film_convert_half_rgba_common_##channels(&kfilm_convert, \ - rgba, \ - render_buffer, \ - num_pixels, \ - width, \ - offset, \ - stride, \ - rgba_offset, \ - rgba_stride, \ - film_get_pass_pixel_##variant); \ - } - -KERNEL_FILM_CONVERT_DEFINE(depth, value) -KERNEL_FILM_CONVERT_DEFINE(mist, value) -KERNEL_FILM_CONVERT_DEFINE(sample_count, value) -KERNEL_FILM_CONVERT_DEFINE(float, value) - -KERNEL_FILM_CONVERT_DEFINE(light_path, rgb) -KERNEL_FILM_CONVERT_DEFINE(float3, rgb) - -KERNEL_FILM_CONVERT_DEFINE(motion, rgba) -KERNEL_FILM_CONVERT_DEFINE(cryptomatte, rgba) -KERNEL_FILM_CONVERT_DEFINE(shadow_catcher, rgba) -KERNEL_FILM_CONVERT_DEFINE(shadow_catcher_matte_with_shadow, rgba) -KERNEL_FILM_CONVERT_DEFINE(combined, rgba) -KERNEL_FILM_CONVERT_DEFINE(float4, rgba) - -#undef KERNEL_FILM_CONVERT_DEFINE -#undef KERNEL_FILM_CONVERT_HALF_RGBA_DEFINE -#undef KERNEL_FILM_CONVERT_PROC + const int render_pixel_index = ccl_gpu_global_id_x(); \ + if (render_pixel_index >= num_pixels) { \ + return; \ + } \ +\ + const int x = render_pixel_index % width; \ + const int y = render_pixel_index / width; \ +\ + ccl_global const float *buffer = render_buffer + offset + x * kfilm_convert.pass_stride + \ + y * stride * kfilm_convert.pass_stride; \ +\ + float pixel[4]; \ + film_get_pass_pixel_##variant(&kfilm_convert, buffer, pixel); \ +\ + if (input_channel_count == 1) { \ + pixel[1] = pixel[2] = pixel[0]; \ + } \ + if (input_channel_count <= 3) { \ + pixel[3] = 1.0f; \ + } \ +\ + film_apply_pass_pixel_overlays_rgba(&kfilm_convert, buffer, pixel); \ +\ + const half4 half_pixel = float4_to_half4_display( \ + make_float4(pixel[0], pixel[1], pixel[2], pixel[3])); \ + kernel_gpu_film_convert_half_write(rgba, rgba_offset, rgba_stride, x, y, half_pixel); \ + } + +/* 1 channel inputs */ +KERNEL_FILM_CONVERT_VARIANT(depth, 1) +KERNEL_FILM_CONVERT_VARIANT(mist, 1) +KERNEL_FILM_CONVERT_VARIANT(sample_count, 1) +KERNEL_FILM_CONVERT_VARIANT(float, 1) + +/* 3 channel inputs */ +KERNEL_FILM_CONVERT_VARIANT(light_path, 3) +KERNEL_FILM_CONVERT_VARIANT(float3, 3) + +/* 4 channel inputs */ +KERNEL_FILM_CONVERT_VARIANT(motion, 4) +KERNEL_FILM_CONVERT_VARIANT(cryptomatte, 4) +KERNEL_FILM_CONVERT_VARIANT(shadow_catcher, 4) +KERNEL_FILM_CONVERT_VARIANT(shadow_catcher_matte_with_shadow, 4) +KERNEL_FILM_CONVERT_VARIANT(combined, 4) +KERNEL_FILM_CONVERT_VARIANT(float4, 4) + +#undef KERNEL_FILM_CONVERT_VARIANT /* -------------------------------------------------------------------- * Shader evaluation. @@ -687,42 +644,46 @@ KERNEL_FILM_CONVERT_DEFINE(float4, rgba) /* Displacement */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_shader_eval_displace(KernelShaderEvalInput *input, - float *output, - const int offset, - const int work_size) + ccl_gpu_kernel_signature(shader_eval_displace, + ccl_global KernelShaderEvalInput *input, + ccl_global float *output, + const int offset, + const int work_size) { int i = ccl_gpu_global_id_x(); if (i < work_size) { - kernel_displace_evaluate(NULL, input, output, offset + i); + ccl_gpu_kernel_call(kernel_displace_evaluate(NULL, input, output, offset + i)); } } /* Background */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_shader_eval_background(KernelShaderEvalInput *input, - float *output, - const int offset, - const int work_size) + ccl_gpu_kernel_signature(shader_eval_background, + ccl_global KernelShaderEvalInput *input, + ccl_global float *output, + const int offset, + const int work_size) { int i = ccl_gpu_global_id_x(); if (i < work_size) { - kernel_background_evaluate(NULL, input, output, offset + i); + ccl_gpu_kernel_call(kernel_background_evaluate(NULL, input, output, offset + i)); } } /* Curve Shadow Transparency */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_shader_eval_curve_shadow_transparency(KernelShaderEvalInput *input, - float *output, - const int offset, - const int work_size) + ccl_gpu_kernel_signature(shader_eval_curve_shadow_transparency, + ccl_global KernelShaderEvalInput *input, + ccl_global float *output, + const int offset, + const int work_size) { int i = ccl_gpu_global_id_x(); if (i < work_size) { - kernel_curve_shadow_transparency_evaluate(NULL, input, output, offset + i); + ccl_gpu_kernel_call( + kernel_curve_shadow_transparency_evaluate(NULL, input, output, offset + i)); } } @@ -731,15 +692,16 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_filter_color_preprocess(float *render_buffer, - int full_x, - int full_y, - int width, - int height, - int offset, - int stride, - int pass_stride, - int pass_denoised) + ccl_gpu_kernel_signature(filter_color_preprocess, + ccl_global float *render_buffer, + int full_x, + int full_y, + int width, + int height, + int offset, + int stride, + int pass_stride, + int pass_denoised) { const int work_index = ccl_gpu_global_id_x(); const int y = work_index / width; @@ -750,31 +712,32 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } const uint64_t render_pixel_index = offset + (x + full_x) + (y + full_y) * stride; - float *buffer = render_buffer + render_pixel_index * pass_stride; + ccl_global float *buffer = render_buffer + render_pixel_index * pass_stride; - float *color_out = buffer + pass_denoised; + ccl_global float *color_out = buffer + pass_denoised; color_out[0] = clamp(color_out[0], 0.0f, 10000.0f); color_out[1] = clamp(color_out[1], 0.0f, 10000.0f); color_out[2] = clamp(color_out[2], 0.0f, 10000.0f); } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_filter_guiding_preprocess(float *guiding_buffer, - int guiding_pass_stride, - int guiding_pass_albedo, - int guiding_pass_normal, - const float *render_buffer, - int render_offset, - int render_stride, - int render_pass_stride, - int render_pass_sample_count, - int render_pass_denoising_albedo, - int render_pass_denoising_normal, - int full_x, - int full_y, - int width, - int height, - int num_samples) + ccl_gpu_kernel_signature(filter_guiding_preprocess, + ccl_global float *guiding_buffer, + int guiding_pass_stride, + int guiding_pass_albedo, + int guiding_pass_normal, + ccl_global const float *render_buffer, + int render_offset, + int render_stride, + int render_pass_stride, + int render_pass_sample_count, + int render_pass_denoising_albedo, + int render_pass_denoising_normal, + int full_x, + int full_y, + int width, + int height, + int num_samples) { const int work_index = ccl_gpu_global_id_x(); const int y = work_index / width; @@ -785,10 +748,10 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } const uint64_t guiding_pixel_index = x + y * width; - float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride; + ccl_global float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride; const uint64_t render_pixel_index = render_offset + (x + full_x) + (y + full_y) * render_stride; - const float *buffer = render_buffer + render_pixel_index * render_pass_stride; + ccl_global const float *buffer = render_buffer + render_pixel_index * render_pass_stride; float pixel_scale; if (render_pass_sample_count == PASS_UNUSED) { @@ -802,8 +765,8 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) if (guiding_pass_albedo != PASS_UNUSED) { kernel_assert(render_pass_denoising_albedo != PASS_UNUSED); - const float *aledo_in = buffer + render_pass_denoising_albedo; - float *albedo_out = guiding_pixel + guiding_pass_albedo; + ccl_global const float *aledo_in = buffer + render_pass_denoising_albedo; + ccl_global float *albedo_out = guiding_pixel + guiding_pass_albedo; albedo_out[0] = aledo_in[0] * pixel_scale; albedo_out[1] = aledo_in[1] * pixel_scale; @@ -814,8 +777,8 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) if (guiding_pass_normal != PASS_UNUSED) { kernel_assert(render_pass_denoising_normal != PASS_UNUSED); - const float *normal_in = buffer + render_pass_denoising_normal; - float *normal_out = guiding_pixel + guiding_pass_normal; + ccl_global const float *normal_in = buffer + render_pass_denoising_normal; + ccl_global float *normal_out = guiding_pixel + guiding_pass_normal; normal_out[0] = normal_in[0] * pixel_scale; normal_out[1] = normal_in[1] * pixel_scale; @@ -824,11 +787,12 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_filter_guiding_set_fake_albedo(float *guiding_buffer, - int guiding_pass_stride, - int guiding_pass_albedo, - int width, - int height) + ccl_gpu_kernel_signature(filter_guiding_set_fake_albedo, + ccl_global float *guiding_buffer, + int guiding_pass_stride, + int guiding_pass_albedo, + int width, + int height) { kernel_assert(guiding_pass_albedo != PASS_UNUSED); @@ -841,9 +805,9 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } const uint64_t guiding_pixel_index = x + y * width; - float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride; + ccl_global float *guiding_pixel = guiding_buffer + guiding_pixel_index * guiding_pass_stride; - float *albedo_out = guiding_pixel + guiding_pass_albedo; + ccl_global float *albedo_out = guiding_pixel + guiding_pass_albedo; albedo_out[0] = 0.5f; albedo_out[1] = 0.5f; @@ -851,20 +815,21 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_filter_color_postprocess(float *render_buffer, - int full_x, - int full_y, - int width, - int height, - int offset, - int stride, - int pass_stride, - int num_samples, - int pass_noisy, - int pass_denoised, - int pass_sample_count, - int num_components, - bool use_compositing) + ccl_gpu_kernel_signature(filter_color_postprocess, + ccl_global float *render_buffer, + int full_x, + int full_y, + int width, + int height, + int offset, + int stride, + int pass_stride, + int num_samples, + int pass_noisy, + int pass_denoised, + int pass_sample_count, + int num_components, + bool use_compositing) { const int work_index = ccl_gpu_global_id_x(); const int y = work_index / width; @@ -875,7 +840,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) } const uint64_t render_pixel_index = offset + (x + full_x) + (y + full_y) * stride; - float *buffer = render_buffer + render_pixel_index * pass_stride; + ccl_global float *buffer = render_buffer + render_pixel_index * pass_stride; float pixel_scale; if (pass_sample_count == PASS_UNUSED) { @@ -885,7 +850,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) pixel_scale = __float_as_uint(buffer[pass_sample_count]); } - float *denoised_pixel = buffer + pass_denoised; + ccl_global float *denoised_pixel = buffer + pass_denoised; denoised_pixel[0] *= pixel_scale; denoised_pixel[1] *= pixel_scale; @@ -898,7 +863,7 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) /* Currently compositing passes are either 3-component (derived by dividing light passes) * or do not have transparency (shadow catcher). Implicitly rely on this logic, as it * simplifies logic and avoids extra memory allocation. */ - const float *noisy_pixel = buffer + pass_noisy; + ccl_global const float *noisy_pixel = buffer + pass_noisy; denoised_pixel[3] = noisy_pixel[3]; } else { @@ -914,21 +879,22 @@ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) */ ccl_gpu_kernel(GPU_KERNEL_BLOCK_NUM_THREADS, GPU_KERNEL_MAX_REGISTERS) - kernel_gpu_integrator_shadow_catcher_count_possible_splits(int num_states, - uint *num_possible_splits) + ccl_gpu_kernel_signature(integrator_shadow_catcher_count_possible_splits, + int num_states, + ccl_global uint *num_possible_splits) { const int state = ccl_gpu_global_id_x(); bool can_split = false; if (state < num_states) { - can_split = kernel_shadow_catcher_path_can_split(nullptr, state); + can_split = ccl_gpu_kernel_call(kernel_shadow_catcher_path_can_split(nullptr, state)); } /* NOTE: All threads specified in the mask must execute the intrinsic. */ - const uint can_split_mask = ccl_gpu_ballot(can_split); + const auto can_split_mask = ccl_gpu_ballot(can_split); const int lane_id = ccl_gpu_thread_idx_x % ccl_gpu_warp_size; if (lane_id == 0) { - atomic_fetch_and_add_uint32(num_possible_splits, __popc(can_split_mask)); + atomic_fetch_and_add_uint32(num_possible_splits, popcount(can_split_mask)); } } diff --git a/intern/cycles/kernel/device/gpu/parallel_active_index.h b/intern/cycles/kernel/device/gpu/parallel_active_index.h index d7416beb783..a5320edcb3c 100644 --- a/intern/cycles/kernel/device/gpu/parallel_active_index.h +++ b/intern/cycles/kernel/device/gpu/parallel_active_index.h @@ -31,10 +31,43 @@ CCL_NAMESPACE_BEGIN # define GPU_PARALLEL_ACTIVE_INDEX_DEFAULT_BLOCK_SIZE 512 #endif +#ifdef __KERNEL_METAL__ +struct ActiveIndexContext { + ActiveIndexContext(int _thread_index, + int _global_index, + int _threadgroup_size, + int _simdgroup_size, + int _simd_lane_index, + int _simd_group_index, + int _num_simd_groups, + threadgroup int *_simdgroup_offset) + : thread_index(_thread_index), + global_index(_global_index), + blocksize(_threadgroup_size), + ccl_gpu_warp_size(_simdgroup_size), + thread_warp(_simd_lane_index), + warp_index(_simd_group_index), + num_warps(_num_simd_groups), + warp_offset(_simdgroup_offset) + { + } + + const int thread_index, global_index, blocksize, ccl_gpu_warp_size, thread_warp, warp_index, + num_warps; + threadgroup int *warp_offset; + + template<uint blocksizeDummy, typename IsActiveOp> + void active_index_array(const uint num_states, + ccl_global int *indices, + ccl_global int *num_indices, + IsActiveOp is_active_op) + { + const uint state_index = global_index; +#else template<uint blocksize, typename IsActiveOp> __device__ void gpu_parallel_active_index_array(const uint num_states, - int *indices, - int *num_indices, + ccl_global int *indices, + ccl_global int *num_indices, IsActiveOp is_active_op) { extern ccl_gpu_shared int warp_offset[]; @@ -45,43 +78,62 @@ __device__ void gpu_parallel_active_index_array(const uint num_states, const uint warp_index = thread_index / ccl_gpu_warp_size; const uint num_warps = blocksize / ccl_gpu_warp_size; - /* Test if state corresponding to this thread is active. */ const uint state_index = ccl_gpu_block_idx_x * blocksize + thread_index; - const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0; +#endif - /* For each thread within a warp compute how many other active states precede it. */ - const uint thread_mask = 0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp); - const uint thread_offset = ccl_gpu_popc(ccl_gpu_ballot(is_active) & thread_mask); + /* Test if state corresponding to this thread is active. */ + const uint is_active = (state_index < num_states) ? is_active_op(state_index) : 0; - /* Last thread in warp stores number of active states for each warp. */ - if (thread_warp == ccl_gpu_warp_size - 1) { - warp_offset[warp_index] = thread_offset + is_active; - } + /* For each thread within a warp compute how many other active states precede it. */ + const uint thread_offset = popcount(ccl_gpu_ballot(is_active) & + ccl_gpu_thread_mask(thread_warp)); - ccl_gpu_syncthreads(); - - /* Last thread in block converts per-warp sizes to offsets, increments global size of - * index array and gets offset to write to. */ - if (thread_index == blocksize - 1) { - /* TODO: parallelize this. */ - int offset = 0; - for (int i = 0; i < num_warps; i++) { - int num_active = warp_offset[i]; - warp_offset[i] = offset; - offset += num_active; + /* Last thread in warp stores number of active states for each warp. */ + if (thread_warp == ccl_gpu_warp_size - 1) { + warp_offset[warp_index] = thread_offset + is_active; } - const uint block_num_active = warp_offset[warp_index] + thread_offset + is_active; - warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active); - } + ccl_gpu_syncthreads(); + + /* Last thread in block converts per-warp sizes to offsets, increments global size of + * index array and gets offset to write to. */ + if (thread_index == blocksize - 1) { + /* TODO: parallelize this. */ + int offset = 0; + for (int i = 0; i < num_warps; i++) { + int num_active = warp_offset[i]; + warp_offset[i] = offset; + offset += num_active; + } + + const uint block_num_active = warp_offset[warp_index] + thread_offset + is_active; + warp_offset[num_warps] = atomic_fetch_and_add_uint32(num_indices, block_num_active); + } - ccl_gpu_syncthreads(); + ccl_gpu_syncthreads(); - /* Write to index array. */ - if (is_active) { - const uint block_offset = warp_offset[num_warps]; - indices[block_offset + warp_offset[warp_index] + thread_offset] = state_index; + /* Write to index array. */ + if (is_active) { + const uint block_offset = warp_offset[num_warps]; + indices[block_offset + warp_offset[warp_index] + thread_offset] = state_index; + } } -} + +#ifdef __KERNEL_METAL__ +}; /* end class ActiveIndexContext */ + +/* inject the required thread params into a struct, and redirect to its templated member function + */ +# define gpu_parallel_active_index_array \ + ActiveIndexContext(metal_local_id, \ + metal_global_id, \ + metal_local_size, \ + simdgroup_size, \ + simd_lane_index, \ + simd_group_index, \ + num_simd_groups, \ + simdgroup_offset) \ + .active_index_array +#endif CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h b/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h index 6de3a022569..4bd002c27e4 100644 --- a/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h +++ b/intern/cycles/kernel/device/gpu/parallel_prefix_sum.h @@ -33,10 +33,12 @@ CCL_NAMESPACE_BEGIN # define GPU_PARALLEL_PREFIX_SUM_DEFAULT_BLOCK_SIZE 512 #endif -template<uint blocksize> -__device__ void gpu_parallel_prefix_sum(int *counter, int *prefix_sum, const int num_values) +__device__ void gpu_parallel_prefix_sum(const int global_id, + ccl_global int *counter, + ccl_global int *prefix_sum, + const int num_values) { - if (!(ccl_gpu_block_idx_x == 0 && ccl_gpu_thread_idx_x == 0)) { + if (global_id != 0) { return; } diff --git a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h index c06d7be444f..c092e2a21ee 100644 --- a/intern/cycles/kernel/device/gpu/parallel_sorted_index.h +++ b/intern/cycles/kernel/device/gpu/parallel_sorted_index.h @@ -33,16 +33,16 @@ CCL_NAMESPACE_BEGIN #endif #define GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY (~0) -template<uint blocksize, typename GetKeyOp> -__device__ void gpu_parallel_sorted_index_array(const uint num_states, +template<typename GetKeyOp> +__device__ void gpu_parallel_sorted_index_array(const uint state_index, + const uint num_states, const int num_states_limit, - int *indices, - int *num_indices, - int *key_counter, - int *key_prefix_sum, + ccl_global int *indices, + ccl_global int *num_indices, + ccl_global int *key_counter, + ccl_global int *key_prefix_sum, GetKeyOp get_key_op) { - const uint state_index = ccl_gpu_block_idx_x * blocksize + ccl_gpu_thread_idx_x; const int key = (state_index < num_states) ? get_key_op(state_index) : GPU_PARALLEL_SORTED_INDEX_INACTIVE_KEY; diff --git a/intern/cycles/kernel/device/hip/compat.h b/intern/cycles/kernel/device/hip/compat.h index 282c3eca641..fff7a09e884 100644 --- a/intern/cycles/kernel/device/hip/compat.h +++ b/intern/cycles/kernel/device/hip/compat.h @@ -45,8 +45,9 @@ typedef unsigned long long uint64_t; #define ccl_device_forceinline __device__ __forceinline__ #define ccl_device_noinline __device__ __noinline__ #define ccl_device_noinline_cpu ccl_device +#define ccl_device_inline_method ccl_device #define ccl_global -#define ccl_static_constant __constant__ +#define ccl_inline_constant __constant__ #define ccl_device_constant __constant__ __device__ #define ccl_constant const #define ccl_gpu_shared __shared__ @@ -74,6 +75,7 @@ typedef unsigned long long uint64_t; #define ccl_gpu_block_idx_x (blockIdx.x) #define ccl_gpu_grid_dim_x (gridDim.x) #define ccl_gpu_warp_size (warpSize) +#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) #define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x) #define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x) @@ -83,7 +85,6 @@ typedef unsigned long long uint64_t; #define ccl_gpu_syncthreads() __syncthreads() #define ccl_gpu_ballot(predicate) __ballot(predicate) #define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down(var, detla) -#define ccl_gpu_popc(x) __popc(x) /* GPU texture objects */ typedef hipTextureObject_t ccl_gpu_tex_object; diff --git a/intern/cycles/kernel/device/hip/config.h b/intern/cycles/kernel/device/hip/config.h index 2fde0d46015..7ec744d8ad2 100644 --- a/intern/cycles/kernel/device/hip/config.h +++ b/intern/cycles/kernel/device/hip/config.h @@ -35,12 +35,29 @@ /* Compute number of threads per block and minimum blocks per multiprocessor * given the maximum number of registers per thread. */ - #define ccl_gpu_kernel(block_num_threads, thread_num_registers) \ extern "C" __global__ void __launch_bounds__(block_num_threads, \ GPU_MULTIPRESSOR_MAX_REGISTERS / \ (block_num_threads * thread_num_registers)) +#define ccl_gpu_kernel_threads(block_num_threads) \ + extern "C" __global__ void __launch_bounds__(block_num_threads) + +#define ccl_gpu_kernel_signature(name, ...) kernel_gpu_##name(__VA_ARGS__) + +#define ccl_gpu_kernel_call(x) x + +/* Define a function object where "func" is the lambda body, and additional parameters are used to + * specify captured state */ +#define ccl_gpu_kernel_lambda(func, ...) \ + struct KernelLambda { \ + __VA_ARGS__; \ + __device__ int operator()(const int state) \ + { \ + return (func); \ + } \ + } ccl_gpu_kernel_lambda_pass + /* sanity checks */ #if GPU_KERNEL_BLOCK_NUM_THREADS > GPU_BLOCK_MAX_THREADS diff --git a/intern/cycles/kernel/device/metal/compat.h b/intern/cycles/kernel/device/metal/compat.h index 77cea30914c..61597a4acfc 100644 --- a/intern/cycles/kernel/device/metal/compat.h +++ b/intern/cycles/kernel/device/metal/compat.h @@ -34,6 +34,7 @@ using namespace metal; #pragma clang diagnostic ignored "-Wunused-variable" #pragma clang diagnostic ignored "-Wsign-compare" +#pragma clang diagnostic ignored "-Wuninitialized" /* Qualifiers */ @@ -42,8 +43,9 @@ using namespace metal; #define ccl_device_forceinline ccl_device #define ccl_device_noinline ccl_device __attribute__((noinline)) #define ccl_device_noinline_cpu ccl_device +#define ccl_device_inline_method ccl_device #define ccl_global device -#define ccl_static_constant static constant constexpr +#define ccl_inline_constant static constant constexpr #define ccl_device_constant constant #define ccl_constant const device #define ccl_gpu_shared threadgroup @@ -58,6 +60,122 @@ using namespace metal; #define kernel_assert(cond) +#define ccl_gpu_global_id_x() metal_global_id +#define ccl_gpu_warp_size simdgroup_size +#define ccl_gpu_thread_idx_x simd_group_index +#define ccl_gpu_thread_mask(thread_warp) uint64_t((1ull << thread_warp) - 1) + +#define ccl_gpu_ballot(predicate) ((uint64_t)((simd_vote::vote_t)simd_ballot(predicate))) +#define ccl_gpu_syncthreads() threadgroup_barrier(mem_flags::mem_threadgroup); + +// clang-format off + +/* kernel.h adapters */ + +#define ccl_gpu_kernel(block_num_threads, thread_num_registers) +#define ccl_gpu_kernel_threads(block_num_threads) + +/* Convert a comma-separated list into a semicolon-separated list + * (so that we can generate a struct based on kernel entry-point parameters). */ +#define FN0() +#define FN1(p1) p1; +#define FN2(p1, p2) p1; p2; +#define FN3(p1, p2, p3) p1; p2; p3; +#define FN4(p1, p2, p3, p4) p1; p2; p3; p4; +#define FN5(p1, p2, p3, p4, p5) p1; p2; p3; p4; p5; +#define FN6(p1, p2, p3, p4, p5, p6) p1; p2; p3; p4; p5; p6; +#define FN7(p1, p2, p3, p4, p5, p6, p7) p1; p2; p3; p4; p5; p6; p7; +#define FN8(p1, p2, p3, p4, p5, p6, p7, p8) p1; p2; p3; p4; p5; p6; p7; p8; +#define FN9(p1, p2, p3, p4, p5, p6, p7, p8, p9) p1; p2; p3; p4; p5; p6; p7; p8; p9; +#define FN10(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; +#define FN11(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; +#define FN12(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; +#define FN13(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; +#define FN14(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; +#define FN15(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; +#define FN16(p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16) p1; p2; p3; p4; p5; p6; p7; p8; p9; p10; p11; p12; p13; p14; p15; p16; +#define GET_LAST_ARG(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15, p16, ...) p16 +#define PARAMS_MAKER(...) GET_LAST_ARG(__VA_ARGS__, FN16, FN15, FN14, FN13, FN12, FN11, FN10, FN9, FN8, FN7, FN6, FN5, FN4, FN3, FN2, FN1, FN0) + +/* Generate a struct containing the entry-point parameters and a "run" + * method which can access them implicitly via this-> */ +#define ccl_gpu_kernel_signature(name, ...) \ +struct kernel_gpu_##name \ +{ \ + PARAMS_MAKER(__VA_ARGS__)(__VA_ARGS__) \ + void run(thread MetalKernelContext& context, \ + threadgroup int *simdgroup_offset, \ + const uint metal_global_id, \ + const ushort metal_local_id, \ + const ushort metal_local_size, \ + uint simdgroup_size, \ + uint simd_lane_index, \ + uint simd_group_index, \ + uint num_simd_groups) ccl_global const; \ +}; \ +kernel void kernel_metal_##name(device const kernel_gpu_##name *params_struct, \ + constant KernelParamsMetal &ccl_restrict _launch_params_metal, \ + constant MetalAncillaries *_metal_ancillaries, \ + threadgroup int *simdgroup_offset[[ threadgroup(0) ]], \ + const uint metal_global_id [[thread_position_in_grid]], \ + const ushort metal_local_id [[thread_position_in_threadgroup]], \ + const ushort metal_local_size [[threads_per_threadgroup]], \ + uint simdgroup_size [[threads_per_simdgroup]], \ + uint simd_lane_index [[thread_index_in_simdgroup]], \ + uint simd_group_index [[simdgroup_index_in_threadgroup]], \ + uint num_simd_groups [[simdgroups_per_threadgroup]]) { \ + MetalKernelContext context(_launch_params_metal, _metal_ancillaries); \ + params_struct->run(context, simdgroup_offset, metal_global_id, metal_local_id, metal_local_size, simdgroup_size, simd_lane_index, simd_group_index, num_simd_groups); \ +} \ +void kernel_gpu_##name::run(thread MetalKernelContext& context, \ + threadgroup int *simdgroup_offset, \ + const uint metal_global_id, \ + const ushort metal_local_id, \ + const ushort metal_local_size, \ + uint simdgroup_size, \ + uint simd_lane_index, \ + uint simd_group_index, \ + uint num_simd_groups) ccl_global const + +#define ccl_gpu_kernel_call(x) context.x + +/* define a function object where "func" is the lambda body, and additional parameters are used to specify captured state */ +#define ccl_gpu_kernel_lambda(func, ...) \ + struct KernelLambda \ + { \ + KernelLambda(ccl_private MetalKernelContext &_context) : context(_context) {} \ + ccl_private MetalKernelContext &context; \ + __VA_ARGS__; \ + int operator()(const int state) const { return (func); } \ + } ccl_gpu_kernel_lambda_pass(context) + +// clang-format on + +/* volumetric lambda functions - use function objects for lambda-like functionality */ +#define VOLUME_READ_LAMBDA(function_call) \ + struct FnObjectRead { \ + KernelGlobals kg; \ + ccl_private MetalKernelContext *context; \ + int state; \ +\ + VolumeStack operator()(const int i) const \ + { \ + return context->function_call; \ + } \ + } volume_read_lambda_pass{kg, this, state}; + +#define VOLUME_WRITE_LAMBDA(function_call) \ + struct FnObjectWrite { \ + KernelGlobals kg; \ + ccl_private MetalKernelContext *context; \ + int state; \ +\ + void operator()(const int i, VolumeStack entry) const \ + { \ + context->function_call; \ + } \ + } volume_write_lambda_pass{kg, this, state}; + /* make_type definitions with Metal style element initializers */ #ifdef make_float2 # undef make_float2 @@ -112,6 +230,7 @@ using namespace metal; #define sinhf(x) sinh(float(x)) #define coshf(x) cosh(float(x)) #define tanhf(x) tanh(float(x)) +#define saturatef(x) saturate(float(x)) /* Use native functions with possibly lower precision for performance, * no issues found so far. */ @@ -124,3 +243,43 @@ using namespace metal; #define logf(x) trigmode::log(float(x)) #define NULL 0 + +#define __device__ + +/* texture bindings and sampler setup */ + +struct Texture2DParamsMetal { + texture2d<float, access::sample> tex; +}; +struct Texture3DParamsMetal { + texture3d<float, access::sample> tex; +}; + +struct MetalAncillaries { + device Texture2DParamsMetal *textures_2d; + device Texture3DParamsMetal *textures_3d; +}; + +#include "util/half.h" +#include "util/types.h" + +enum SamplerType { + SamplerFilterNearest_AddressRepeat, + SamplerFilterNearest_AddressClampEdge, + SamplerFilterNearest_AddressClampZero, + + SamplerFilterLinear_AddressRepeat, + SamplerFilterLinear_AddressClampEdge, + SamplerFilterLinear_AddressClampZero, + + SamplerCount +}; + +constant constexpr array<sampler, SamplerCount> metal_samplers = { + sampler(address::repeat, filter::nearest), + sampler(address::clamp_to_edge, filter::nearest), + sampler(address::clamp_to_zero, filter::nearest), + sampler(address::repeat, filter::linear), + sampler(address::clamp_to_edge, filter::linear), + sampler(address::clamp_to_zero, filter::linear), +}; diff --git a/intern/cycles/kernel/device/metal/context_begin.h b/intern/cycles/kernel/device/metal/context_begin.h new file mode 100644 index 00000000000..8c9e1c54077 --- /dev/null +++ b/intern/cycles/kernel/device/metal/context_begin.h @@ -0,0 +1,79 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// clang-format off + +/* Open the Metal kernel context class + * Necessary to access resource bindings */ +class MetalKernelContext { + public: + constant KernelParamsMetal &launch_params_metal; + constant MetalAncillaries *metal_ancillaries; + + MetalKernelContext(constant KernelParamsMetal &_launch_params_metal, constant MetalAncillaries * _metal_ancillaries) + : launch_params_metal(_launch_params_metal), metal_ancillaries(_metal_ancillaries) + {} + + /* texture fetch adapter functions */ + typedef uint64_t ccl_gpu_tex_object; + + template<typename T> + inline __attribute__((__always_inline__)) + T ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const { + kernel_assert(0); + return 0; + } + template<typename T> + inline __attribute__((__always_inline__)) + T ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const { + kernel_assert(0); + return 0; + } + + // texture2d + template<> + inline __attribute__((__always_inline__)) + float4 ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const { + const uint tid(tex); + const uint sid(tex >> 32); + return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)); + } + template<> + inline __attribute__((__always_inline__)) + float ccl_gpu_tex_object_read_2D(ccl_gpu_tex_object tex, float x, float y) const { + const uint tid(tex); + const uint sid(tex >> 32); + return metal_ancillaries->textures_2d[tid].tex.sample(metal_samplers[sid], float2(x, y)).x; + } + + // texture3d + template<> + inline __attribute__((__always_inline__)) + float4 ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const { + const uint tid(tex); + const uint sid(tex >> 32); + return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)); + } + template<> + inline __attribute__((__always_inline__)) + float ccl_gpu_tex_object_read_3D(ccl_gpu_tex_object tex, float x, float y, float z) const { + const uint tid(tex); + const uint sid(tex >> 32); + return metal_ancillaries->textures_3d[tid].tex.sample(metal_samplers[sid], float3(x, y, z)).x; + } +# include "kernel/device/gpu/image.h" + + // clang-format on diff --git a/intern/cycles/kernel/device/metal/context_end.h b/intern/cycles/kernel/device/metal/context_end.h new file mode 100644 index 00000000000..e700f294440 --- /dev/null +++ b/intern/cycles/kernel/device/metal/context_end.h @@ -0,0 +1,23 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +} +; /* end of MetalKernelContext class definition */ + +/* Silently redirect into the MetalKernelContext instance */ +/* NOTE: These macros will need maintaining as entry-points change. */ + +#undef kernel_integrator_state +#define kernel_integrator_state context.launch_params_metal.__integrator_state diff --git a/intern/cycles/kernel/device/metal/globals.h b/intern/cycles/kernel/device/metal/globals.h new file mode 100644 index 00000000000..1aea36589d0 --- /dev/null +++ b/intern/cycles/kernel/device/metal/globals.h @@ -0,0 +1,51 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Constant Globals */ + +#include "kernel/types.h" +#include "kernel/util/profiling.h" + +#include "kernel/integrator/state.h" + +CCL_NAMESPACE_BEGIN + +typedef struct KernelParamsMetal { + +#define KERNEL_TEX(type, name) ccl_global const type *name; +#include "kernel/textures.h" +#undef KERNEL_TEX + + const IntegratorStateGPU __integrator_state; + const KernelData data; + +} KernelParamsMetal; + +typedef struct KernelGlobalsGPU { + int unused[1]; +} KernelGlobalsGPU; + +typedef ccl_global const KernelGlobalsGPU *ccl_restrict KernelGlobals; + +#define kernel_data launch_params_metal.data +#define kernel_integrator_state launch_params_metal.__integrator_state + +/* data lookup defines */ + +#define kernel_tex_fetch(tex, index) launch_params_metal.tex[index] +#define kernel_tex_array(tex) launch_params_metal.tex + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/device/metal/kernel.metal b/intern/cycles/kernel/device/metal/kernel.metal new file mode 100644 index 00000000000..feca20ff475 --- /dev/null +++ b/intern/cycles/kernel/device/metal/kernel.metal @@ -0,0 +1,25 @@ +/* + * Copyright 2021 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* Metal kernel entry points */ + +// clang-format off + +#include "kernel/device/metal/compat.h" +#include "kernel/device/metal/globals.h" +#include "kernel/device/gpu/kernel.h" + +// clang-format on
\ No newline at end of file diff --git a/intern/cycles/kernel/device/optix/compat.h b/intern/cycles/kernel/device/optix/compat.h index 835e4621d47..0619c135c39 100644 --- a/intern/cycles/kernel/device/optix/compat.h +++ b/intern/cycles/kernel/device/optix/compat.h @@ -49,10 +49,11 @@ typedef unsigned long long uint64_t; __device__ __forceinline__ // Function calls are bad for OptiX performance, so inline everything #define ccl_device_inline ccl_device #define ccl_device_forceinline ccl_device +#define ccl_device_inline_method ccl_device #define ccl_device_noinline __device__ __noinline__ #define ccl_device_noinline_cpu ccl_device #define ccl_global -#define ccl_static_constant __constant__ +#define ccl_inline_constant __constant__ #define ccl_device_constant __constant__ __device__ #define ccl_constant const #define ccl_gpu_shared __shared__ @@ -76,6 +77,7 @@ typedef unsigned long long uint64_t; #define ccl_gpu_block_idx_x (blockIdx.x) #define ccl_gpu_grid_dim_x (gridDim.x) #define ccl_gpu_warp_size (warpSize) +#define ccl_gpu_thread_mask(thread_warp) uint(0xFFFFFFFF >> (ccl_gpu_warp_size - thread_warp)) #define ccl_gpu_global_id_x() (ccl_gpu_block_idx_x * ccl_gpu_block_dim_x + ccl_gpu_thread_idx_x) #define ccl_gpu_global_size_x() (ccl_gpu_grid_dim_x * ccl_gpu_block_dim_x) @@ -85,7 +87,6 @@ typedef unsigned long long uint64_t; #define ccl_gpu_syncthreads() __syncthreads() #define ccl_gpu_ballot(predicate) __ballot_sync(0xFFFFFFFF, predicate) #define ccl_gpu_shfl_down_sync(mask, var, detla) __shfl_down_sync(mask, var, detla) -#define ccl_gpu_popc(x) __popc(x) /* GPU texture objects */ diff --git a/intern/cycles/kernel/device/optix/kernel.cu b/intern/cycles/kernel/device/optix/kernel.cu index b987aa7a817..4feed59d018 100644 --- a/intern/cycles/kernel/device/optix/kernel.cu +++ b/intern/cycles/kernel/device/optix/kernel.cu @@ -21,6 +21,8 @@ #include "kernel/device/gpu/image.h" /* Texture lookup uses normal CUDA intrinsics. */ +#include "kernel/tables.h" + #include "kernel/integrator/state.h" #include "kernel/integrator/state_flow.h" #include "kernel/integrator/state_util.h" @@ -44,7 +46,7 @@ template<typename T> ccl_device_forceinline T *get_payload_ptr_2() ccl_device_forceinline int get_object_id() { #ifdef __OBJECT_MOTION__ - /* Always get the the instance ID from the TLAS + /* Always get the instance ID from the TLAS * There might be a motion transform node between TLAS and BLAS which does not have one. */ return optixGetInstanceIdFromHandle(optixGetTransformListHandle(0)); #else @@ -159,9 +161,9 @@ extern "C" __global__ void __anyhit__kernel_optix_local_hit() /* Record geometric normal. */ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w; - const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)); - const float3 tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)); - const float3 tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2)); + const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0); + const float3 tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1); + const float3 tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); /* Continue tracing (without this the trace call would return after the first hit). */ diff --git a/intern/cycles/kernel/film/accumulate.h b/intern/cycles/kernel/film/accumulate.h index d66d7d6fb70..fb52b1cd05f 100644 --- a/intern/cycles/kernel/film/accumulate.h +++ b/intern/cycles/kernel/film/accumulate.h @@ -151,7 +151,8 @@ ccl_device_forceinline ccl_global float *kernel_accum_pixel_render_buffer( ccl_device_inline int kernel_accum_sample(KernelGlobals kg, ConstIntegratorState state, ccl_global float *ccl_restrict render_buffer, - int sample) + int sample, + int sample_offset) { if (kernel_data.film.pass_sample_count == PASS_UNUSED) { return sample; @@ -159,7 +160,9 @@ ccl_device_inline int kernel_accum_sample(KernelGlobals kg, ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); - return atomic_fetch_and_add_uint32((uint *)(buffer) + kernel_data.film.pass_sample_count, 1); + return atomic_fetch_and_add_uint32( + (ccl_global uint *)(buffer) + kernel_data.film.pass_sample_count, 1) + + sample_offset; } ccl_device void kernel_accum_adaptive_buffer(KernelGlobals kg, @@ -550,7 +553,7 @@ ccl_device_inline void kernel_accum_background(KernelGlobals kg, const bool is_transparent_background_ray, ccl_global float *ccl_restrict render_buffer) { - float3 contribution = INTEGRATOR_STATE(state, path, throughput) * L; + float3 contribution = float3(INTEGRATOR_STATE(state, path, throughput)) * L; kernel_accum_clamp(kg, &contribution, INTEGRATOR_STATE(state, path, bounce) - 1); ccl_global float *buffer = kernel_accum_pixel_render_buffer(kg, state, render_buffer); diff --git a/intern/cycles/kernel/geom/attribute.h b/intern/cycles/kernel/geom/attribute.h index 848e0430caa..a7ac2bd926f 100644 --- a/intern/cycles/kernel/geom/attribute.h +++ b/intern/cycles/kernel/geom/attribute.h @@ -27,7 +27,12 @@ CCL_NAMESPACE_BEGIN * Lookup of attributes is different between OSL and SVM, as OSL is ustring * based while for SVM we use integer ids. */ -ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd); +/* Patch index for triangle, -1 if not subdivision triangle */ + +ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd) +{ + return (sd->prim != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, sd->prim) : ~0; +} ccl_device_inline uint attribute_primitive_type(KernelGlobals kg, ccl_private const ShaderData *sd) { @@ -106,9 +111,9 @@ ccl_device Transform primitive_attribute_matrix(KernelGlobals kg, { Transform tfm; - tfm.x = kernel_tex_fetch(__attributes_float3, desc.offset + 0); - tfm.y = kernel_tex_fetch(__attributes_float3, desc.offset + 1); - tfm.z = kernel_tex_fetch(__attributes_float3, desc.offset + 2); + tfm.x = kernel_tex_fetch(__attributes_float4, desc.offset + 0); + tfm.y = kernel_tex_fetch(__attributes_float4, desc.offset + 1); + tfm.z = kernel_tex_fetch(__attributes_float4, desc.offset + 2); return tfm; } diff --git a/intern/cycles/kernel/geom/curve.h b/intern/cycles/kernel/geom/curve.h index 7271193eef8..4b6eecf9640 100644 --- a/intern/cycles/kernel/geom/curve.h +++ b/intern/cycles/kernel/geom/curve.h @@ -126,8 +126,8 @@ ccl_device float3 curve_attribute_float3(KernelGlobals kg, int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type); int k1 = k0 + 1; - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k0)); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + k1)); + float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + k0); + float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + k1); # ifdef __RAY_DIFFERENTIALS__ if (dx) @@ -149,7 +149,7 @@ ccl_device float3 curve_attribute_float3(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim : desc.offset; - return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset)); + return kernel_tex_fetch(__attributes_float3, offset); } else { return make_float3(0.0f, 0.0f, 0.0f); @@ -168,8 +168,8 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg, int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type); int k1 = k0 + 1; - float4 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + k0); - float4 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + k1); + float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + k0); + float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + k1); # ifdef __RAY_DIFFERENTIALS__ if (dx) @@ -191,7 +191,7 @@ ccl_device float4 curve_attribute_float4(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_CURVE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { const int offset = (desc.element == ATTR_ELEMENT_CURVE) ? desc.offset + sd->prim : desc.offset; - return kernel_tex_fetch(__attributes_float3, offset); + return kernel_tex_fetch(__attributes_float4, offset); } else { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); diff --git a/intern/cycles/kernel/geom/motion_curve.h b/intern/cycles/kernel/geom/motion_curve.h index 2dd213d43f6..8358c94360f 100644 --- a/intern/cycles/kernel/geom/motion_curve.h +++ b/intern/cycles/kernel/geom/motion_curve.h @@ -48,8 +48,8 @@ ccl_device_inline void motion_curve_keys_for_step_linear(KernelGlobals kg, offset += step * numkeys; - keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0); - keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1); + keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0); + keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1); } } @@ -106,10 +106,10 @@ ccl_device_inline void motion_curve_keys_for_step(KernelGlobals kg, offset += step * numkeys; - keys[0] = kernel_tex_fetch(__attributes_float3, offset + k0); - keys[1] = kernel_tex_fetch(__attributes_float3, offset + k1); - keys[2] = kernel_tex_fetch(__attributes_float3, offset + k2); - keys[3] = kernel_tex_fetch(__attributes_float3, offset + k3); + keys[0] = kernel_tex_fetch(__attributes_float4, offset + k0); + keys[1] = kernel_tex_fetch(__attributes_float4, offset + k1); + keys[2] = kernel_tex_fetch(__attributes_float4, offset + k2); + keys[3] = kernel_tex_fetch(__attributes_float4, offset + k3); } } diff --git a/intern/cycles/kernel/geom/motion_triangle.h b/intern/cycles/kernel/geom/motion_triangle.h index 43f894938e0..62b7b630c89 100644 --- a/intern/cycles/kernel/geom/motion_triangle.h +++ b/intern/cycles/kernel/geom/motion_triangle.h @@ -43,9 +43,9 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg, { if (step == numsteps) { /* center step: regular vertex location */ - verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); + verts[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + verts[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + verts[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); } else { /* center step not store in this array */ @@ -54,9 +54,9 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals kg, offset += step * numverts; - verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); - verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); - verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); + verts[0] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x); + verts[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y); + verts[2] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z); } } @@ -70,9 +70,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg, { if (step == numsteps) { /* center step: regular vertex location */ - normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); - normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); - normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); + normals[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x); + normals[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y); + normals[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z); } else { /* center step is not stored in this array */ @@ -81,9 +81,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals kg, offset += step * numverts; - normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); - normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); - normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); + normals[0] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x); + normals[1] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y); + normals[2] = kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z); } } diff --git a/intern/cycles/kernel/geom/motion_triangle_intersect.h b/intern/cycles/kernel/geom/motion_triangle_intersect.h index 256e7add21e..72ad237eeeb 100644 --- a/intern/cycles/kernel/geom/motion_triangle_intersect.h +++ b/intern/cycles/kernel/geom/motion_triangle_intersect.h @@ -163,19 +163,7 @@ ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg, motion_triangle_vertices(kg, fobject, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; - if (ray_triangle_intersect(P, - dir, - tmax, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - (ssef *)verts, -#else - verts[0], - verts[1], - verts[2], -#endif - &u, - &v, - &t)) { + if (ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) { #ifdef __VISIBILITY_FLAG__ /* Visibility flag test. we do it here under the assumption * that most triangles are culled by node flags. @@ -229,19 +217,7 @@ ccl_device_inline bool motion_triangle_intersect_local(KernelGlobals kg, motion_triangle_vertices(kg, local_object, prim, time, verts); /* Ray-triangle intersection, unoptimized. */ float t, u, v; - if (!ray_triangle_intersect(P, - dir, - tmax, -# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - (ssef *)verts, -# else - verts[0], - verts[1], - verts[2], -# endif - &u, - &v, - &t)) { + if (!ray_triangle_intersect(P, dir, tmax, verts[0], verts[1], verts[2], &u, &v, &t)) { return false; } diff --git a/intern/cycles/kernel/geom/patch.h b/intern/cycles/kernel/geom/patch.h index 7d24937a41e..432618aa243 100644 --- a/intern/cycles/kernel/geom/patch.h +++ b/intern/cycles/kernel/geom/patch.h @@ -380,7 +380,7 @@ ccl_device float3 patch_eval_float3(KernelGlobals kg, *dv = make_float3(0.0f, 0.0f, 0.0f); for (int i = 0; i < num_control; i++) { - float3 v = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + indices[i])); + float3 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]); val += v * weights[i]; if (du) @@ -417,7 +417,7 @@ ccl_device float4 patch_eval_float4(KernelGlobals kg, *dv = make_float4(0.0f, 0.0f, 0.0f, 0.0f); for (int i = 0; i < num_control; i++) { - float4 v = kernel_tex_fetch(__attributes_float3, offset + indices[i]); + float4 v = kernel_tex_fetch(__attributes_float4, offset + indices[i]); val += v * weights[i]; if (du) diff --git a/intern/cycles/kernel/geom/primitive.h b/intern/cycles/kernel/geom/primitive.h index 7a8921b6d6e..6d7b550d82f 100644 --- a/intern/cycles/kernel/geom/primitive.h +++ b/intern/cycles/kernel/geom/primitive.h @@ -284,18 +284,33 @@ ccl_device_inline float4 primitive_motion_vector(KernelGlobals kg, int numverts, numkeys; object_motion_info(kg, sd->object, NULL, &numverts, &numkeys); - /* lookup attributes */ - motion_pre = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL); - - desc.offset += (sd->type & PRIMITIVE_ALL_TRIANGLE) ? numverts : numkeys; - motion_post = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL); - #ifdef __HAIR__ - if (is_curve_primitive && (sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) { - object_position_transform(kg, sd, &motion_pre); - object_position_transform(kg, sd, &motion_post); + if (is_curve_primitive) { + motion_pre = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL)); + desc.offset += numkeys; + motion_post = float4_to_float3(curve_attribute_float4(kg, sd, desc, NULL, NULL)); + + /* Curve */ + if ((sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) { + object_position_transform(kg, sd, &motion_pre); + object_position_transform(kg, sd, &motion_post); + } } + else #endif + if (sd->type & PRIMITIVE_ALL_TRIANGLE) { + /* Triangle */ + if (subd_triangle_patch(kg, sd) == ~0) { + motion_pre = triangle_attribute_float3(kg, sd, desc, NULL, NULL); + desc.offset += numverts; + motion_post = triangle_attribute_float3(kg, sd, desc, NULL, NULL); + } + else { + motion_pre = subd_triangle_attribute_float3(kg, sd, desc, NULL, NULL); + desc.offset += numverts; + motion_post = subd_triangle_attribute_float3(kg, sd, desc, NULL, NULL); + } + } } /* object motion. note that depending on the mesh having motion vectors, this diff --git a/intern/cycles/kernel/geom/subd_triangle.h b/intern/cycles/kernel/geom/subd_triangle.h index 8a9a3f71231..1b693a915bf 100644 --- a/intern/cycles/kernel/geom/subd_triangle.h +++ b/intern/cycles/kernel/geom/subd_triangle.h @@ -20,13 +20,6 @@ CCL_NAMESPACE_BEGIN -/* Patch index for triangle, -1 if not subdivision triangle */ - -ccl_device_inline uint subd_triangle_patch(KernelGlobals kg, ccl_private const ShaderData *sd) -{ - return (sd->prim != PRIM_NONE) ? kernel_tex_fetch(__tri_patch, sd->prim) : ~0; -} - /* UV coords of triangle within patch */ ccl_device_inline void subd_triangle_patch_uv(KernelGlobals kg, @@ -443,8 +436,8 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, if (dy) *dy = make_float3(0.0f, 0.0f, 0.0f); - return float4_to_float3( - kernel_tex_fetch(__attributes_float3, desc.offset + subd_triangle_patch_face(kg, patch))); + return kernel_tex_fetch(__attributes_float3, + desc.offset + subd_triangle_patch_face(kg, patch)); } else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) { float2 uv[3]; @@ -452,10 +445,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, uint4 v = subd_triangle_patch_indices(kg, patch); - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.x)); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.y)); - float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.z)); - float3 f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + v.w)); + float3 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + v.x); + float3 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + v.y); + float3 f2 = kernel_tex_fetch(__attributes_float3, desc.offset + v.z); + float3 f3 = kernel_tex_fetch(__attributes_float3, desc.offset + v.w); if (subd_triangle_patch_num_corners(kg, patch) != 4) { f1 = (f1 + f0) * 0.5f; @@ -484,10 +477,10 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, float3 f0, f1, f2, f3; - f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset)); - f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset)); - f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset)); - f3 = float4_to_float3(kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset)); + f0 = kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset); + f1 = kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset); + f2 = kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset); + f3 = kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset); if (subd_triangle_patch_num_corners(kg, patch) != 4) { f1 = (f1 + f0) * 0.5f; @@ -513,7 +506,7 @@ ccl_device_noinline float3 subd_triangle_attribute_float3(KernelGlobals kg, if (dy) *dy = make_float3(0.0f, 0.0f, 0.0f); - return float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset)); + return kernel_tex_fetch(__attributes_float3, desc.offset); } else { if (dx) @@ -590,7 +583,7 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, if (dy) *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - return kernel_tex_fetch(__attributes_float3, + return kernel_tex_fetch(__attributes_float4, desc.offset + subd_triangle_patch_face(kg, patch)); } else if (desc.element == ATTR_ELEMENT_VERTEX || desc.element == ATTR_ELEMENT_VERTEX_MOTION) { @@ -599,10 +592,10 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, uint4 v = subd_triangle_patch_indices(kg, patch); - float4 f0 = kernel_tex_fetch(__attributes_float3, desc.offset + v.x); - float4 f1 = kernel_tex_fetch(__attributes_float3, desc.offset + v.y); - float4 f2 = kernel_tex_fetch(__attributes_float3, desc.offset + v.z); - float4 f3 = kernel_tex_fetch(__attributes_float3, desc.offset + v.w); + float4 f0 = kernel_tex_fetch(__attributes_float4, desc.offset + v.x); + float4 f1 = kernel_tex_fetch(__attributes_float4, desc.offset + v.y); + float4 f2 = kernel_tex_fetch(__attributes_float4, desc.offset + v.z); + float4 f3 = kernel_tex_fetch(__attributes_float4, desc.offset + v.w); if (subd_triangle_patch_num_corners(kg, patch) != 4) { f1 = (f1 + f0) * 0.5f; @@ -642,10 +635,10 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, color_uchar4_to_float4(kernel_tex_fetch(__attributes_uchar4, corners[3] + desc.offset))); } else { - f0 = kernel_tex_fetch(__attributes_float3, corners[0] + desc.offset); - f1 = kernel_tex_fetch(__attributes_float3, corners[1] + desc.offset); - f2 = kernel_tex_fetch(__attributes_float3, corners[2] + desc.offset); - f3 = kernel_tex_fetch(__attributes_float3, corners[3] + desc.offset); + f0 = kernel_tex_fetch(__attributes_float4, corners[0] + desc.offset); + f1 = kernel_tex_fetch(__attributes_float4, corners[1] + desc.offset); + f2 = kernel_tex_fetch(__attributes_float4, corners[2] + desc.offset); + f3 = kernel_tex_fetch(__attributes_float4, corners[3] + desc.offset); } if (subd_triangle_patch_num_corners(kg, patch) != 4) { @@ -672,7 +665,7 @@ ccl_device_noinline float4 subd_triangle_attribute_float4(KernelGlobals kg, if (dy) *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f); - return kernel_tex_fetch(__attributes_float3, desc.offset); + return kernel_tex_fetch(__attributes_float4, desc.offset); } else { if (dx) diff --git a/intern/cycles/kernel/geom/triangle.h b/intern/cycles/kernel/geom/triangle.h index 233e901c7ca..854022b3369 100644 --- a/intern/cycles/kernel/geom/triangle.h +++ b/intern/cycles/kernel/geom/triangle.h @@ -29,9 +29,9 @@ ccl_device_inline float3 triangle_normal(KernelGlobals kg, ccl_private ShaderDat { /* load triangle vertices */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim); - const float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - const float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - const float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); + const float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + const float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + const float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); /* return normal */ if (sd->object_flag & SD_OBJECT_NEGATIVE_SCALE_APPLIED) { @@ -54,9 +54,9 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg, { /* load triangle vertices */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); + float3 v0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + float3 v1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + float3 v2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); /* compute point */ float t = 1.0f - u - v; *P = (u * v0 + v * v1 + t * v2); @@ -78,9 +78,9 @@ ccl_device_inline void triangle_point_normal(KernelGlobals kg, ccl_device_inline void triangle_vertices(KernelGlobals kg, int prim, float3 P[3]) { const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); + P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); } /* Triangle vertex locations and vertex normals */ @@ -91,12 +91,12 @@ ccl_device_inline void triangle_vertices_and_normals(KernelGlobals kg, float3 N[3]) { const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); - N[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); - N[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); - N[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); + P[0] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + P[1] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + P[2] = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); + N[0] = kernel_tex_fetch(__tri_vnormal, tri_vindex.x); + N[1] = kernel_tex_fetch(__tri_vnormal, tri_vindex.y); + N[2] = kernel_tex_fetch(__tri_vnormal, tri_vindex.z); } /* Interpolate smooth vertex normal from vertices */ @@ -106,9 +106,9 @@ triangle_smooth_normal(KernelGlobals kg, float3 Ng, int prim, float u, float v) { /* load triangle vertices */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); - float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); - float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); + float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x); + float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y); + float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z); float3 N = safe_normalize((1.0f - u - v) * n2 + u * n0 + v * n1); @@ -120,9 +120,9 @@ ccl_device_inline float3 triangle_smooth_normal_unnormalized( { /* load triangle vertices */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.x)); - float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.y)); - float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, tri_vindex.z)); + float3 n0 = kernel_tex_fetch(__tri_vnormal, tri_vindex.x); + float3 n1 = kernel_tex_fetch(__tri_vnormal, tri_vindex.y); + float3 n2 = kernel_tex_fetch(__tri_vnormal, tri_vindex.z); /* ensure that the normals are in object space */ if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) { @@ -145,9 +145,9 @@ ccl_device_inline void triangle_dPdudv(KernelGlobals kg, { /* fetch triangle vertex coordinates */ const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - const float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 0)); - const float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 1)); - const float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex.w + 2)); + const float3 p0 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 0); + const float3 p1 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 1); + const float3 p2 = kernel_tex_fetch(__tri_verts, tri_vindex.w + 2); /* compute derivatives of P w.r.t. uv */ *dPdu = (p0 - p2); @@ -267,15 +267,15 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) { const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim); - f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x)); - f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y)); - f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z)); + f0 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x); + f1 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y); + f2 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z); } else { const int tri = desc.offset + sd->prim * 3; - f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0)); - f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1)); - f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2)); + f0 = kernel_tex_fetch(__attributes_float3, tri + 0); + f1 = kernel_tex_fetch(__attributes_float3, tri + 1); + f2 = kernel_tex_fetch(__attributes_float3, tri + 2); } #ifdef __RAY_DIFFERENTIALS__ @@ -298,7 +298,7 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim : desc.offset; - return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset)); + return kernel_tex_fetch(__attributes_float3, offset); } else { return make_float3(0.0f, 0.0f, 0.0f); @@ -318,16 +318,16 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_VERTEX | ATTR_ELEMENT_VERTEX_MOTION)) { const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, sd->prim); - f0 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.x); - f1 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.y); - f2 = kernel_tex_fetch(__attributes_float3, desc.offset + tri_vindex.z); + f0 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.x); + f1 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.y); + f2 = kernel_tex_fetch(__attributes_float4, desc.offset + tri_vindex.z); } else { const int tri = desc.offset + sd->prim * 3; if (desc.element == ATTR_ELEMENT_CORNER) { - f0 = kernel_tex_fetch(__attributes_float3, tri + 0); - f1 = kernel_tex_fetch(__attributes_float3, tri + 1); - f2 = kernel_tex_fetch(__attributes_float3, tri + 2); + f0 = kernel_tex_fetch(__attributes_float4, tri + 0); + f1 = kernel_tex_fetch(__attributes_float4, tri + 1); + f2 = kernel_tex_fetch(__attributes_float4, tri + 2); } else { f0 = color_srgb_to_linear_v4( @@ -359,7 +359,7 @@ ccl_device float4 triangle_attribute_float4(KernelGlobals kg, if (desc.element & (ATTR_ELEMENT_FACE | ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { const int offset = (desc.element == ATTR_ELEMENT_FACE) ? desc.offset + sd->prim : desc.offset; - return kernel_tex_fetch(__attributes_float3, offset); + return kernel_tex_fetch(__attributes_float4, offset); } else { return make_float4(0.0f, 0.0f, 0.0f, 0.0f); diff --git a/intern/cycles/kernel/geom/triangle_intersect.h b/intern/cycles/kernel/geom/triangle_intersect.h index faff8a85a93..57a6ae7fe72 100644 --- a/intern/cycles/kernel/geom/triangle_intersect.h +++ b/intern/cycles/kernel/geom/triangle_intersect.h @@ -37,27 +37,11 @@ ccl_device_inline bool triangle_intersect(KernelGlobals kg, { const int prim = kernel_tex_fetch(__prim_index, prim_addr); const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w; -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex]; -#else - const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), + const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); -#endif float t, u, v; - if (ray_triangle_intersect(P, - dir, - tmax, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - ssef_verts, -#else - float4_to_float3(tri_a), - float4_to_float3(tri_b), - float4_to_float3(tri_c), -#endif - &u, - &v, - &t)) { + if (ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) { #ifdef __VISIBILITY_FLAG__ /* Visibility flag test. we do it here under the assumption * that most triangles are culled by node flags. @@ -106,27 +90,11 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg, const int prim = kernel_tex_fetch(__prim_index, prim_addr); const uint tri_vindex = kernel_tex_fetch(__tri_vindex, prim).w; -# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - const ssef *ssef_verts = (ssef *)&kg->__tri_verts.data[tri_vindex]; -# else - const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)), - tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)), - tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2)); -# endif + const float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), + tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), + tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); float t, u, v; - if (!ray_triangle_intersect(P, - dir, - tmax, -# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - ssef_verts, -# else - tri_a, - tri_b, - tri_c, -# endif - &u, - &v, - &t)) { + if (!ray_triangle_intersect(P, dir, tmax, tri_a, tri_b, tri_c, &u, &v, &t)) { return false; } @@ -178,11 +146,6 @@ ccl_device_inline bool triangle_intersect_local(KernelGlobals kg, isect->t = t; /* Record geometric normal. */ -# if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - const float3 tri_a = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 0)), - tri_b = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 1)), - tri_c = float4_to_float3(kernel_tex_fetch(__tri_verts, tri_vindex + 2)); -# endif local_isect->Ng[hit] = normalize(cross(tri_b - tri_a, tri_c - tri_a)); return false; @@ -223,9 +186,9 @@ ccl_device_inline float3 triangle_refine(KernelGlobals kg, P = P + D * t; const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w; - const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), - tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), - tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); + const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), + tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), + tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); @@ -280,9 +243,9 @@ ccl_device_inline float3 triangle_refine_local(KernelGlobals kg, # ifdef __INTERSECTION_REFINE__ const uint tri_vindex = kernel_tex_fetch(__tri_vindex, isect_prim).w; - const float4 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), - tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), - tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); + const packed_float3 tri_a = kernel_tex_fetch(__tri_verts, tri_vindex + 0), + tri_b = kernel_tex_fetch(__tri_verts, tri_vindex + 1), + tri_c = kernel_tex_fetch(__tri_verts, tri_vindex + 2); float3 edge1 = make_float3(tri_a.x - tri_c.x, tri_a.y - tri_c.y, tri_a.z - tri_c.z); float3 edge2 = make_float3(tri_b.x - tri_c.x, tri_b.y - tri_c.y, tri_b.z - tri_c.z); float3 tvec = make_float3(P.x - tri_c.x, P.y - tri_c.y, P.z - tri_c.z); diff --git a/intern/cycles/kernel/geom/volume.h b/intern/cycles/kernel/geom/volume.h index 4e83ad6acb3..387eb2646da 100644 --- a/intern/cycles/kernel/geom/volume.h +++ b/intern/cycles/kernel/geom/volume.h @@ -75,7 +75,7 @@ ccl_device float4 volume_attribute_float4(KernelGlobals kg, const AttributeDescriptor desc) { if (desc.element & (ATTR_ELEMENT_OBJECT | ATTR_ELEMENT_MESH)) { - return kernel_tex_fetch(__attributes_float3, desc.offset); + return kernel_tex_fetch(__attributes_float4, desc.offset); } else if (desc.element == ATTR_ELEMENT_VOXEL) { /* todo: optimize this so we don't have to transform both here and in diff --git a/intern/cycles/kernel/integrator/init_from_bake.h b/intern/cycles/kernel/integrator/init_from_bake.h index dbaf02836e4..f4a2fbea405 100644 --- a/intern/cycles/kernel/integrator/init_from_bake.h +++ b/intern/cycles/kernel/integrator/init_from_bake.h @@ -65,7 +65,8 @@ ccl_device bool integrator_init_from_bake(KernelGlobals kg, } /* Always count the sample, even if the camera sample will reject the ray. */ - const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample); + const int sample = kernel_accum_sample( + kg, state, render_buffer, scheduled_sample, tile->sample_offset); /* Setup render buffers. */ const int index = INTEGRATOR_STATE(state, path, render_pixel_index); diff --git a/intern/cycles/kernel/integrator/init_from_camera.h b/intern/cycles/kernel/integrator/init_from_camera.h index f0ba77bd9a6..59dd1a9fa75 100644 --- a/intern/cycles/kernel/integrator/init_from_camera.h +++ b/intern/cycles/kernel/integrator/init_from_camera.h @@ -89,7 +89,8 @@ ccl_device bool integrator_init_from_camera(KernelGlobals kg, * This logic allows to both count actual number of samples per pixel, and to add samples to this * pixel after it was converged and samples were added somewhere else (in which case the * `scheduled_sample` will be different from actual number of samples in this pixel). */ - const int sample = kernel_accum_sample(kg, state, render_buffer, scheduled_sample); + const int sample = kernel_accum_sample( + kg, state, render_buffer, scheduled_sample, tile->sample_offset); /* Initialize random number seed for path. */ const uint rng_hash = path_rng_hash_init(kg, sample, x, y); diff --git a/intern/cycles/kernel/integrator/shade_background.h b/intern/cycles/kernel/integrator/shade_background.h index 31452de1ca4..a8ebbe908ae 100644 --- a/intern/cycles/kernel/integrator/shade_background.h +++ b/intern/cycles/kernel/integrator/shade_background.h @@ -20,7 +20,6 @@ #include "kernel/integrator/shader_eval.h" #include "kernel/light/light.h" #include "kernel/light/sample.h" -#include "kernel/sample/mis.h" CCL_NAMESPACE_BEGIN @@ -81,8 +80,7 @@ ccl_device float3 integrator_eval_background_shader(KernelGlobals kg, /* multiple importance sampling, get background light pdf for ray * direction, and compute weight with respect to BSDF pdf */ const float pdf = background_light_pdf(kg, ray_P - ray_D * mis_ray_t, ray_D); - const float mis_weight = power_heuristic(mis_ray_pdf, pdf); - + const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, pdf); L *= mis_weight; } # endif @@ -169,7 +167,7 @@ ccl_device_inline void integrate_distant_lights(KernelGlobals kg, /* multiple importance sampling, get regular light pdf, * and compute weight with respect to BSDF pdf */ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); - const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf); + const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, ls.pdf); light_eval *= mis_weight; } diff --git a/intern/cycles/kernel/integrator/shade_light.h b/intern/cycles/kernel/integrator/shade_light.h index 5abe9e98abc..97ca430752c 100644 --- a/intern/cycles/kernel/integrator/shade_light.h +++ b/intern/cycles/kernel/integrator/shade_light.h @@ -84,7 +84,7 @@ ccl_device_inline void integrate_light(KernelGlobals kg, /* multiple importance sampling, get regular light pdf, * and compute weight with respect to BSDF pdf */ const float mis_ray_pdf = INTEGRATOR_STATE(state, path, mis_ray_pdf); - const float mis_weight = power_heuristic(mis_ray_pdf, ls.pdf); + const float mis_weight = light_sample_mis_weight_forward(kg, mis_ray_pdf, ls.pdf); light_eval *= mis_weight; } diff --git a/intern/cycles/kernel/integrator/shade_shadow.h b/intern/cycles/kernel/integrator/shade_shadow.h index 1de890aae29..a68fcaa7a64 100644 --- a/intern/cycles/kernel/integrator/shade_shadow.h +++ b/intern/cycles/kernel/integrator/shade_shadow.h @@ -95,8 +95,8 @@ ccl_device_inline void integrate_transparent_volume_shadow(KernelGlobals kg, shader_setup_from_volume(kg, shadow_sd, &ray); - const float step_size = volume_stack_step_size( - kg, [=](const int i) { return integrator_state_read_shadow_volume_stack(state, i); }); + VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i)); + const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); volume_shadow_heterogeneous(kg, state, &ray, shadow_sd, throughput, step_size); } diff --git a/intern/cycles/kernel/integrator/shade_surface.h b/intern/cycles/kernel/integrator/shade_surface.h index 2793dd3e218..c9c586f5ae4 100644 --- a/intern/cycles/kernel/integrator/shade_surface.h +++ b/intern/cycles/kernel/integrator/shade_surface.h @@ -27,8 +27,6 @@ #include "kernel/light/light.h" #include "kernel/light/sample.h" -#include "kernel/sample/mis.h" - CCL_NAMESPACE_BEGIN ccl_device_forceinline void integrate_surface_shader_setup(KernelGlobals kg, @@ -95,8 +93,7 @@ ccl_device_forceinline void integrate_surface_emission(KernelGlobals kg, /* Multiple importance sampling, get triangle light pdf, * and compute weight with respect to BSDF pdf. */ float pdf = triangle_light_pdf(kg, sd, t); - float mis_weight = power_heuristic(bsdf_pdf, pdf); - + float mis_weight = light_sample_mis_weight_forward(kg, bsdf_pdf, pdf); L *= mis_weight; } @@ -155,7 +152,7 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, bsdf_eval_mul3(&bsdf_eval, light_eval / ls.pdf); if (ls.shader & SHADER_USE_MIS) { - const float mis_weight = power_heuristic(ls.pdf, bsdf_pdf); + const float mis_weight = light_sample_mis_weight_nee(kg, ls.pdf, bsdf_pdf); bsdf_eval_mul(&bsdf_eval, mis_weight); } @@ -195,12 +192,13 @@ ccl_device_forceinline void integrate_surface_direct_light(KernelGlobals kg, const float3 throughput = INTEGRATOR_STATE(state, path, throughput) * bsdf_eval_sum(&bsdf_eval); if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { - const float3 pass_diffuse_weight = (bounce == 0) ? - bsdf_eval_pass_diffuse_weight(&bsdf_eval) : - INTEGRATOR_STATE(state, path, pass_diffuse_weight); - const float3 pass_glossy_weight = (bounce == 0) ? - bsdf_eval_pass_glossy_weight(&bsdf_eval) : - INTEGRATOR_STATE(state, path, pass_glossy_weight); + const packed_float3 pass_diffuse_weight = + (bounce == 0) ? packed_float3(bsdf_eval_pass_diffuse_weight(&bsdf_eval)) : + INTEGRATOR_STATE(state, path, pass_diffuse_weight); + const packed_float3 pass_glossy_weight = (bounce == 0) ? + packed_float3( + bsdf_eval_pass_glossy_weight(&bsdf_eval)) : + INTEGRATOR_STATE(state, path, pass_glossy_weight); INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = pass_diffuse_weight; INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = pass_glossy_weight; } diff --git a/intern/cycles/kernel/integrator/shade_volume.h b/intern/cycles/kernel/integrator/shade_volume.h index cc47557d580..712c22357b8 100644 --- a/intern/cycles/kernel/integrator/shade_volume.h +++ b/intern/cycles/kernel/integrator/shade_volume.h @@ -27,8 +27,6 @@ #include "kernel/light/light.h" #include "kernel/light/sample.h" -#include "kernel/sample/mis.h" - CCL_NAMESPACE_BEGIN #ifdef __VOLUME__ @@ -78,9 +76,8 @@ ccl_device_inline bool shadow_volume_shader_sample(KernelGlobals kg, ccl_private ShaderData *ccl_restrict sd, ccl_private float3 *ccl_restrict extinction) { - shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, [=](const int i) { - return integrator_state_read_shadow_volume_stack(state, i); - }); + VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i)) + shader_eval_volume<true>(kg, state, sd, PATH_RAY_SHADOW, volume_read_lambda_pass); if (!(sd->flag & SD_EXTINCTION)) { return false; @@ -98,9 +95,8 @@ ccl_device_inline bool volume_shader_sample(KernelGlobals kg, ccl_private VolumeShaderCoefficients *coeff) { const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag); - shader_eval_volume<false>(kg, state, sd, path_flag, [=](const int i) { - return integrator_state_read_volume_stack(state, i); - }); + VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) + shader_eval_volume<false>(kg, state, sd, path_flag, volume_read_lambda_pass); if (!(sd->flag & (SD_EXTINCTION | SD_SCATTER | SD_EMISSION))) { return false; @@ -772,7 +768,7 @@ ccl_device_forceinline void integrate_volume_direct_light( const float phase_pdf = shader_volume_phase_eval(kg, sd, phases, ls->D, &phase_eval); if (ls->shader & SHADER_USE_MIS) { - float mis_weight = power_heuristic(ls->pdf, phase_pdf); + float mis_weight = light_sample_mis_weight_nee(kg, ls->pdf, phase_pdf); bsdf_eval_mul(&phase_eval, mis_weight); } @@ -805,9 +801,10 @@ ccl_device_forceinline void integrate_volume_direct_light( const float3 throughput_phase = throughput * bsdf_eval_sum(&phase_eval); if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) { - const float3 pass_diffuse_weight = (bounce == 0) ? - one_float3() : - INTEGRATOR_STATE(state, path, pass_diffuse_weight); + const packed_float3 pass_diffuse_weight = (bounce == 0) ? + packed_float3(one_float3()) : + INTEGRATOR_STATE( + state, path, pass_diffuse_weight); INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = pass_diffuse_weight; INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = zero_float3(); } @@ -932,8 +929,8 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg, VOLUME_SAMPLE_DISTANCE; /* Step through volume. */ - const float step_size = volume_stack_step_size( - kg, [=](const int i) { return integrator_state_read_volume_stack(state, i); }); + VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) + const float step_size = volume_stack_step_size(kg, volume_read_lambda_pass); /* TODO: expensive to zero closures? */ VolumeIntegrateResult result = {}; diff --git a/intern/cycles/kernel/integrator/shadow_state_template.h b/intern/cycles/kernel/integrator/shadow_state_template.h index 667ab88c8c4..625a429d3db 100644 --- a/intern/cycles/kernel/integrator/shadow_state_template.h +++ b/intern/cycles/kernel/integrator/shadow_state_template.h @@ -40,15 +40,15 @@ KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, queued_kernel, KERNEL_FEATURE_PATH_T /* enum PathRayFlag */ KERNEL_STRUCT_MEMBER(shadow_path, uint32_t, flag, KERNEL_FEATURE_PATH_TRACING) /* Throughput. */ -KERNEL_STRUCT_MEMBER(shadow_path, float3, throughput, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, throughput, KERNEL_FEATURE_PATH_TRACING) /* Throughput for shadow pass. */ KERNEL_STRUCT_MEMBER(shadow_path, - float3, + packed_float3, unshadowed_throughput, KERNEL_FEATURE_SHADOW_PASS | KERNEL_FEATURE_AO_ADDITIVE) /* Ratio of throughput to distinguish diffuse / glossy / transmission render passes. */ -KERNEL_STRUCT_MEMBER(shadow_path, float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES) -KERNEL_STRUCT_MEMBER(shadow_path, float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES) +KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES) +KERNEL_STRUCT_MEMBER(shadow_path, packed_float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES) /* Number of intersections found by ray-tracing. */ KERNEL_STRUCT_MEMBER(shadow_path, uint16_t, num_hits, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_END(shadow_path) @@ -56,8 +56,8 @@ KERNEL_STRUCT_END(shadow_path) /********************************** Shadow Ray *******************************/ KERNEL_STRUCT_BEGIN(shadow_ray) -KERNEL_STRUCT_MEMBER(shadow_ray, float3, P, KERNEL_FEATURE_PATH_TRACING) -KERNEL_STRUCT_MEMBER(shadow_ray, float3, D, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, P, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(shadow_ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, t, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, time, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(shadow_ray, float, dP, KERNEL_FEATURE_PATH_TRACING) diff --git a/intern/cycles/kernel/integrator/state_template.h b/intern/cycles/kernel/integrator/state_template.h index 3299f973713..bd18a7498a3 100644 --- a/intern/cycles/kernel/integrator/state_template.h +++ b/intern/cycles/kernel/integrator/state_template.h @@ -59,12 +59,12 @@ KERNEL_STRUCT_MEMBER(path, float, min_ray_pdf, KERNEL_FEATURE_PATH_TRACING) /* Continuation probability for path termination. */ KERNEL_STRUCT_MEMBER(path, float, continuation_probability, KERNEL_FEATURE_PATH_TRACING) /* Throughput. */ -KERNEL_STRUCT_MEMBER(path, float3, throughput, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(path, packed_float3, throughput, KERNEL_FEATURE_PATH_TRACING) /* Ratio of throughput to distinguish diffuse / glossy / transmission render passes. */ -KERNEL_STRUCT_MEMBER(path, float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES) -KERNEL_STRUCT_MEMBER(path, float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES) +KERNEL_STRUCT_MEMBER(path, packed_float3, pass_diffuse_weight, KERNEL_FEATURE_LIGHT_PASSES) +KERNEL_STRUCT_MEMBER(path, packed_float3, pass_glossy_weight, KERNEL_FEATURE_LIGHT_PASSES) /* Denoising. */ -KERNEL_STRUCT_MEMBER(path, float3, denoising_feature_throughput, KERNEL_FEATURE_DENOISING) +KERNEL_STRUCT_MEMBER(path, packed_float3, denoising_feature_throughput, KERNEL_FEATURE_DENOISING) /* Shader sorting. */ /* TODO: compress as uint16? or leave out entirely and recompute key in sorting code? */ KERNEL_STRUCT_MEMBER(path, uint32_t, shader_sort_key, KERNEL_FEATURE_PATH_TRACING) @@ -73,8 +73,8 @@ KERNEL_STRUCT_END(path) /************************************** Ray ***********************************/ KERNEL_STRUCT_BEGIN(ray) -KERNEL_STRUCT_MEMBER(ray, float3, P, KERNEL_FEATURE_PATH_TRACING) -KERNEL_STRUCT_MEMBER(ray, float3, D, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(ray, packed_float3, P, KERNEL_FEATURE_PATH_TRACING) +KERNEL_STRUCT_MEMBER(ray, packed_float3, D, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(ray, float, t, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(ray, float, time, KERNEL_FEATURE_PATH_TRACING) KERNEL_STRUCT_MEMBER(ray, float, dP, KERNEL_FEATURE_PATH_TRACING) @@ -96,10 +96,10 @@ KERNEL_STRUCT_END(isect) /*************** Subsurface closure state for subsurface kernel ***************/ KERNEL_STRUCT_BEGIN(subsurface) -KERNEL_STRUCT_MEMBER(subsurface, float3, albedo, KERNEL_FEATURE_SUBSURFACE) -KERNEL_STRUCT_MEMBER(subsurface, float3, radius, KERNEL_FEATURE_SUBSURFACE) +KERNEL_STRUCT_MEMBER(subsurface, packed_float3, albedo, KERNEL_FEATURE_SUBSURFACE) +KERNEL_STRUCT_MEMBER(subsurface, packed_float3, radius, KERNEL_FEATURE_SUBSURFACE) KERNEL_STRUCT_MEMBER(subsurface, float, anisotropy, KERNEL_FEATURE_SUBSURFACE) -KERNEL_STRUCT_MEMBER(subsurface, float3, Ng, KERNEL_FEATURE_SUBSURFACE) +KERNEL_STRUCT_MEMBER(subsurface, packed_float3, Ng, KERNEL_FEATURE_SUBSURFACE) KERNEL_STRUCT_END(subsurface) /********************************** Volume Stack ******************************/ diff --git a/intern/cycles/kernel/integrator/volume_stack.h b/intern/cycles/kernel/integrator/volume_stack.h index cf69826ffff..ea3fa901e2d 100644 --- a/intern/cycles/kernel/integrator/volume_stack.h +++ b/intern/cycles/kernel/integrator/volume_stack.h @@ -18,6 +18,14 @@ CCL_NAMESPACE_BEGIN +/* Volumetric read/write lambda functions - default implementations */ +#ifndef VOLUME_READ_LAMBDA +# define VOLUME_READ_LAMBDA(function_call) \ + auto volume_read_lambda_pass = [=](const int i) { return function_call; }; +# define VOLUME_WRITE_LAMBDA(function_call) \ + auto volume_write_lambda_pass = [=](const int i, VolumeStack entry) { function_call; }; +#endif + /* Volume Stack * * This is an array of object/shared ID's that the current segment of the path @@ -88,26 +96,18 @@ ccl_device void volume_stack_enter_exit(KernelGlobals kg, IntegratorState state, ccl_private const ShaderData *sd) { - volume_stack_enter_exit( - kg, - sd, - [=](const int i) { return integrator_state_read_volume_stack(state, i); }, - [=](const int i, const VolumeStack entry) { - integrator_state_write_volume_stack(state, i, entry); - }); + VOLUME_READ_LAMBDA(integrator_state_read_volume_stack(state, i)) + VOLUME_WRITE_LAMBDA(integrator_state_write_volume_stack(state, i, entry)) + volume_stack_enter_exit(kg, sd, volume_read_lambda_pass, volume_write_lambda_pass); } ccl_device void shadow_volume_stack_enter_exit(KernelGlobals kg, IntegratorShadowState state, ccl_private const ShaderData *sd) { - volume_stack_enter_exit( - kg, - sd, - [=](const int i) { return integrator_state_read_shadow_volume_stack(state, i); }, - [=](const int i, const VolumeStack entry) { - integrator_state_write_shadow_volume_stack(state, i, entry); - }); + VOLUME_READ_LAMBDA(integrator_state_read_shadow_volume_stack(state, i)) + VOLUME_WRITE_LAMBDA(integrator_state_write_shadow_volume_stack(state, i, entry)) + volume_stack_enter_exit(kg, sd, volume_read_lambda_pass, volume_write_lambda_pass); } /* Clean stack after the last bounce. diff --git a/intern/cycles/kernel/light/light.h b/intern/cycles/kernel/light/light.h index 97dca936552..e0a9f1c57f5 100644 --- a/intern/cycles/kernel/light/light.h +++ b/intern/cycles/kernel/light/light.h @@ -676,19 +676,7 @@ ccl_device_forceinline void triangle_light_sample(KernelGlobals kg, ls->D = z * B + safe_sqrtf(1.0f - z * z) * safe_normalize(C_ - dot(C_, B) * B); /* calculate intersection with the planar triangle */ - if (!ray_triangle_intersect(P, - ls->D, - FLT_MAX, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - (ssef *)V, -#else - V[0], - V[1], - V[2], -#endif - &ls->u, - &ls->v, - &ls->t)) { + if (!ray_triangle_intersect(P, ls->D, FLT_MAX, V[0], V[1], V[2], &ls->u, &ls->v, &ls->t)) { ls->pdf = 0.0f; return; } diff --git a/intern/cycles/kernel/light/sample.h b/intern/cycles/kernel/light/sample.h index 6b643a95250..ff5d43ed8cd 100644 --- a/intern/cycles/kernel/light/sample.h +++ b/intern/cycles/kernel/light/sample.h @@ -22,6 +22,7 @@ #include "kernel/light/light.h" #include "kernel/sample/mapping.h" +#include "kernel/sample/mis.h" CCL_NAMESPACE_BEGIN @@ -268,4 +269,36 @@ ccl_device_inline void light_sample_to_volume_shadow_ray( shadow_ray_setup(sd, ls, P, ray); } +ccl_device_inline float light_sample_mis_weight_forward(KernelGlobals kg, + const float forward_pdf, + const float nee_pdf) +{ +#ifdef WITH_CYCLES_DEBUG + if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) { + return 1.0f; + } + else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) { + return 0.0f; + } + else +#endif + return power_heuristic(forward_pdf, nee_pdf); +} + +ccl_device_inline float light_sample_mis_weight_nee(KernelGlobals kg, + const float nee_pdf, + const float forward_pdf) +{ +#ifdef WITH_CYCLES_DEBUG + if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_FORWARD) { + return 0.0f; + } + else if (kernel_data.integrator.direct_light_sampling_type == DIRECT_LIGHT_SAMPLING_NEE) { + return 1.0f; + } + else +#endif + return power_heuristic(nee_pdf, forward_pdf); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt index f226c95766f..90e16bd70d4 100644 --- a/intern/cycles/kernel/osl/CMakeLists.txt +++ b/intern/cycles/kernel/osl/CMakeLists.txt @@ -55,7 +55,7 @@ if(APPLE) # Disable allocation warning on macOS prior to 10.14: the OSLRenderServices # contains member which is 64 bytes aligned (cache inside of OIIO's # unordered_map_concurrent). This is not something what the SDK supportsm, but - # since we take care of allocations ourselves is is OK to ignore the + # since we take care of allocations ourselves is OK to ignore the # diagnostic message. string(APPEND CMAKE_CXX_FLAGS " -faligned-allocation") endif() diff --git a/intern/cycles/kernel/sample/lcg.h b/intern/cycles/kernel/sample/lcg.h index 92cfff639b4..e8c4915813e 100644 --- a/intern/cycles/kernel/sample/lcg.h +++ b/intern/cycles/kernel/sample/lcg.h @@ -19,14 +19,16 @@ CCL_NAMESPACE_BEGIN /* Linear Congruential Generator */ -ccl_device uint lcg_step_uint(uint *rng) +/* This is templated to handle multiple address spaces on Metal. */ +template<class T> ccl_device uint lcg_step_uint(T rng) { /* implicit mod 2^32 */ *rng = (1103515245 * (*rng) + 12345); return *rng; } -ccl_device float lcg_step_float(uint *rng) +/* This is templated to handle multiple address spaces on Metal. */ +template<class T> ccl_device float lcg_step_float(T rng) { /* implicit mod 2^32 */ *rng = (1103515245 * (*rng) + 12345); diff --git a/intern/cycles/kernel/sample/pattern.h b/intern/cycles/kernel/sample/pattern.h index 0c27992c7f6..adc8493badd 100644 --- a/intern/cycles/kernel/sample/pattern.h +++ b/intern/cycles/kernel/sample/pattern.h @@ -163,18 +163,7 @@ ccl_device_inline bool sample_is_even(int pattern, int sample) /* See Section 10.2.1, "Progressive Multi-Jittered Sample Sequences", Christensen et al. * We can use this to get divide sample sequence into two classes for easier variance * estimation. */ -#if defined(__GNUC__) && !defined(__KERNEL_GPU__) - return __builtin_popcount(sample & 0xaaaaaaaa) & 1; -#elif defined(__NVCC__) - return __popc(sample & 0xaaaaaaaa) & 1; -#else - /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */ - int i = sample & 0xaaaaaaaa; - i = i - ((i >> 1) & 0x55555555); - i = (i & 0x33333333) + ((i >> 2) & 0x33333333); - i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; - return i & 1; -#endif + return popcount(uint(sample) & 0xaaaaaaaa) & 1; } else { /* TODO(Stefan): Are there reliable ways of dividing CMJ and Sobol into two classes? */ diff --git a/intern/cycles/kernel/svm/math_util.h b/intern/cycles/kernel/svm/math_util.h index b2e539cdd1f..20817cd0fd3 100644 --- a/intern/cycles/kernel/svm/math_util.h +++ b/intern/cycles/kernel/svm/math_util.h @@ -212,33 +212,6 @@ ccl_device float3 svm_math_blackbody_color(float t) * which is enough to get the same 8 bit/channel color. */ - const float blackbody_table_r[6][3] = { - {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f}, - {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f}, - {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f}, - {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f}, - {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f}, - {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f}, - }; - - const float blackbody_table_g[6][3] = { - {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f}, - {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f}, - {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f}, - {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f}, - {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f}, - {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f}, - }; - - const float blackbody_table_b[6][4] = { - {0.0f, 0.0f, 0.0f, 0.0f}, /* zeros should be optimized by compiler */ - {0.0f, 0.0f, 0.0f, 0.0f}, - {0.0f, 0.0f, 0.0f, 0.0f}, - {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f}, - {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f}, - {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f}, - }; - if (t >= 12000.0f) { return make_float3(0.826270103f, 0.994478524f, 1.56626022f); } diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 62ba5bf04e3..ce32e1a520f 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -220,7 +220,7 @@ CCL_NAMESPACE_BEGIN template<uint node_feature_mask, ShaderType type, typename ConstIntegratorGenericState> ccl_device void svm_eval_nodes(KernelGlobals kg, ConstIntegratorGenericState state, - ShaderData *sd, + ccl_private ShaderData *sd, ccl_global float *render_buffer, uint32_t path_flag) { diff --git a/intern/cycles/kernel/svm/wavelength.h b/intern/cycles/kernel/svm/wavelength.h index 28fd172abc7..6e25224243f 100644 --- a/intern/cycles/kernel/svm/wavelength.h +++ b/intern/cycles/kernel/svm/wavelength.h @@ -42,41 +42,6 @@ ccl_device_noinline void svm_node_wavelength(KernelGlobals kg, uint wavelength, uint color_out) { - // CIE colour matching functions xBar, yBar, and zBar for - // wavelengths from 380 through 780 nanometers, every 5 - // nanometers. For a wavelength lambda in this range: - // cie_colour_match[(lambda - 380) / 5][0] = xBar - // cie_colour_match[(lambda - 380) / 5][1] = yBar - // cie_colour_match[(lambda - 380) / 5][2] = zBar - const float cie_colour_match[81][3] = { - {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f}, - {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f}, - {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f}, - {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f}, - {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f}, - {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f}, - {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f}, - {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f}, - {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f}, - {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f}, - {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f}, - {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f}, - {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f}, - {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f}, - {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f}, - {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f}, - {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f}, - {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f}, - {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f}, - {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f}, - {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f}, - {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f}, - {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f}, - {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f}, - {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f}, - {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, - {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f}}; - float lambda_nm = stack_load_float(stack, wavelength); float ii = (lambda_nm - 380.0f) * (1.0f / 5.0f); // scaled 0..80 int i = float_to_int(ii); diff --git a/intern/cycles/kernel/tables.h b/intern/cycles/kernel/tables.h new file mode 100644 index 00000000000..768033d4ffe --- /dev/null +++ b/intern/cycles/kernel/tables.h @@ -0,0 +1,76 @@ +/* + * Copyright 2011-2013 Blender Foundation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* clang-format off */ + +ccl_inline_constant float blackbody_table_r[][3] = { + {2.52432244e+03f, -1.06185848e-03f, 3.11067539e+00f}, + {3.37763626e+03f, -4.34581697e-04f, 1.64843306e+00f}, + {4.10671449e+03f, -8.61949938e-05f, 6.41423749e-01f}, + {4.66849800e+03f, 2.85655028e-05f, 1.29075375e-01f}, + {4.60124770e+03f, 2.89727618e-05f, 1.48001316e-01f}, + {3.78765709e+03f, 9.36026367e-06f, 3.98995841e-01f} +}; + +ccl_inline_constant float blackbody_table_g[][3] = { + {-7.50343014e+02f, 3.15679613e-04f, 4.73464526e-01f}, + {-1.00402363e+03f, 1.29189794e-04f, 9.08181524e-01f}, + {-1.22075471e+03f, 2.56245413e-05f, 1.20753416e+00f}, + {-1.42546105e+03f, -4.01730887e-05f, 1.44002695e+00f}, + {-1.18134453e+03f, -2.18913373e-05f, 1.30656109e+00f}, + {-5.00279505e+02f, -4.59745390e-06f, 1.09090465e+00f} +}; + +ccl_inline_constant float blackbody_table_b[][4] = { + {0.0f, 0.0f, 0.0f, 0.0f}, /* zeros should be optimized by compiler */ + {0.0f, 0.0f, 0.0f, 0.0f}, + {0.0f, 0.0f, 0.0f, 0.0f}, + {-2.02524603e-11f, 1.79435860e-07f, -2.60561875e-04f, -1.41761141e-02f}, + {-2.22463426e-13f, -1.55078698e-08f, 3.81675160e-04f, -7.30646033e-01f}, + {6.72595954e-13f, -2.73059993e-08f, 4.24068546e-04f, -7.52204323e-01f} +}; + +ccl_inline_constant float cie_colour_match[][3] = { + {0.0014f, 0.0000f, 0.0065f}, {0.0022f, 0.0001f, 0.0105f}, {0.0042f, 0.0001f, 0.0201f}, + {0.0076f, 0.0002f, 0.0362f}, {0.0143f, 0.0004f, 0.0679f}, {0.0232f, 0.0006f, 0.1102f}, + {0.0435f, 0.0012f, 0.2074f}, {0.0776f, 0.0022f, 0.3713f}, {0.1344f, 0.0040f, 0.6456f}, + {0.2148f, 0.0073f, 1.0391f}, {0.2839f, 0.0116f, 1.3856f}, {0.3285f, 0.0168f, 1.6230f}, + {0.3483f, 0.0230f, 1.7471f}, {0.3481f, 0.0298f, 1.7826f}, {0.3362f, 0.0380f, 1.7721f}, + {0.3187f, 0.0480f, 1.7441f}, {0.2908f, 0.0600f, 1.6692f}, {0.2511f, 0.0739f, 1.5281f}, + {0.1954f, 0.0910f, 1.2876f}, {0.1421f, 0.1126f, 1.0419f}, {0.0956f, 0.1390f, 0.8130f}, + {0.0580f, 0.1693f, 0.6162f}, {0.0320f, 0.2080f, 0.4652f}, {0.0147f, 0.2586f, 0.3533f}, + {0.0049f, 0.3230f, 0.2720f}, {0.0024f, 0.4073f, 0.2123f}, {0.0093f, 0.5030f, 0.1582f}, + {0.0291f, 0.6082f, 0.1117f}, {0.0633f, 0.7100f, 0.0782f}, {0.1096f, 0.7932f, 0.0573f}, + {0.1655f, 0.8620f, 0.0422f}, {0.2257f, 0.9149f, 0.0298f}, {0.2904f, 0.9540f, 0.0203f}, + {0.3597f, 0.9803f, 0.0134f}, {0.4334f, 0.9950f, 0.0087f}, {0.5121f, 1.0000f, 0.0057f}, + {0.5945f, 0.9950f, 0.0039f}, {0.6784f, 0.9786f, 0.0027f}, {0.7621f, 0.9520f, 0.0021f}, + {0.8425f, 0.9154f, 0.0018f}, {0.9163f, 0.8700f, 0.0017f}, {0.9786f, 0.8163f, 0.0014f}, + {1.0263f, 0.7570f, 0.0011f}, {1.0567f, 0.6949f, 0.0010f}, {1.0622f, 0.6310f, 0.0008f}, + {1.0456f, 0.5668f, 0.0006f}, {1.0026f, 0.5030f, 0.0003f}, {0.9384f, 0.4412f, 0.0002f}, + {0.8544f, 0.3810f, 0.0002f}, {0.7514f, 0.3210f, 0.0001f}, {0.6424f, 0.2650f, 0.0000f}, + {0.5419f, 0.2170f, 0.0000f}, {0.4479f, 0.1750f, 0.0000f}, {0.3608f, 0.1382f, 0.0000f}, + {0.2835f, 0.1070f, 0.0000f}, {0.2187f, 0.0816f, 0.0000f}, {0.1649f, 0.0610f, 0.0000f}, + {0.1212f, 0.0446f, 0.0000f}, {0.0874f, 0.0320f, 0.0000f}, {0.0636f, 0.0232f, 0.0000f}, + {0.0468f, 0.0170f, 0.0000f}, {0.0329f, 0.0119f, 0.0000f}, {0.0227f, 0.0082f, 0.0000f}, + {0.0158f, 0.0057f, 0.0000f}, {0.0114f, 0.0041f, 0.0000f}, {0.0081f, 0.0029f, 0.0000f}, + {0.0058f, 0.0021f, 0.0000f}, {0.0041f, 0.0015f, 0.0000f}, {0.0029f, 0.0010f, 0.0000f}, + {0.0020f, 0.0007f, 0.0000f}, {0.0014f, 0.0005f, 0.0000f}, {0.0010f, 0.0004f, 0.0000f}, + {0.0007f, 0.0002f, 0.0000f}, {0.0005f, 0.0002f, 0.0000f}, {0.0003f, 0.0001f, 0.0000f}, + {0.0002f, 0.0001f, 0.0000f}, {0.0002f, 0.0001f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, + {0.0001f, 0.0000f, 0.0000f}, {0.0001f, 0.0000f, 0.0000f}, {0.0000f, 0.0000f, 0.0000f} +}; + +/* clang-format on */
\ No newline at end of file diff --git a/intern/cycles/kernel/textures.h b/intern/cycles/kernel/textures.h index 464ecb183cb..2e3ae29a19a 100644 --- a/intern/cycles/kernel/textures.h +++ b/intern/cycles/kernel/textures.h @@ -40,11 +40,11 @@ KERNEL_TEX(DecomposedTransform, __camera_motion) /* triangles */ KERNEL_TEX(uint, __tri_shader) -KERNEL_TEX(float4, __tri_vnormal) +KERNEL_TEX(packed_float3, __tri_vnormal) KERNEL_TEX(uint4, __tri_vindex) KERNEL_TEX(uint, __tri_patch) KERNEL_TEX(float2, __tri_patch_uv) -KERNEL_TEX(float4, __tri_verts) +KERNEL_TEX(packed_float3, __tri_verts) /* curves */ KERNEL_TEX(KernelCurve, __curves) @@ -58,7 +58,8 @@ KERNEL_TEX(uint, __patches) KERNEL_TEX(uint4, __attributes_map) KERNEL_TEX(float, __attributes_float) KERNEL_TEX(float2, __attributes_float2) -KERNEL_TEX(float4, __attributes_float3) +KERNEL_TEX(packed_float3, __attributes_float3) +KERNEL_TEX(float4, __attributes_float4) KERNEL_TEX(uchar4, __attributes_uchar4) /* lights */ diff --git a/intern/cycles/kernel/types.h b/intern/cycles/kernel/types.h index 2f6cadf7496..4a730dbfaaa 100644 --- a/intern/cycles/kernel/types.h +++ b/intern/cycles/kernel/types.h @@ -36,13 +36,6 @@ # define __KERNEL_CPU__ #endif -/* TODO(sergey): This is only to make it possible to include this header - * from outside of the kernel. but this could be done somewhat cleaner? - */ -#ifndef ccl_addr_space -# define ccl_addr_space -#endif - CCL_NAMESPACE_BEGIN /* Constants */ @@ -489,6 +482,16 @@ enum PanoramaType { PANORAMA_NUM_TYPES, }; +/* Direct Light Sampling */ + +enum DirectLightSamplingType { + DIRECT_LIGHT_SAMPLING_MIS = 0, + DIRECT_LIGHT_SAMPLING_FORWARD = 1, + DIRECT_LIGHT_SAMPLING_NEE = 2, + + DIRECT_LIGHT_SAMPLING_NUM, +}; + /* Differential */ typedef struct differential3 { @@ -1201,8 +1204,11 @@ typedef struct KernelIntegrator { /* Closure filter. */ int filter_closures; + /* MIS debuging */ + int direct_light_sampling_type; + /* padding */ - int pad1, pad2, pad3; + int pad1, pad2; } KernelIntegrator; static_assert_align(KernelIntegrator, 16); @@ -1426,6 +1432,7 @@ typedef struct KernelWorkTile { uint start_sample; uint num_samples; + uint sample_offset; int offset; uint stride; diff --git a/intern/cycles/scene/attribute.cpp b/intern/cycles/scene/attribute.cpp index 3401eea307f..6d15f3325f7 100644 --- a/intern/cycles/scene/attribute.cpp +++ b/intern/cycles/scene/attribute.cpp @@ -404,6 +404,10 @@ AttrKernelDataType Attribute::kernel_type(const Attribute &attr) return AttrKernelDataType::FLOAT2; } + if (attr.type == TypeFloat4 || attr.type == TypeRGBA || attr.type == TypeDesc::TypeMatrix) { + return AttrKernelDataType::FLOAT4; + } + return AttrKernelDataType::FLOAT3; } @@ -585,7 +589,7 @@ Attribute *AttributeSet::add(AttributeStandard std, ustring name) attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE); break; case ATTR_STD_MOTION_VERTEX_POSITION: - attr = add(name, TypeDesc::TypePoint, ATTR_ELEMENT_CURVE_KEY_MOTION); + attr = add(name, TypeDesc::TypeFloat4, ATTR_ELEMENT_CURVE_KEY_MOTION); break; case ATTR_STD_CURVE_INTERCEPT: attr = add(name, TypeDesc::TypeFloat, ATTR_ELEMENT_CURVE_KEY); diff --git a/intern/cycles/scene/attribute.h b/intern/cycles/scene/attribute.h index 4a25a900c14..612a0b7c80d 100644 --- a/intern/cycles/scene/attribute.h +++ b/intern/cycles/scene/attribute.h @@ -47,12 +47,7 @@ struct Transform; * * The values of this enumeration are also used as flags to detect changes in AttributeSet. */ -enum AttrKernelDataType { - FLOAT = 0, - FLOAT2 = 1, - FLOAT3 = 2, - UCHAR4 = 3, -}; +enum AttrKernelDataType { FLOAT = 0, FLOAT2 = 1, FLOAT3 = 2, FLOAT4 = 3, UCHAR4 = 4, NUM = 5 }; /* Attribute * diff --git a/intern/cycles/scene/geometry.cpp b/intern/cycles/scene/geometry.cpp index 8a3fc522d22..bf426fc49f6 100644 --- a/intern/cycles/scene/geometry.cpp +++ b/intern/cycles/scene/geometry.cpp @@ -551,6 +551,7 @@ static void update_attribute_element_size(Geometry *geom, size_t *attr_float_size, size_t *attr_float2_size, size_t *attr_float3_size, + size_t *attr_float4_size, size_t *attr_uchar4_size) { if (mattr) { @@ -569,7 +570,10 @@ static void update_attribute_element_size(Geometry *geom, *attr_float2_size += size; } else if (mattr->type == TypeDesc::TypeMatrix) { - *attr_float3_size += size * 4; + *attr_float4_size += size * 4; + } + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { + *attr_float4_size += size; } else { *attr_float3_size += size; @@ -582,8 +586,10 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, size_t &attr_float_offset, device_vector<float2> &attr_float2, size_t &attr_float2_offset, - device_vector<float4> &attr_float3, + device_vector<packed_float3> &attr_float3, size_t &attr_float3_offset, + device_vector<float4> &attr_float4, + size_t &attr_float4_offset, device_vector<uchar4> &attr_uchar4, size_t &attr_uchar4_offset, Attribute *mattr, @@ -646,18 +652,30 @@ void GeometryManager::update_attribute_element_offset(Geometry *geom, } else if (mattr->type == TypeDesc::TypeMatrix) { Transform *tfm = mattr->data_transform(); - offset = attr_float3_offset; + offset = attr_float4_offset; - assert(attr_float3.size() >= offset + size * 3); + assert(attr_float4.size() >= offset + size * 3); if (mattr->modified) { for (size_t k = 0; k < size * 3; k++) { - attr_float3[offset + k] = (&tfm->x)[k]; + attr_float4[offset + k] = (&tfm->x)[k]; } } - attr_float3_offset += size * 3; + attr_float4_offset += size * 3; } - else { + else if (mattr->type == TypeFloat4 || mattr->type == TypeRGBA) { float4 *data = mattr->data_float4(); + offset = attr_float4_offset; + + assert(attr_float4.size() >= offset + size); + if (mattr->modified) { + for (size_t k = 0; k < size; k++) { + attr_float4[offset + k] = data[k]; + } + } + attr_float4_offset += size; + } + else { + float3 *data = mattr->data_float3(); offset = attr_float3_offset; assert(attr_float3.size() >= offset + size); @@ -783,6 +801,7 @@ void GeometryManager::device_update_attributes(Device *device, size_t attr_float_size = 0; size_t attr_float2_size = 0; size_t attr_float3_size = 0; + size_t attr_float4_size = 0; size_t attr_uchar4_size = 0; for (size_t i = 0; i < scene->geometry.size(); i++) { @@ -797,6 +816,7 @@ void GeometryManager::device_update_attributes(Device *device, &attr_float_size, &attr_float2_size, &attr_float3_size, + &attr_float4_size, &attr_uchar4_size); if (geom->is_mesh()) { @@ -809,6 +829,7 @@ void GeometryManager::device_update_attributes(Device *device, &attr_float_size, &attr_float2_size, &attr_float3_size, + &attr_float4_size, &attr_uchar4_size); } } @@ -824,6 +845,7 @@ void GeometryManager::device_update_attributes(Device *device, &attr_float_size, &attr_float2_size, &attr_float3_size, + &attr_float4_size, &attr_uchar4_size); } } @@ -831,19 +853,22 @@ void GeometryManager::device_update_attributes(Device *device, dscene->attributes_float.alloc(attr_float_size); dscene->attributes_float2.alloc(attr_float2_size); dscene->attributes_float3.alloc(attr_float3_size); + dscene->attributes_float4.alloc(attr_float4_size); dscene->attributes_uchar4.alloc(attr_uchar4_size); /* The order of those flags needs to match that of AttrKernelDataType. */ - const bool attributes_need_realloc[4] = { + const bool attributes_need_realloc[AttrKernelDataType::NUM] = { dscene->attributes_float.need_realloc(), dscene->attributes_float2.need_realloc(), dscene->attributes_float3.need_realloc(), + dscene->attributes_float4.need_realloc(), dscene->attributes_uchar4.need_realloc(), }; size_t attr_float_offset = 0; size_t attr_float2_offset = 0; size_t attr_float3_offset = 0; + size_t attr_float4_offset = 0; size_t attr_uchar4_offset = 0; /* Fill in attributes. */ @@ -868,6 +893,8 @@ void GeometryManager::device_update_attributes(Device *device, attr_float2_offset, dscene->attributes_float3, attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, dscene->attributes_uchar4, attr_uchar4_offset, attr, @@ -891,6 +918,8 @@ void GeometryManager::device_update_attributes(Device *device, attr_float2_offset, dscene->attributes_float3, attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, dscene->attributes_uchar4, attr_uchar4_offset, subd_attr, @@ -923,6 +952,8 @@ void GeometryManager::device_update_attributes(Device *device, attr_float2_offset, dscene->attributes_float3, attr_float3_offset, + dscene->attributes_float4, + attr_float4_offset, dscene->attributes_uchar4, attr_uchar4_offset, attr, @@ -954,6 +985,7 @@ void GeometryManager::device_update_attributes(Device *device, dscene->attributes_float.copy_to_device_if_modified(); dscene->attributes_float2.copy_to_device_if_modified(); dscene->attributes_float3.copy_to_device_if_modified(); + dscene->attributes_float4.copy_to_device_if_modified(); dscene->attributes_uchar4.copy_to_device_if_modified(); if (progress.get_cancel()) @@ -1080,9 +1112,9 @@ void GeometryManager::device_update_mesh(Device *, /* normals */ progress.set_status("Updating Mesh", "Computing normals"); - float4 *tri_verts = dscene->tri_verts.alloc(tri_size * 3); + packed_float3 *tri_verts = dscene->tri_verts.alloc(tri_size * 3); uint *tri_shader = dscene->tri_shader.alloc(tri_size); - float4 *vnormal = dscene->tri_vnormal.alloc(vert_size); + packed_float3 *vnormal = dscene->tri_vnormal.alloc(vert_size); uint4 *tri_vindex = dscene->tri_vindex.alloc(tri_size); uint *tri_patch = dscene->tri_patch.alloc(tri_size); float2 *tri_patch_uv = dscene->tri_patch_uv.alloc(vert_size); @@ -1293,18 +1325,21 @@ enum { ATTR_FLOAT_MODIFIED = (1 << 2), ATTR_FLOAT2_MODIFIED = (1 << 3), ATTR_FLOAT3_MODIFIED = (1 << 4), - ATTR_UCHAR4_MODIFIED = (1 << 5), + ATTR_FLOAT4_MODIFIED = (1 << 5), + ATTR_UCHAR4_MODIFIED = (1 << 6), - CURVE_DATA_NEED_REALLOC = (1 << 6), - MESH_DATA_NEED_REALLOC = (1 << 7), + CURVE_DATA_NEED_REALLOC = (1 << 7), + MESH_DATA_NEED_REALLOC = (1 << 8), - ATTR_FLOAT_NEEDS_REALLOC = (1 << 8), - ATTR_FLOAT2_NEEDS_REALLOC = (1 << 9), - ATTR_FLOAT3_NEEDS_REALLOC = (1 << 10), - ATTR_UCHAR4_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT_NEEDS_REALLOC = (1 << 9), + ATTR_FLOAT2_NEEDS_REALLOC = (1 << 10), + ATTR_FLOAT3_NEEDS_REALLOC = (1 << 11), + ATTR_FLOAT4_NEEDS_REALLOC = (1 << 12), + ATTR_UCHAR4_NEEDS_REALLOC = (1 << 13), ATTRS_NEED_REALLOC = (ATTR_FLOAT_NEEDS_REALLOC | ATTR_FLOAT2_NEEDS_REALLOC | - ATTR_FLOAT3_NEEDS_REALLOC | ATTR_UCHAR4_NEEDS_REALLOC), + ATTR_FLOAT3_NEEDS_REALLOC | ATTR_FLOAT4_NEEDS_REALLOC | + ATTR_UCHAR4_NEEDS_REALLOC), DEVICE_MESH_DATA_NEEDS_REALLOC = (MESH_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), DEVICE_CURVE_DATA_NEEDS_REALLOC = (CURVE_DATA_NEED_REALLOC | ATTRS_NEED_REALLOC), }; @@ -1332,10 +1367,17 @@ static void update_device_flags_attribute(uint32_t &device_update_flags, device_update_flags |= ATTR_FLOAT3_MODIFIED; break; } + case AttrKernelDataType::FLOAT4: { + device_update_flags |= ATTR_FLOAT4_MODIFIED; + break; + } case AttrKernelDataType::UCHAR4: { device_update_flags |= ATTR_UCHAR4_MODIFIED; break; } + case AttrKernelDataType::NUM: { + break; + } } } } @@ -1352,6 +1394,9 @@ static void update_attribute_realloc_flags(uint32_t &device_update_flags, if (attributes.modified(AttrKernelDataType::FLOAT3)) { device_update_flags |= ATTR_FLOAT3_NEEDS_REALLOC; } + if (attributes.modified(AttrKernelDataType::FLOAT4)) { + device_update_flags |= ATTR_FLOAT4_NEEDS_REALLOC; + } if (attributes.modified(AttrKernelDataType::UCHAR4)) { device_update_flags |= ATTR_UCHAR4_NEEDS_REALLOC; } @@ -1553,6 +1598,14 @@ void GeometryManager::device_update_preprocess(Device *device, Scene *scene, Pro dscene->attributes_float3.tag_modified(); } + if (device_update_flags & ATTR_FLOAT4_NEEDS_REALLOC) { + dscene->attributes_map.tag_realloc(); + dscene->attributes_float4.tag_realloc(); + } + else if (device_update_flags & ATTR_FLOAT4_MODIFIED) { + dscene->attributes_float4.tag_modified(); + } + if (device_update_flags & ATTR_UCHAR4_NEEDS_REALLOC) { dscene->attributes_map.tag_realloc(); dscene->attributes_uchar4.tag_realloc(); @@ -2014,6 +2067,7 @@ void GeometryManager::device_update(Device *device, dscene->attributes_float.clear_modified(); dscene->attributes_float2.clear_modified(); dscene->attributes_float3.clear_modified(); + dscene->attributes_float4.clear_modified(); dscene->attributes_uchar4.clear_modified(); } @@ -2041,6 +2095,7 @@ void GeometryManager::device_free(Device *device, DeviceScene *dscene, bool forc dscene->attributes_float.free_if_need_realloc(force_free); dscene->attributes_float2.free_if_need_realloc(force_free); dscene->attributes_float3.free_if_need_realloc(force_free); + dscene->attributes_float4.free_if_need_realloc(force_free); dscene->attributes_uchar4.free_if_need_realloc(force_free); /* Signal for shaders like displacement not to do ray tracing. */ diff --git a/intern/cycles/scene/geometry.h b/intern/cycles/scene/geometry.h index 335bcdcd0b7..91799d7fde8 100644 --- a/intern/cycles/scene/geometry.h +++ b/intern/cycles/scene/geometry.h @@ -257,8 +257,10 @@ class GeometryManager { size_t &attr_float_offset, device_vector<float2> &attr_float2, size_t &attr_float2_offset, - device_vector<float4> &attr_float3, + device_vector<packed_float3> &attr_float3, size_t &attr_float3_offset, + device_vector<float4> &attr_float4, + size_t &attr_float4_offset, device_vector<uchar4> &attr_uchar4, size_t &attr_uchar4_offset, Attribute *mattr, diff --git a/intern/cycles/scene/image.cpp b/intern/cycles/scene/image.cpp index 80091e01b8c..8bb2d87fd1e 100644 --- a/intern/cycles/scene/image.cpp +++ b/intern/cycles/scene/image.cpp @@ -303,7 +303,6 @@ ImageManager::ImageManager(const DeviceInfo &info) animation_frame = 0; /* Set image limits */ - features.has_half_float = info.has_half_images; features.has_nanovdb = info.has_nanovdb; } @@ -357,8 +356,6 @@ void ImageManager::load_image_metadata(Image *img) metadata.detect_colorspace(); - assert(features.has_half_float || - (metadata.type != IMAGE_DATA_TYPE_HALF4 && metadata.type != IMAGE_DATA_TYPE_HALF)); assert(features.has_nanovdb || (metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT || metadata.type != IMAGE_DATA_TYPE_NANOVDB_FLOAT3)); diff --git a/intern/cycles/scene/image.h b/intern/cycles/scene/image.h index 6447b028ebf..7cf09dd6d8f 100644 --- a/intern/cycles/scene/image.h +++ b/intern/cycles/scene/image.h @@ -100,7 +100,6 @@ class ImageMetaData { /* Information about supported features that Image loaders can use. */ class ImageDeviceFeatures { public: - bool has_half_float; bool has_nanovdb; }; diff --git a/intern/cycles/scene/image_oiio.cpp b/intern/cycles/scene/image_oiio.cpp index feafae035a1..4cea7fbfb01 100644 --- a/intern/cycles/scene/image_oiio.cpp +++ b/intern/cycles/scene/image_oiio.cpp @@ -30,7 +30,8 @@ OIIOImageLoader::~OIIOImageLoader() { } -bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMetaData &metadata) +bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures & /*features*/, + ImageMetaData &metadata) { /* Perform preliminary checks, with meaningful logging. */ if (!path_exists(filepath.string())) { @@ -76,7 +77,7 @@ bool OIIOImageLoader::load_metadata(const ImageDeviceFeatures &features, ImageMe } /* check if it's half float */ - if (spec.format == TypeDesc::HALF && features.has_half_float) { + if (spec.format == TypeDesc::HALF) { is_half = true; } diff --git a/intern/cycles/scene/integrator.cpp b/intern/cycles/scene/integrator.cpp index a97833a8d32..31e645c1f3a 100644 --- a/intern/cycles/scene/integrator.cpp +++ b/intern/cycles/scene/integrator.cpp @@ -54,6 +54,18 @@ NODE_DEFINE(Integrator) SOCKET_INT(transparent_min_bounce, "Transparent Min Bounce", 0); SOCKET_INT(transparent_max_bounce, "Transparent Max Bounce", 7); +#ifdef WITH_CYCLES_DEBUG + static NodeEnum direct_light_sampling_type_enum; + direct_light_sampling_type_enum.insert("multiple_importance_sampling", + DIRECT_LIGHT_SAMPLING_MIS); + direct_light_sampling_type_enum.insert("forward_path_tracing", DIRECT_LIGHT_SAMPLING_FORWARD); + direct_light_sampling_type_enum.insert("next_event_estimation", DIRECT_LIGHT_SAMPLING_NEE); + SOCKET_ENUM(direct_light_sampling_type, + "Direct Light Sampling Type", + direct_light_sampling_type_enum, + DIRECT_LIGHT_SAMPLING_MIS); +#endif + SOCKET_INT(ao_bounces, "AO Bounces", 0); SOCKET_FLOAT(ao_factor, "AO Factor", 0.0f); SOCKET_FLOAT(ao_distance, "AO Distance", FLT_MAX); @@ -173,6 +185,12 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene kintegrator->ao_bounces_factor = ao_factor; kintegrator->ao_additive_factor = ao_additive_factor; +#ifdef WITH_CYCLES_DEBUG + kintegrator->direct_light_sampling_type = direct_light_sampling_type; +#else + kintegrator->direct_light_sampling_type = DIRECT_LIGHT_SAMPLING_MIS; +#endif + /* Transparent Shadows * We only need to enable transparent shadows, if we actually have * transparent shaders in the scene. Otherwise we can disable it diff --git a/intern/cycles/scene/integrator.h b/intern/cycles/scene/integrator.h index 464d96ca01b..52f1b296a20 100644 --- a/intern/cycles/scene/integrator.h +++ b/intern/cycles/scene/integrator.h @@ -41,6 +41,10 @@ class Integrator : public Node { NODE_SOCKET_API(int, max_transmission_bounce) NODE_SOCKET_API(int, max_volume_bounce) +#ifdef WITH_CYCLES_DEBUG + NODE_SOCKET_API(DirectLightSamplingType, direct_light_sampling_type) +#endif + NODE_SOCKET_API(int, transparent_min_bounce) NODE_SOCKET_API(int, transparent_max_bounce) diff --git a/intern/cycles/scene/mesh.cpp b/intern/cycles/scene/mesh.cpp index f47dab30869..e65b8462e34 100644 --- a/intern/cycles/scene/mesh.cpp +++ b/intern/cycles/scene/mesh.cpp @@ -707,7 +707,7 @@ void Mesh::pack_shaders(Scene *scene, uint *tri_shader) } } -void Mesh::pack_normals(float4 *vnormal) +void Mesh::pack_normals(packed_float3 *vnormal) { Attribute *attr_vN = attributes.find(ATTR_STD_VERTEX_NORMAL); if (attr_vN == NULL) { @@ -727,11 +727,14 @@ void Mesh::pack_normals(float4 *vnormal) if (do_transform) vNi = safe_normalize(transform_direction(&ntfm, vNi)); - vnormal[i] = make_float4(vNi.x, vNi.y, vNi.z, 0.0f); + vnormal[i] = make_float3(vNi.x, vNi.y, vNi.z); } } -void Mesh::pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv) +void Mesh::pack_verts(packed_float3 *tri_verts, + uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv) { size_t verts_size = verts.size(); @@ -752,9 +755,9 @@ void Mesh::pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, flo tri_patch[i] = (!get_num_subd_faces()) ? -1 : (triangle_patch[i] * 8 + patch_offset); - tri_verts[i * 3] = float3_to_float4(verts[t.v[0]]); - tri_verts[i * 3 + 1] = float3_to_float4(verts[t.v[1]]); - tri_verts[i * 3 + 2] = float3_to_float4(verts[t.v[2]]); + tri_verts[i * 3] = verts[t.v[0]]; + tri_verts[i * 3 + 1] = verts[t.v[1]]; + tri_verts[i * 3 + 2] = verts[t.v[2]]; } } diff --git a/intern/cycles/scene/mesh.h b/intern/cycles/scene/mesh.h index d13b3003164..254672d0620 100644 --- a/intern/cycles/scene/mesh.h +++ b/intern/cycles/scene/mesh.h @@ -223,8 +223,11 @@ class Mesh : public Geometry { void get_uv_tiles(ustring map, unordered_set<int> &tiles) override; void pack_shaders(Scene *scene, uint *shader); - void pack_normals(float4 *vnormal); - void pack_verts(float4 *tri_verts, uint4 *tri_vindex, uint *tri_patch, float2 *tri_patch_uv); + void pack_normals(packed_float3 *vnormal); + void pack_verts(packed_float3 *tri_verts, + uint4 *tri_vindex, + uint *tri_patch, + float2 *tri_patch_uv); void pack_patches(uint *patch_data); PrimitiveType primitive_type() const override; diff --git a/intern/cycles/scene/mesh_subdivision.cpp b/intern/cycles/scene/mesh_subdivision.cpp index a0c0bc68f8b..35f15cfafbc 100644 --- a/intern/cycles/scene/mesh_subdivision.cpp +++ b/intern/cycles/scene/mesh_subdivision.cpp @@ -331,7 +331,8 @@ struct OsdPatch : Patch { void eval(float3 *P, float3 *dPdu, float3 *dPdv, float3 *N, float u, float v) { - const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch(patch_index, u, v); + const Far::PatchTable::PatchHandle *handle = osd_data->patch_map->FindPatch( + patch_index, (double)u, (double)v); assert(handle); float p_weights[20], du_weights[20], dv_weights[20]; diff --git a/intern/cycles/scene/scene.cpp b/intern/cycles/scene/scene.cpp index ef0ee0c6625..4230abe9a1b 100644 --- a/intern/cycles/scene/scene.cpp +++ b/intern/cycles/scene/scene.cpp @@ -74,6 +74,7 @@ DeviceScene::DeviceScene(Device *device) attributes_float(device, "__attributes_float", MEM_GLOBAL), attributes_float2(device, "__attributes_float2", MEM_GLOBAL), attributes_float3(device, "__attributes_float3", MEM_GLOBAL), + attributes_float4(device, "__attributes_float4", MEM_GLOBAL), attributes_uchar4(device, "__attributes_uchar4", MEM_GLOBAL), light_distribution(device, "__light_distribution", MEM_GLOBAL), lights(device, "__lights", MEM_GLOBAL), diff --git a/intern/cycles/scene/scene.h b/intern/cycles/scene/scene.h index fa7fc54602a..4af05349dd3 100644 --- a/intern/cycles/scene/scene.h +++ b/intern/cycles/scene/scene.h @@ -81,9 +81,9 @@ class DeviceScene { device_vector<float2> prim_time; /* mesh */ - device_vector<float4> tri_verts; + device_vector<packed_float3> tri_verts; device_vector<uint> tri_shader; - device_vector<float4> tri_vnormal; + device_vector<packed_float3> tri_vnormal; device_vector<uint4> tri_vindex; device_vector<uint> tri_patch; device_vector<float2> tri_patch_uv; @@ -108,7 +108,8 @@ class DeviceScene { device_vector<uint4> attributes_map; device_vector<float> attributes_float; device_vector<float2> attributes_float2; - device_vector<float4> attributes_float3; + device_vector<packed_float3> attributes_float3; + device_vector<float4> attributes_float4; device_vector<uchar4> attributes_uchar4; /* lights */ diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 8a9ef56b0ae..8c20807a52b 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -34,6 +34,8 @@ #include "util/log.h" #include "util/transform.h" +#include "kernel/tables.h" + #include "kernel/svm/color_util.h" #include "kernel/svm/mapping_util.h" #include "kernel/svm/math_util.h" diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp index 530baa8cafb..af5c6b3f1fd 100644 --- a/intern/cycles/session/session.cpp +++ b/intern/cycles/session/session.cpp @@ -262,6 +262,7 @@ RenderWork Session::run_update_for_next_iteration() } render_scheduler_.set_num_samples(params.samples); + render_scheduler_.set_start_sample(params.sample_offset); render_scheduler_.set_time_limit(params.time_limit); while (have_tiles) { @@ -409,7 +410,7 @@ void Session::do_delayed_reset() /* Tile and work scheduling. */ tile_manager_.reset_scheduling(buffer_params_, get_effective_tile_size()); - render_scheduler_.reset(buffer_params_, params.samples); + render_scheduler_.reset(buffer_params_, params.samples, params.sample_offset); /* Passes. */ /* When multiple tiles are used SAMPLE_COUNT pass is used to keep track of possible partial diff --git a/intern/cycles/session/session.h b/intern/cycles/session/session.h index 1ec0c6e9bb1..3f73593f008 100644 --- a/intern/cycles/session/session.h +++ b/intern/cycles/session/session.h @@ -54,6 +54,7 @@ class SessionParams { bool experimental; int samples; + int sample_offset; int pixel_size; int threads; @@ -75,6 +76,7 @@ class SessionParams { experimental = false; samples = 1024; + sample_offset = 0; pixel_size = 1; threads = 0; time_limit = 0.0; diff --git a/intern/cycles/util/atomic.h b/intern/cycles/util/atomic.h index faba411c769..afc3fd019df 100644 --- a/intern/cycles/util/atomic.h +++ b/intern/cycles/util/atomic.h @@ -63,6 +63,62 @@ ccl_device_inline float atomic_compare_and_swap_float(volatile float *dest, # endif /* __KERNEL_CUDA__ */ +# ifdef __KERNEL_METAL__ + +// global address space versions +ccl_device_inline float atomic_add_and_fetch_float(volatile ccl_global float *_source, + const float operand) +{ + volatile ccl_global atomic_int *source = (ccl_global atomic_int *)_source; + union { + int int_value; + float float_value; + } new_value, prev_value; + prev_value.int_value = atomic_load_explicit(source, memory_order_relaxed); + do { + new_value.float_value = prev_value.float_value + operand; + } while (!atomic_compare_exchange_weak_explicit(source, + &prev_value.int_value, + new_value.int_value, + memory_order_relaxed, + memory_order_relaxed)); + + return new_value.float_value; +} + +# define atomic_fetch_and_add_uint32(p, x) \ + atomic_fetch_add_explicit((device atomic_uint *)p, x, memory_order_relaxed) +# define atomic_fetch_and_sub_uint32(p, x) \ + atomic_fetch_sub_explicit((device atomic_uint *)p, x, memory_order_relaxed) +# define atomic_fetch_and_inc_uint32(p) \ + atomic_fetch_add_explicit((device atomic_uint *)p, 1, memory_order_relaxed) +# define atomic_fetch_and_dec_uint32(p) \ + atomic_fetch_sub_explicit((device atomic_uint *)p, 1, memory_order_relaxed) +# define atomic_fetch_and_or_uint32(p, x) \ + atomic_fetch_or_explicit((device atomic_uint *)p, x, memory_order_relaxed) + +ccl_device_inline float atomic_compare_and_swap_float(volatile ccl_global float *dest, + const float old_val, + const float new_val) +{ + int prev_value; + prev_value = __float_as_int(old_val); + atomic_compare_exchange_weak_explicit((ccl_global atomic_int *)dest, + &prev_value, + __float_as_int(new_val), + memory_order_relaxed, + memory_order_relaxed); + return __int_as_float(prev_value); +} + +# define atomic_store(p, x) atomic_store_explicit(p, x, memory_order_relaxed) +# define atomic_fetch(p) atomic_load_explicit(p, memory_order_relaxed) + +# define CCL_LOCAL_MEM_FENCE mem_flags::mem_threadgroup +# define ccl_barrier(flags) threadgroup_barrier(flags) + +# endif /* __KERNEL_METAL__ */ + #endif /* __KERNEL_GPU__ */ #endif /* __UTIL_ATOMIC_H__ */ diff --git a/intern/cycles/util/debug.cpp b/intern/cycles/util/debug.cpp index 7d5b6d4e54e..717e55a2c9a 100644 --- a/intern/cycles/util/debug.cpp +++ b/intern/cycles/util/debug.cpp @@ -64,6 +64,11 @@ DebugFlags::HIP::HIP() : adaptive_compile(false) reset(); } +DebugFlags::Metal::Metal() : adaptive_compile(false) +{ + reset(); +} + void DebugFlags::CUDA::reset() { if (getenv("CYCLES_CUDA_ADAPTIVE_COMPILE") != NULL) @@ -76,6 +81,12 @@ void DebugFlags::HIP::reset() adaptive_compile = true; } +void DebugFlags::Metal::reset() +{ + if (getenv("CYCLES_METAL_ADAPTIVE_COMPILE") != NULL) + adaptive_compile = true; +} + DebugFlags::OptiX::OptiX() { reset(); @@ -97,6 +108,7 @@ void DebugFlags::reset() cpu.reset(); cuda.reset(); optix.reset(); + metal.reset(); } CCL_NAMESPACE_END diff --git a/intern/cycles/util/debug.h b/intern/cycles/util/debug.h index 548c67600e5..1e431fde68a 100644 --- a/intern/cycles/util/debug.h +++ b/intern/cycles/util/debug.h @@ -116,6 +116,17 @@ class DebugFlags { bool use_debug; }; + /* Descriptor of Metal feature-set to be used. */ + struct Metal { + Metal(); + + /* Reset flags to their defaults. */ + void reset(); + + /* Whether adaptive feature based runtime compile is enabled or not.*/ + bool adaptive_compile; + }; + /* Get instance of debug flags registry. */ static DebugFlags &get() { @@ -138,6 +149,9 @@ class DebugFlags { /* Requested HIP flags. */ HIP hip; + /* Requested Metal flags. */ + Metal metal; + private: DebugFlags(); diff --git a/intern/cycles/util/defines.h b/intern/cycles/util/defines.h index a778bef52b2..a2e8d83adb7 100644 --- a/intern/cycles/util/defines.h +++ b/intern/cycles/util/defines.h @@ -44,6 +44,7 @@ # if defined(_WIN32) && !defined(FREE_WINDOWS) # define ccl_device_inline static __forceinline # define ccl_device_forceinline static __forceinline +# define ccl_device_inline_method __forceinline # define ccl_align(...) __declspec(align(__VA_ARGS__)) # ifdef __KERNEL_64_BIT__ # define ccl_try_align(...) __declspec(align(__VA_ARGS__)) @@ -58,6 +59,7 @@ # else /* _WIN32 && !FREE_WINDOWS */ # define ccl_device_inline static inline __attribute__((always_inline)) # define ccl_device_forceinline static inline __attribute__((always_inline)) +# define ccl_device_inline_method __attribute__((always_inline)) # define ccl_align(...) __attribute__((aligned(__VA_ARGS__))) # ifndef FREE_WINDOWS64 # define __forceinline inline __attribute__((always_inline)) @@ -70,7 +72,7 @@ /* Address spaces for GPU. */ # define ccl_global -# define ccl_static_constant static const +# define ccl_inline_constant inline constexpr # define ccl_constant const # define ccl_private diff --git a/intern/cycles/util/half.h b/intern/cycles/util/half.h index 016975e3c25..555f17259bd 100644 --- a/intern/cycles/util/half.h +++ b/intern/cycles/util/half.h @@ -28,8 +28,27 @@ CCL_NAMESPACE_BEGIN /* Half Floats */ +#if defined(__KERNEL_METAL__) + +ccl_device_inline float half_to_float(half h_in) +{ + float f; + union { + half h; + uint16_t s; + } val; + val.h = h_in; + + *((ccl_private int *)&f) = ((val.s & 0x8000) << 16) | (((val.s & 0x7c00) + 0x1C000) << 13) | + ((val.s & 0x03FF) << 13); + + return f; +} + +#else + /* CUDA has its own half data type, no need to define then */ -#if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__) +# if !defined(__KERNEL_CUDA__) && !defined(__KERNEL_HIP__) /* Implementing this as a class rather than a typedef so that the compiler can tell it apart from * unsigned shorts. */ class half { @@ -53,11 +72,12 @@ class half { private: unsigned short v; }; -#endif +# endif struct half4 { half x, y, z, w; }; +#endif /* Conversion to/from half float for image textures * @@ -66,7 +86,9 @@ struct half4 { ccl_device_inline half float_to_half_image(float f) { -#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) +#if defined(__KERNEL_METAL__) + return half(f); +#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) return __float2half(f); #else const uint u = __float_as_uint(f); @@ -92,7 +114,9 @@ ccl_device_inline half float_to_half_image(float f) ccl_device_inline float half_to_float_image(half h) { -#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) +#if defined(__KERNEL_METAL__) + return half_to_float(h); +#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) return __half2float(h); #else const int x = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); @@ -125,7 +149,9 @@ ccl_device_inline float4 half4_to_float4_image(const half4 h) ccl_device_inline half float_to_half_display(const float f) { -#if defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) +#if defined(__KERNEL_METAL__) + return half(f); +#elif defined(__KERNEL_CUDA__) || defined(__KERNEL_HIP__) return __float2half(f); #else const int x = __float_as_int((f > 0.0f) ? ((f < 65504.0f) ? f : 65504.0f) : 0.0f); diff --git a/intern/cycles/util/ies.cpp b/intern/cycles/util/ies.cpp index 5e879478df5..e924d660407 100644 --- a/intern/cycles/util/ies.cpp +++ b/intern/cycles/util/ies.cpp @@ -23,10 +23,10 @@ CCL_NAMESPACE_BEGIN -// NOTE: For some reason gcc-7.2 does not instantiate this versio of allocator -// gere (used in IESTextParser). Works fine for gcc-6, gcc-7.3 and gcc-8. +// NOTE: For some reason gcc-7.2 does not instantiate this version of the +// allocator here (used in IESTextParser). Works fine for gcc-6, gcc-7.3 and gcc-8. // -// TODO(sergey): Get to the root of this issue, or confirm this i a compiler +// TODO(sergey): Get to the root of this issue, or confirm this is a compiler // issue. template class GuardedAllocator<char>; diff --git a/intern/cycles/util/math.h b/intern/cycles/util/math.h index e4c7df6e44a..6cfeb1aa917 100644 --- a/intern/cycles/util/math.h +++ b/intern/cycles/util/math.h @@ -30,9 +30,11 @@ # include <hip/hip_vector_types.h> #endif -#include <float.h> -#include <math.h> -#include <stdio.h> +#if !defined(__KERNEL_METAL__) +# include <float.h> +# include <math.h> +# include <stdio.h> +#endif /* !defined(__KERNEL_METAL__) */ #include "util/types.h" @@ -174,6 +176,7 @@ ccl_device_inline float max4(float a, float b, float c, float d) return max(max(a, b), max(c, d)); } +#if !defined(__KERNEL_METAL__) /* Int/Float conversion */ ccl_device_inline int as_int(uint i) @@ -206,7 +209,7 @@ ccl_device_inline uint as_uint(float f) return u.i; } -#ifndef __HIP__ +# ifndef __HIP__ ccl_device_inline int __float_as_int(float f) { union { @@ -246,28 +249,33 @@ ccl_device_inline float __uint_as_float(uint i) u.i = i; return u.f; } -#endif +# endif ccl_device_inline int4 __float4_as_int4(float4 f) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int4(_mm_castps_si128(f.m128)); -#else +# else return make_int4( __float_as_int(f.x), __float_as_int(f.y), __float_as_int(f.z), __float_as_int(f.w)); -#endif +# endif } ccl_device_inline float4 __int4_as_float4(int4 i) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_castsi128_ps(i.m128)); -#else +# else return make_float4( __int_as_float(i.x), __int_as_float(i.y), __int_as_float(i.z), __int_as_float(i.w)); -#endif +# endif } +#endif /* !defined(__KERNEL_METAL__) */ +#if defined(__KERNEL_METAL__) +# define isnan_safe(v) isnan(v) +# define isfinite_safe(v) isfinite(v) +#else template<typename T> ccl_device_inline uint pointer_pack_to_uint_0(T *ptr) { return ((uint64_t)ptr) & 0xFFFFFFFF; @@ -311,12 +319,14 @@ ccl_device_inline bool isfinite_safe(float f) unsigned int x = __float_as_uint(f); return (f == f) && (x == 0 || x == (1u << 31) || (f != 2.0f * f)) && !((x << 1) > 0xff000000u); } +#endif ccl_device_inline float ensure_finite(float v) { return isfinite_safe(v) ? v : 0.0f; } +#if !defined(__KERNEL_METAL__) ccl_device_inline int clamp(int a, int mn, int mx) { return min(max(a, mn), mx); @@ -346,15 +356,17 @@ ccl_device_inline float smoothstep(float edge0, float edge1, float x) return result; } -#ifndef __KERNEL_CUDA__ +#endif /* !defined(__KERNEL_METAL__) */ + +#if defined(__KERNEL_CUDA__) ccl_device_inline float saturatef(float a) { - return clamp(a, 0.0f, 1.0f); + return __saturatef(a); } -#else +#elif !defined(__KERNEL_METAL__) ccl_device_inline float saturatef(float a) { - return __saturatef(a); + return clamp(a, 0.0f, 1.0f); } #endif /* __KERNEL_CUDA__ */ @@ -491,6 +503,7 @@ CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN +#if !defined(__KERNEL_METAL__) /* Interpolation */ template<class A, class B> A lerp(const A &a, const A &b, const B &t) @@ -498,6 +511,8 @@ template<class A, class B> A lerp(const A &a, const A &b, const B &t) return (A)(a * ((B)1 - t) + b * t); } +#endif /* __KERNEL_METAL__ */ + /* Triangle */ ccl_device_inline float triangle_area(ccl_private const float3 &v1, @@ -627,7 +642,11 @@ ccl_device_inline float safe_sqrtf(float f) ccl_device_inline float inversesqrtf(float f) { +#if defined(__KERNEL_METAL__) + return (f > 0.0f) ? rsqrt(f) : 0.0f; +#else return (f > 0.0f) ? 1.0f / sqrtf(f) : 0.0f; +#endif } ccl_device float safe_asinf(float a) @@ -715,10 +734,30 @@ ccl_device float bits_to_01(uint bits) return bits * (1.0f / (float)0xFFFFFFFF); } +#if !defined(__KERNEL_GPU__) +# if defined(__GNUC__) +# define popcount(x) __builtin_popcount(x) +# else +ccl_device_inline uint popcount(uint x) +{ + /* TODO(Stefan): pop-count intrinsic for Windows with fallback for older CPUs. */ + uint i = x & 0xaaaaaaaa; + i = i - ((i >> 1) & 0x55555555); + i = (i & 0x33333333) + ((i >> 2) & 0x33333333); + i = (((i + (i >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; + return i & 1; +} +# endif +#elif !defined(__KERNEL_METAL__) +# define popcount(x) __popc(x) +#endif + ccl_device_inline uint count_leading_zeros(uint x) { #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__) return __clz(x); +#elif defined(__KERNEL_METAL__) + return clz(x); #else assert(x != 0); # ifdef _MSC_VER @@ -735,6 +774,8 @@ ccl_device_inline uint count_trailing_zeros(uint x) { #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__) return (__ffs(x) - 1); +#elif defined(__KERNEL_METAL__) + return ctz(x); #else assert(x != 0); # ifdef _MSC_VER @@ -751,6 +792,8 @@ ccl_device_inline uint find_first_set(uint x) { #if defined(__KERNEL_CUDA__) || defined(__KERNEL_OPTIX__) || defined(__KERNEL_HIP__) return __ffs(x); +#elif defined(__KERNEL_METAL__) + return (x != 0) ? ctz(x) + 1 : 0; #else # ifdef _MSC_VER return (x != 0) ? (32 - count_leading_zeros(x & (-x))) : 0; @@ -801,7 +844,7 @@ ccl_device_inline float2 map_to_sphere(const float3 co) * https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ */ -ccl_device_inline float compare_floats(float a, float b, float abs_diff, int ulp_diff) +ccl_device_inline bool compare_floats(float a, float b, float abs_diff, int ulp_diff) { if (fabsf(a - b) < abs_diff) { return true; @@ -849,6 +892,8 @@ ccl_device_inline uint32_t reverse_integer_bits(uint32_t x) return x; #elif defined(__KERNEL_CUDA__) return __brev(x); +#elif defined(__KERNEL_METAL__) + return reverse_bits(x); #elif __has_builtin(__builtin_bitreverse32) return __builtin_bitreverse32(x); #else diff --git a/intern/cycles/util/math_float2.h b/intern/cycles/util/math_float2.h index 87141d5bc37..8ff75c6c20a 100644 --- a/intern/cycles/util/math_float2.h +++ b/intern/cycles/util/math_float2.h @@ -27,6 +27,7 @@ CCL_NAMESPACE_BEGIN * Declaration. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline float2 operator-(const float2 &a); ccl_device_inline float2 operator*(const float2 &a, const float2 &b); ccl_device_inline float2 operator*(const float2 &a, float f); @@ -63,6 +64,7 @@ ccl_device_inline float2 fabs(const float2 &a); ccl_device_inline float2 as_float2(const float4 &a); ccl_device_inline float2 interp(const float2 &a, const float2 &b, float t); ccl_device_inline float2 floor(const float2 &a); +#endif /* !__KERNEL_METAL__ */ ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b); @@ -80,6 +82,7 @@ ccl_device_inline float2 one_float2() return make_float2(1.0f, 1.0f); } +#if !defined(__KERNEL_METAL__) ccl_device_inline float2 operator-(const float2 &a) { return make_float2(-a.x, -a.y); @@ -259,6 +262,8 @@ ccl_device_inline float2 floor(const float2 &a) return make_float2(floorf(a.x), floorf(a.y)); } +#endif /* !__KERNEL_METAL__ */ + ccl_device_inline float2 safe_divide_float2_float(const float2 a, const float b) { return (b != 0.0f) ? a / b : zero_float2(); diff --git a/intern/cycles/util/math_float3.h b/intern/cycles/util/math_float3.h index 81550c5d03c..1a0213f2a6d 100644 --- a/intern/cycles/util/math_float3.h +++ b/intern/cycles/util/math_float3.h @@ -27,6 +27,7 @@ CCL_NAMESPACE_BEGIN * Declaration. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline float3 operator-(const float3 &a); ccl_device_inline float3 operator*(const float3 &a, const float3 &b); ccl_device_inline float3 operator*(const float3 &a, const float f); @@ -62,19 +63,20 @@ ccl_device_inline float3 rcp(const float3 &a); ccl_device_inline float3 sqrt(const float3 &a); ccl_device_inline float3 floor(const float3 &a); ccl_device_inline float3 ceil(const float3 &a); +ccl_device_inline float3 reflect(const float3 incident, const float3 normal); +#endif /* !defined(__KERNEL_METAL__) */ ccl_device_inline float min3(float3 a); ccl_device_inline float max3(float3 a); ccl_device_inline float len(const float3 a); ccl_device_inline float len_squared(const float3 a); -ccl_device_inline float3 reflect(const float3 incident, const float3 normal); ccl_device_inline float3 project(const float3 v, const float3 v_proj); ccl_device_inline float3 saturate3(float3 a); ccl_device_inline float3 safe_normalize(const float3 a); -ccl_device_inline float3 normalize_len(const float3 a, float *t); -ccl_device_inline float3 safe_normalize_len(const float3 a, float *t); +ccl_device_inline float3 normalize_len(const float3 a, ccl_private float *t); +ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t); ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b); ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b); ccl_device_inline float3 interp(float3 a, float3 b, float t); @@ -103,49 +105,58 @@ ccl_device_inline float3 one_float3() return make_float3(1.0f, 1.0f, 1.0f); } +#if defined(__KERNEL_METAL__) + +ccl_device_inline float3 rcp(float3 a) +{ + return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z); +} + +#else + ccl_device_inline float3 operator-(const float3 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000)))); -#else +# else return make_float3(-a.x, -a.y, -a.z); -#endif +# endif } ccl_device_inline float3 operator*(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_mul_ps(a.m128, b.m128)); -#else +# else return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); -#endif +# endif } ccl_device_inline float3 operator*(const float3 &a, const float f) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_mul_ps(a.m128, _mm_set1_ps(f))); -#else +# else return make_float3(a.x * f, a.y * f, a.z * f); -#endif +# endif } ccl_device_inline float3 operator*(const float f, const float3 &a) { -#if defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE__) return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128)); -#else +# else return make_float3(a.x * f, a.y * f, a.z * f); -#endif +# endif } ccl_device_inline float3 operator/(const float f, const float3 &a) { -#if defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE__) return float3(_mm_div_ps(_mm_set1_ps(f), a.m128)); -#else +# else return make_float3(f / a.x, f / a.y, f / a.z); -#endif +# endif } ccl_device_inline float3 operator/(const float3 &a, const float f) @@ -156,11 +167,11 @@ ccl_device_inline float3 operator/(const float3 &a, const float f) ccl_device_inline float3 operator/(const float3 &a, const float3 &b) { -#if defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE__) return float3(_mm_div_ps(a.m128, b.m128)); -#else +# else return make_float3(a.x / b.x, a.y / b.y, a.z / b.z); -#endif +# endif } ccl_device_inline float3 operator+(const float3 &a, const float f) @@ -170,11 +181,11 @@ ccl_device_inline float3 operator+(const float3 &a, const float f) ccl_device_inline float3 operator+(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_add_ps(a.m128, b.m128)); -#else +# else return make_float3(a.x + b.x, a.y + b.y, a.z + b.z); -#endif +# endif } ccl_device_inline float3 operator-(const float3 &a, const float f) @@ -184,11 +195,11 @@ ccl_device_inline float3 operator-(const float3 &a, const float f) ccl_device_inline float3 operator-(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_sub_ps(a.m128, b.m128)); -#else +# else return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); -#endif +# endif } ccl_device_inline float3 operator+=(float3 &a, const float3 &b) @@ -222,13 +233,39 @@ ccl_device_inline float3 operator/=(float3 &a, float f) return a = a * invf; } +#if !(defined(__KERNEL_METAL__) || defined(__KERNEL_CUDA__)) +ccl_device_inline packed_float3 operator*=(packed_float3 &a, const float3 &b) +{ + a = float3(a) * b; + return a; +} + +ccl_device_inline packed_float3 operator*=(packed_float3 &a, float f) +{ + a = float3(a) * f; + return a; +} + +ccl_device_inline packed_float3 operator/=(packed_float3 &a, const float3 &b) +{ + a = float3(a) / b; + return a; +} + +ccl_device_inline packed_float3 operator/=(packed_float3 &a, float f) +{ + a = float3(a) / f; + return a; +} +#endif + ccl_device_inline bool operator==(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 7) == 7; -#else +# else return (a.x == b.x && a.y == b.y && a.z == b.z); -#endif +# endif } ccl_device_inline bool operator!=(const float3 &a, const float3 &b) @@ -243,20 +280,20 @@ ccl_device_inline float distance(const float3 &a, const float3 &b) ccl_device_inline float dot(const float3 &a, const float3 &b) { -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F)); -#else +# else return a.x * b.x + a.y * b.y + a.z * b.z; -#endif +# endif } ccl_device_inline float dot_xy(const float3 &a, const float3 &b) { -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) return _mm_cvtss_f32(_mm_hadd_ps(_mm_mul_ps(a, b), b)); -#else +# else return a.x * b.x + a.y * b.y; -#endif +# endif } ccl_device_inline float3 cross(const float3 &a, const float3 &b) @@ -267,30 +304,30 @@ ccl_device_inline float3 cross(const float3 &a, const float3 &b) ccl_device_inline float3 normalize(const float3 &a) { -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F)); return float3(_mm_div_ps(a.m128, norm)); -#else +# else return a / len(a); -#endif +# endif } ccl_device_inline float3 min(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_min_ps(a.m128, b.m128)); -#else +# else return make_float3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); -#endif +# endif } ccl_device_inline float3 max(const float3 &a, const float3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_max_ps(a.m128, b.m128)); -#else +# else return make_float3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); -#endif +# endif } ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 &mx) @@ -300,43 +337,43 @@ ccl_device_inline float3 clamp(const float3 &a, const float3 &mn, const float3 & ccl_device_inline float3 fabs(const float3 &a) { -#ifdef __KERNEL_SSE__ -# ifdef __KERNEL_NEON__ +# ifdef __KERNEL_SSE__ +# ifdef __KERNEL_NEON__ return float3(vabsq_f32(a.m128)); -# else +# else __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)); return float3(_mm_and_ps(a.m128, mask)); -# endif -#else +# endif +# else return make_float3(fabsf(a.x), fabsf(a.y), fabsf(a.z)); -#endif +# endif } ccl_device_inline float3 sqrt(const float3 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_sqrt_ps(a)); -#else +# else return make_float3(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z)); -#endif +# endif } ccl_device_inline float3 floor(const float3 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_floor_ps(a)); -#else +# else return make_float3(floorf(a.x), floorf(a.y), floorf(a.z)); -#endif +# endif } ccl_device_inline float3 ceil(const float3 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float3(_mm_ceil_ps(a)); -#else +# else return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z)); -#endif +# endif } ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t) @@ -346,13 +383,14 @@ ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t) ccl_device_inline float3 rcp(const float3 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ /* Don't use _mm_rcp_ps due to poor precision. */ return float3(_mm_div_ps(_mm_set_ps1(1.0f), a.m128)); -#else +# else return make_float3(1.0f / a.x, 1.0f / a.y, 1.0f / a.z); -#endif +# endif } +#endif /* !__KERNEL_METAL__ */ ccl_device_inline float min3(float3 a) { @@ -378,6 +416,7 @@ ccl_device_inline float len_squared(const float3 a) return dot(a, a); } +#if !defined(__KERNEL_METAL__) ccl_device_inline float3 reflect(const float3 incident, const float3 normal) { float3 unit_normal = normalize(normal); @@ -399,6 +438,7 @@ ccl_device_inline float3 faceforward(const float3 vector, { return (dot(reference, incident) < 0.0f) ? vector : -vector; } +#endif ccl_device_inline float3 project(const float3 v, const float3 v_proj) { @@ -479,7 +519,11 @@ ccl_device_inline float average(const float3 a) ccl_device_inline bool isequal_float3(const float3 a, const float3 b) { +#if defined(__KERNEL_METAL__) + return all(a == b); +#else return a == b; +#endif } ccl_device_inline float3 pow3(float3 v, float e) diff --git a/intern/cycles/util/math_float4.h b/intern/cycles/util/math_float4.h index c76959ee7ff..1203a10cca4 100644 --- a/intern/cycles/util/math_float4.h +++ b/intern/cycles/util/math_float4.h @@ -27,6 +27,7 @@ CCL_NAMESPACE_BEGIN * Declaration. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline float4 operator-(const float4 &a); ccl_device_inline float4 operator*(const float4 &a, const float4 &b); ccl_device_inline float4 operator*(const float4 &a, float f); @@ -65,6 +66,7 @@ ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 & ccl_device_inline float4 fabs(const float4 &a); ccl_device_inline float4 floor(const float4 &a); ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t); +#endif /* !__KERNEL_METAL__*/ ccl_device_inline float4 safe_divide_float4_float(const float4 a, const float b); @@ -110,32 +112,33 @@ ccl_device_inline float4 one_float4() return make_float4(1.0f, 1.0f, 1.0f, 1.0f); } +#if !defined(__KERNEL_METAL__) ccl_device_inline float4 operator-(const float4 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x80000000)); return float4(_mm_xor_ps(a.m128, mask)); -#else +# else return make_float4(-a.x, -a.y, -a.z, -a.w); -#endif +# endif } ccl_device_inline float4 operator*(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_mul_ps(a.m128, b.m128)); -#else +# else return make_float4(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w); -#endif +# endif } ccl_device_inline float4 operator*(const float4 &a, float f) { -#if defined(__KERNEL_SSE__) +# if defined(__KERNEL_SSE__) return a * make_float4(f); -#else +# else return make_float4(a.x * f, a.y * f, a.z * f, a.w * f); -#endif +# endif } ccl_device_inline float4 operator*(float f, const float4 &a) @@ -150,11 +153,11 @@ ccl_device_inline float4 operator/(const float4 &a, float f) ccl_device_inline float4 operator/(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_div_ps(a.m128, b.m128)); -#else +# else return make_float4(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w); -#endif +# endif } ccl_device_inline float4 operator+(const float4 &a, const float f) @@ -164,11 +167,11 @@ ccl_device_inline float4 operator+(const float4 &a, const float f) ccl_device_inline float4 operator+(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_add_ps(a.m128, b.m128)); -#else +# else return make_float4(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); -#endif +# endif } ccl_device_inline float4 operator-(const float4 &a, const float f) @@ -178,11 +181,11 @@ ccl_device_inline float4 operator-(const float4 &a, const float f) ccl_device_inline float4 operator-(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_sub_ps(a.m128, b.m128)); -#else +# else return make_float4(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); -#endif +# endif } ccl_device_inline float4 operator+=(float4 &a, const float4 &b) @@ -212,38 +215,38 @@ ccl_device_inline float4 operator/=(float4 &a, float f) ccl_device_inline int4 operator<(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int4(_mm_castps_si128(_mm_cmplt_ps(a.m128, b.m128))); -#else +# else return make_int4(a.x < b.x, a.y < b.y, a.z < b.z, a.w < b.w); -#endif +# endif } ccl_device_inline int4 operator>=(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int4(_mm_castps_si128(_mm_cmpge_ps(a.m128, b.m128))); -#else +# else return make_int4(a.x >= b.x, a.y >= b.y, a.z >= b.z, a.w >= b.w); -#endif +# endif } ccl_device_inline int4 operator<=(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int4(_mm_castps_si128(_mm_cmple_ps(a.m128, b.m128))); -#else +# else return make_int4(a.x <= b.x, a.y <= b.y, a.z <= b.z, a.w <= b.w); -#endif +# endif } ccl_device_inline bool operator==(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 15) == 15; -#else +# else return (a.x == b.x && a.y == b.y && a.z == b.z && a.w == b.w); -#endif +# endif } ccl_device_inline float distance(const float4 &a, const float4 &b) @@ -253,16 +256,16 @@ ccl_device_inline float distance(const float4 &a, const float4 &b) ccl_device_inline float dot(const float4 &a, const float4 &b) { -#if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) -# if defined(__KERNEL_NEON__) +# if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__) +# if defined(__KERNEL_NEON__) __m128 t = vmulq_f32(a, b); return vaddvq_f32(t); -# else +# else return _mm_cvtss_f32(_mm_dp_ps(a, b, 0xFF)); -# endif -#else +# endif +# else return (a.x * b.x + a.y * b.y) + (a.z * b.z + a.w * b.w); -#endif +# endif } ccl_device_inline float len_squared(const float4 &a) @@ -272,21 +275,21 @@ ccl_device_inline float len_squared(const float4 &a) ccl_device_inline float4 rcp(const float4 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ /* Don't use _mm_rcp_ps due to poor precision. */ return float4(_mm_div_ps(_mm_set_ps1(1.0f), a.m128)); -#else +# else return make_float4(1.0f / a.x, 1.0f / a.y, 1.0f / a.z, 1.0f / a.w); -#endif +# endif } ccl_device_inline float4 sqrt(const float4 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_sqrt_ps(a.m128)); -#else +# else return make_float4(sqrtf(a.x), sqrtf(a.y), sqrtf(a.z), sqrtf(a.w)); -#endif +# endif } ccl_device_inline float4 sqr(const float4 &a) @@ -296,39 +299,39 @@ ccl_device_inline float4 sqr(const float4 &a) ccl_device_inline float4 cross(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return (shuffle<1, 2, 0, 0>(a) * shuffle<2, 0, 1, 0>(b)) - (shuffle<2, 0, 1, 0>(a) * shuffle<1, 2, 0, 0>(b)); -#else +# else return make_float4(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x, 0.0f); -#endif +# endif } ccl_device_inline bool is_zero(const float4 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return a == make_float4(0.0f); -#else +# else return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f && a.w == 0.0f); -#endif +# endif } ccl_device_inline float4 reduce_add(const float4 &a) { -#if defined(__KERNEL_SSE__) -# if defined(__KERNEL_NEON__) +# if defined(__KERNEL_SSE__) +# if defined(__KERNEL_NEON__) return float4(vdupq_n_f32(vaddvq_f32(a))); -# elif defined(__KERNEL_SSE3__) +# elif defined(__KERNEL_SSE3__) float4 h(_mm_hadd_ps(a.m128, a.m128)); return float4(_mm_hadd_ps(h.m128, h.m128)); -# else +# else float4 h(shuffle<1, 0, 3, 2>(a) + a); return shuffle<2, 3, 0, 1>(h) + h; -# endif -#else +# endif +# else float sum = (a.x + a.y) + (a.z + a.w); return make_float4(sum, sum, sum, sum); -#endif +# endif } ccl_device_inline float average(const float4 &a) @@ -354,20 +357,20 @@ ccl_device_inline float4 safe_normalize(const float4 &a) ccl_device_inline float4 min(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_min_ps(a.m128, b.m128)); -#else +# else return make_float4(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z), min(a.w, b.w)); -#endif +# endif } ccl_device_inline float4 max(const float4 &a, const float4 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_max_ps(a.m128, b.m128)); -#else +# else return make_float4(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z), max(a.w, b.w)); -#endif +# endif } ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 &mx) @@ -377,24 +380,24 @@ ccl_device_inline float4 clamp(const float4 &a, const float4 &mn, const float4 & ccl_device_inline float4 fabs(const float4 &a) { -#if defined(__KERNEL_SSE__) -# if defined(__KERNEL_NEON__) +# if defined(__KERNEL_SSE__) +# if defined(__KERNEL_NEON__) return float4(vabsq_f32(a)); -# else +# else return float4(_mm_and_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff)))); -# endif -#else +# endif +# else return make_float4(fabsf(a.x), fabsf(a.y), fabsf(a.z), fabsf(a.w)); -#endif +# endif } ccl_device_inline float4 floor(const float4 &a) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return float4(_mm_floor_ps(a)); -#else +# else return make_float4(floorf(a.x), floorf(a.y), floorf(a.z), floorf(a.w)); -#endif +# endif } ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t) @@ -402,6 +405,8 @@ ccl_device_inline float4 mix(const float4 &a, const float4 &b, float t) return a + t * (b - a); } +#endif /* !__KERNEL_METAL__*/ + #ifdef __KERNEL_SSE__ template<size_t index_0, size_t index_1, size_t index_2, size_t index_3> __forceinline const float4 shuffle(const float4 &b) diff --git a/intern/cycles/util/math_int2.h b/intern/cycles/util/math_int2.h index 5b04be92152..39dc3b28f11 100644 --- a/intern/cycles/util/math_int2.h +++ b/intern/cycles/util/math_int2.h @@ -27,17 +27,20 @@ CCL_NAMESPACE_BEGIN * Declaration. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline bool operator==(const int2 a, const int2 b); ccl_device_inline int2 operator+(const int2 &a, const int2 &b); ccl_device_inline int2 operator+=(int2 &a, const int2 &b); ccl_device_inline int2 operator-(const int2 &a, const int2 &b); ccl_device_inline int2 operator*(const int2 &a, const int2 &b); ccl_device_inline int2 operator/(const int2 &a, const int2 &b); +#endif /* !__KERNEL_METAL__ */ /******************************************************************************* * Definition. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline bool operator==(const int2 a, const int2 b) { return (a.x == b.x && a.y == b.y); @@ -67,6 +70,7 @@ ccl_device_inline int2 operator/(const int2 &a, const int2 &b) { return make_int2(a.x / b.x, a.y / b.y); } +#endif /* !__KERNEL_METAL__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/math_int3.h b/intern/cycles/util/math_int3.h index 128f2cb53b8..a09c68ef49a 100644 --- a/intern/cycles/util/math_int3.h +++ b/intern/cycles/util/math_int3.h @@ -27,49 +27,52 @@ CCL_NAMESPACE_BEGIN * Declaration. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline int3 min(int3 a, int3 b); ccl_device_inline int3 max(int3 a, int3 b); ccl_device_inline int3 clamp(const int3 &a, int mn, int mx); ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx); +#endif /* !defined(__KERNEL_METAL__) */ /******************************************************************************* * Definition. */ +#if !defined(__KERNEL_METAL__) ccl_device_inline int3 min(int3 a, int3 b) { -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) +# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) return int3(_mm_min_epi32(a.m128, b.m128)); -#else +# else return make_int3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z)); -#endif +# endif } ccl_device_inline int3 max(int3 a, int3 b) { -#if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) +# if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE41__) return int3(_mm_max_epi32(a.m128, b.m128)); -#else +# else return make_int3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z)); -#endif +# endif } ccl_device_inline int3 clamp(const int3 &a, int mn, int mx) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return min(max(a, make_int3(mn)), make_int3(mx)); -#else +# else return make_int3(clamp(a.x, mn, mx), clamp(a.y, mn, mx), clamp(a.z, mn, mx)); -#endif +# endif } ccl_device_inline int3 clamp(const int3 &a, int3 &mn, int mx) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return min(max(a, mn), make_int3(mx)); -#else +# else return make_int3(clamp(a.x, mn.x, mx), clamp(a.y, mn.y, mx), clamp(a.z, mn.z, mx)); -#endif +# endif } ccl_device_inline bool operator==(const int3 &a, const int3 &b) @@ -89,21 +92,22 @@ ccl_device_inline bool operator<(const int3 &a, const int3 &b) ccl_device_inline int3 operator+(const int3 &a, const int3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int3(_mm_add_epi32(a.m128, b.m128)); -#else +# else return make_int3(a.x + b.x, a.y + b.y, a.z + b.z); -#endif +# endif } ccl_device_inline int3 operator-(const int3 &a, const int3 &b) { -#ifdef __KERNEL_SSE__ +# ifdef __KERNEL_SSE__ return int3(_mm_sub_epi32(a.m128, b.m128)); -#else +# else return make_int3(a.x - b.x, a.y - b.y, a.z - b.z); -#endif +# endif } +#endif /* !__KERNEL_METAL__ */ CCL_NAMESPACE_END diff --git a/intern/cycles/util/math_intersect.h b/intern/cycles/util/math_intersect.h index 0c431a36afb..54ce3ab4b66 100644 --- a/intern/cycles/util/math_intersect.h +++ b/intern/cycles/util/math_intersect.h @@ -88,29 +88,16 @@ ccl_device bool ray_aligned_disk_intersect(float3 ray_P, ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P, float3 ray_dir, float ray_t, -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - const ssef *ssef_verts, -#else const float3 tri_a, const float3 tri_b, const float3 tri_c, -#endif ccl_private float *isect_u, ccl_private float *isect_v, ccl_private float *isect_t) { -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - typedef ssef float3; - const float3 tri_a(ssef_verts[0]); - const float3 tri_b(ssef_verts[1]); - const float3 tri_c(ssef_verts[2]); - const float3 P(ray_P); - const float3 dir(ray_dir); -#else -# define dot3(a, b) dot(a, b) +#define dot3(a, b) dot(a, b) const float3 P = ray_P; const float3 dir = ray_dir; -#endif /* Calculate vertices relative to ray origin. */ const float3 v0 = tri_c - P; @@ -123,43 +110,16 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P, const float3 e2 = v1 - v2; /* Perform edge tests. */ -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - const float3 crossU = cross(v2 + v0, e0); - const float3 crossV = cross(v0 + v1, e1); - const float3 crossW = cross(v1 + v2, e2); - - ssef crossX(crossU); - ssef crossY(crossV); - ssef crossZ(crossW); - ssef zero = _mm_setzero_ps(); - _MM_TRANSPOSE4_PS(crossX, crossY, crossZ, zero); - - const ssef dirX(ray_dir.x); - const ssef dirY(ray_dir.y); - const ssef dirZ(ray_dir.z); - - ssef UVWW = madd(crossX, dirX, madd(crossY, dirY, crossZ * dirZ)); -#else /* __KERNEL_SSE2__ */ const float U = dot(cross(v2 + v0, e0), ray_dir); const float V = dot(cross(v0 + v1, e1), ray_dir); const float W = dot(cross(v1 + v2, e2), ray_dir); -#endif /* __KERNEL_SSE2__ */ -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - int uvw_sign = movemask(UVWW) & 0x7; - if (uvw_sign != 0) { - if (uvw_sign != 0x7) { - return false; - } - } -#else const float minUVW = min(U, min(V, W)); const float maxUVW = max(U, max(V, W)); if (minUVW < 0.0f && maxUVW > 0.0f) { return false; } -#endif /* Calculate geometry normal and denominator. */ const float3 Ng1 = cross(e1, e0); @@ -180,14 +140,8 @@ ccl_device_forceinline bool ray_triangle_intersect(float3 ray_P, } const float inv_den = 1.0f / den; -#if defined(__KERNEL_SSE2__) && defined(__KERNEL_SSE__) - UVWW *= inv_den; - _mm_store_ss(isect_u, UVWW); - _mm_store_ss(isect_v, shuffle<1, 1, 3, 3>(UVWW)); -#else *isect_u = U * inv_den; *isect_v = V * inv_den; -#endif *isect_t = T * inv_den; return true; diff --git a/intern/cycles/util/math_matrix.h b/intern/cycles/util/math_matrix.h index bff7ddb4cee..c1be71517e3 100644 --- a/intern/cycles/util/math_matrix.h +++ b/intern/cycles/util/math_matrix.h @@ -162,7 +162,7 @@ ccl_device_inline void math_trimatrix_add_gramian(ccl_global float *A, { for (int row = 0; row < n; row++) { for (int col = 0; col <= row; col++) { - MATHS(A, row, col, 1) += v[row] * v[col] * weight; + atomic_add_and_fetch_float(&MATHS(A, row, col, 1), v[row] * v[col] * weight); } } } diff --git a/intern/cycles/util/path.cpp b/intern/cycles/util/path.cpp index 5704c4ef8ef..aad790482d5 100644 --- a/intern/cycles/util/path.cpp +++ b/intern/cycles/util/path.cpp @@ -313,7 +313,7 @@ static char *path_specials(const string &sub) if (env_shader_path != NULL && sub == "shader") { return env_shader_path; } - else if (env_shader_path != NULL && sub == "source") { + else if (env_source_path != NULL && sub == "source") { return env_source_path; } return NULL; @@ -541,7 +541,7 @@ static string path_make_compatible(const string &path) if ((path.size() >= 3) && (path[0] == DIR_SEP) && (path[1] == DIR_SEP)) { result = path_cleanup_unc(result); } - /* Make sure volume-only path ends up wit ha directory separator. */ + /* Make sure volume-only path ends up wit a directory separator. */ if (result.size() == 2 && result[1] == ':') { result += DIR_SEP; } diff --git a/intern/cycles/util/progress.h b/intern/cycles/util/progress.h index f2d80e49ab8..15bd26d34bf 100644 --- a/intern/cycles/util/progress.h +++ b/intern/cycles/util/progress.h @@ -207,7 +207,7 @@ class Progress { if (total_pixel_samples > 0) { return ((double)pixel_samples) / (double)total_pixel_samples; } - return 0.0f; + return 0.0; } void add_samples(uint64_t pixel_samples_, int tile_sample) diff --git a/intern/cycles/util/ssef.h b/intern/cycles/util/ssef.h index ea5e78b54d2..fc496e55a0c 100644 --- a/intern/cycles/util/ssef.h +++ b/intern/cycles/util/ssef.h @@ -906,7 +906,7 @@ __forceinline void store4f_nt(void *ptr, const ssef &v) } //////////////////////////////////////////////////////////////////////////////// -/// Euclidian Space Operators +/// Euclidean Space Operators //////////////////////////////////////////////////////////////////////////////// __forceinline float dot(const ssef &a, const ssef &b) diff --git a/intern/cycles/util/transform.h b/intern/cycles/util/transform.h index 7bfe747fcfb..1d78dfd1385 100644 --- a/intern/cycles/util/transform.h +++ b/intern/cycles/util/transform.h @@ -53,6 +53,15 @@ typedef struct DecomposedTransform { /* Functions */ +#ifdef __KERNEL_METAL__ +/* transform_point specialized for ccl_global */ +ccl_device_inline float3 transform_point(ccl_global const Transform *t, const float3 a) +{ + ccl_global const float3x3 &b(*(ccl_global const float3x3 *)t); + return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w); +} +#endif + ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a) { /* TODO(sergey): Disabled for now, causes crashes in certain cases. */ @@ -73,6 +82,9 @@ ccl_device_inline float3 transform_point(ccl_private const Transform *t, const f tmp += w; return float3(tmp.m128); +#elif defined(__KERNEL_METAL__) + ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t); + return (a * b).xyz + make_float3(t->x.w, t->y.w, t->z.w); #else float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z + t->x.w, a.x * t->y.x + a.y * t->y.y + a.z * t->y.z + t->y.w, @@ -99,6 +111,9 @@ ccl_device_inline float3 transform_direction(ccl_private const Transform *t, con tmp = madd(shuffle<2>(aa), z, tmp); return float3(tmp.m128); +#elif defined(__KERNEL_METAL__) + ccl_private const float3x3 &b(*(ccl_private const float3x3 *)t); + return (a * b).xyz; #else float3 c = make_float3(a.x * t->x.x + a.y * t->x.y + a.z * t->x.z, a.x * t->y.x + a.y * t->y.y + a.z * t->y.z, @@ -450,8 +465,8 @@ ccl_device_inline void transform_compose(ccl_private Transform *tfm, } /* Interpolate from array of decomposed transforms. */ -ccl_device void transform_motion_array_interpolate(Transform *tfm, - const DecomposedTransform *motion, +ccl_device void transform_motion_array_interpolate(ccl_private Transform *tfm, + ccl_global const DecomposedTransform *motion, uint numsteps, float time) { @@ -460,8 +475,8 @@ ccl_device void transform_motion_array_interpolate(Transform *tfm, int step = min((int)(time * maxstep), maxstep - 1); float t = time * maxstep - step; - const DecomposedTransform *a = motion + step; - const DecomposedTransform *b = motion + step + 1; + ccl_global const DecomposedTransform *a = motion + step; + ccl_global const DecomposedTransform *b = motion + step + 1; /* Interpolate rotation, translation and scale. */ DecomposedTransform decomp; diff --git a/intern/cycles/util/types.h b/intern/cycles/util/types.h index 697dc2b44ea..58a6d134819 100644 --- a/intern/cycles/util/types.h +++ b/intern/cycles/util/types.h @@ -17,7 +17,9 @@ #ifndef __UTIL_TYPES_H__ #define __UTIL_TYPES_H__ -#include <stdlib.h> +#if !defined(__KERNEL_METAL__) +# include <stdlib.h> +#endif /* Standard Integer Types */ diff --git a/intern/cycles/util/types_float3.h b/intern/cycles/util/types_float3.h index f990367e7b8..cafcfebf526 100644 --- a/intern/cycles/util/types_float3.h +++ b/intern/cycles/util/types_float3.h @@ -55,6 +55,41 @@ ccl_device_inline float3 make_float3(float x, float y, float z); ccl_device_inline void print_float3(const char *label, const float3 &a); #endif /* __KERNEL_GPU__ */ +/* Smaller float3 for storage. For math operations this must be converted to float3, so that on the + * CPU SIMD instructions can be used. */ +#if defined(__KERNEL_METAL__) +/* Metal has native packed_float3. */ +#elif defined(__KERNEL_CUDA__) +/* CUDA float3 is already packed. */ +typedef float3 packed_float3; +#else +/* HIP float3 is not packed (https://github.com/ROCm-Developer-Tools/HIP/issues/706). */ +struct packed_float3 { + ccl_device_inline_method packed_float3(){}; + + ccl_device_inline_method packed_float3(const float3 &a) : x(a.x), y(a.y), z(a.z) + { + } + + ccl_device_inline_method operator float3() const + { + return make_float3(x, y, z); + } + + ccl_device_inline_method packed_float3 &operator=(const float3 &a) + { + x = a.x; + y = a.y; + z = a.z; + return *this; + } + + float x, y, z; +}; +#endif + +static_assert(sizeof(packed_float3) == 12, "packed_float3 expected to be exactly 12 bytes"); + CCL_NAMESPACE_END #endif /* __UTIL_TYPES_FLOAT3_H__ */ diff --git a/intern/ghost/GHOST_C-api.h b/intern/ghost/GHOST_C-api.h index 784febe8581..98094cc0669 100644 --- a/intern/ghost/GHOST_C-api.h +++ b/intern/ghost/GHOST_C-api.h @@ -729,13 +729,6 @@ extern GHOST_TSuccess GHOST_ReleaseOpenGLContext(GHOST_ContextHandle contexthand extern unsigned int GHOST_GetContextDefaultOpenGLFramebuffer(GHOST_ContextHandle contexthandle); /** - * Returns whether a context is rendered upside down compared to OpenGL. This only needs to be - * called if there's a non-OpenGL context, which is really the exception. - * So generally, this does not need to be called. - */ -extern int GHOST_isUpsideDownContext(GHOST_ContextHandle contexthandle); - -/** * Get the OpenGL frame-buffer handle that serves as a default frame-buffer. */ extern unsigned int GHOST_GetDefaultOpenGLFramebuffer(GHOST_WindowHandle windwHandle); diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 2c8014a08cc..ce0185bc7d0 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -654,8 +654,8 @@ enum { GHOST_kXrContextDebug = (1 << 0), GHOST_kXrContextDebugTime = (1 << 1), # ifdef WIN32 - /* Needed to avoid issues with the SteamVR OpenGL graphics binding (use DirectX fallback - instead). */ + /* Needed to avoid issues with the SteamVR OpenGL graphics binding + * (use DirectX fallback instead). */ GHOST_kXrContextGpuNVIDIA = (1 << 2), # endif }; diff --git a/intern/ghost/intern/GHOST_SystemCocoa.mm b/intern/ghost/intern/GHOST_SystemCocoa.mm index 204bbdaec50..b92c3e73a88 100644 --- a/intern/ghost/intern/GHOST_SystemCocoa.mm +++ b/intern/ghost/intern/GHOST_SystemCocoa.mm @@ -1245,7 +1245,7 @@ GHOST_TSuccess GHOST_SystemCocoa::handleDraggingEvent(GHOST_TEventType eventType /* Convert the image in a RGBA 32bit format */ /* As Core Graphics does not support contexts with non premutliplied alpha, - we need to get alpha key values in a separate batch */ + * we need to get alpha key values in a separate batch */ /* First get RGB values w/o Alpha to avoid pre-multiplication, * 32bit but last byte is unused */ @@ -1479,8 +1479,8 @@ GHOST_TSuccess GHOST_SystemCocoa::handleMouseEvent(void *eventPtr) CocoaWindow *cocoawindow; /* [event window] returns other windows if mouse-over, that's OSX input standard - however, if mouse exits window(s), the windows become inactive, until you click. - We then fall back to the active window from ghost */ + * however, if mouse exits window(s), the windows become inactive, until you click. + * We then fall back to the active window from ghost. */ window = (GHOST_WindowCocoa *)m_windowManager->getWindowAssociatedWithOSWindow( (void *)[event window]); if (!window) { diff --git a/intern/ghost/intern/GHOST_XrAction.cpp b/intern/ghost/intern/GHOST_XrAction.cpp index 704b1ce9fac..f51f98c9b3d 100644 --- a/intern/ghost/intern/GHOST_XrAction.cpp +++ b/intern/ghost/intern/GHOST_XrAction.cpp @@ -216,8 +216,9 @@ GHOST_XrAction::GHOST_XrAction(XrInstance instance, XrActionCreateInfo action_info{XR_TYPE_ACTION_CREATE_INFO}; strcpy(action_info.actionName, info.name); - strcpy(action_info.localizedActionName, info.name); /* Just use same name for localized. This can - be changed in the future if necessary. */ + + /* Just use same name for localized. This can be changed in the future if necessary. */ + strcpy(action_info.localizedActionName, info.name); switch (info.type) { case GHOST_kXrActionTypeBooleanInput: diff --git a/intern/ghost/intern/GHOST_XrControllerModel.cpp b/intern/ghost/intern/GHOST_XrControllerModel.cpp index ae15bf11aa0..27f92ffe7c5 100644 --- a/intern/ghost/intern/GHOST_XrControllerModel.cpp +++ b/intern/ghost/intern/GHOST_XrControllerModel.cpp @@ -97,8 +97,8 @@ static void read_vertices(const tinygltf::Accessor &accessor, validate_accessor(accessor, buffer_view, buffer, stride, packed_size); /* Resize the vertices vector, if necessary, to include room for the attribute data. - If there are multiple attributes for a primitive, the first one will resize, and the - subsequent will not need to. */ + * If there are multiple attributes for a primitive, the first one will resize, and the + * subsequent will not need to. */ primitive.vertices.resize(accessor.count); /* Copy the attribute value over from the glTF buffer into the appropriate vertex field. */ @@ -147,9 +147,9 @@ static void read_indices(const tinygltf::Accessor &accessor, const tinygltf::Buffer &buffer, GHOST_XrPrimitive &primitive) { - if (buffer_view.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER && - buffer_view.target != 0) { /* Allow 0 (not specified) even though spec doesn't seem to allow - this (BoomBox GLB fails). */ + + /* Allow 0 (not specified) even though spec doesn't seem to allow this (BoomBox GLB fails). */ + if (buffer_view.target != TINYGLTF_TARGET_ELEMENT_ARRAY_BUFFER && buffer_view.target != 0) { throw GHOST_XrException( "glTF: Accessor for indices uses bufferview with invalid 'target' type."); } @@ -164,8 +164,8 @@ static void read_indices(const tinygltf::Accessor &accessor, validate_accessor(accessor, buffer_view, buffer, component_size_bytes, component_size_bytes); - if ((accessor.count % 3) != 0) { /* Since only triangles are supported, enforce that the number - of indices is divisible by 3. */ + /* Since only triangles are supported, enforce that the number of indices is divisible by 3. */ + if ((accessor.count % 3) != 0) { throw GHOST_XrException("glTF: Unexpected number of indices for triangle primitive"); } diff --git a/intern/guardedalloc/MEM_guardedalloc.h b/intern/guardedalloc/MEM_guardedalloc.h index 713b1fac788..874abb88ff5 100644 --- a/intern/guardedalloc/MEM_guardedalloc.h +++ b/intern/guardedalloc/MEM_guardedalloc.h @@ -78,7 +78,8 @@ extern short (*MEM_testN)(void *vmemh); /** * Duplicates a block of memory, and returns a pointer to the - * newly allocated block. */ + * newly allocated block. + * NULL-safe; will return NULL when receiving a NULL pointer. */ extern void *(*MEM_dupallocN)(const void *vmemh) /* ATTR_MALLOC */ ATTR_WARN_UNUSED_RESULT; /** diff --git a/intern/locale/boost_locale_wrapper.cpp b/intern/locale/boost_locale_wrapper.cpp index ede9377b38f..444b51b5e04 100644 --- a/intern/locale/boost_locale_wrapper.cpp +++ b/intern/locale/boost_locale_wrapper.cpp @@ -26,8 +26,8 @@ static std::string messages_path; static std::string default_domain; static std::string locale_str; -/* Note: We cannot use short stuff like boost::locale::gettext, because those return - * std::basic_string objects, which c_ptr()-returned char* is no more valid +/* NOTE: We cannot use short stuff like `boost::locale::gettext`, because those return + * `std::basic_string` objects, which c_ptr()-returned char* is no more valid * once deleted (which happens as soons they are out of scope of this func). */ typedef boost::locale::message_format<char> char_message_facet; static std::locale locale_global; @@ -63,7 +63,7 @@ static void bl_locale_global_cache() void bl_locale_init(const char *_messages_path, const char *_default_domain) { - // Avoid using ICU backend, we do not need its power and it's rather heavy! + /* Avoid using ICU backend, we do not need its power and it's rather heavy! */ boost::locale::localization_backend_manager lman = boost::locale::localization_backend_manager::global(); #if defined(_WIN32) @@ -81,7 +81,7 @@ void bl_locale_set(const char *locale) { boost::locale::generator gen; std::locale _locale; - // Specify location of dictionaries. + /* Specify location of dictionaries. */ gen.add_messages_path(messages_path); gen.add_messages_domain(default_domain); // gen.set_default_messages_domain(default_domain); @@ -99,12 +99,12 @@ void bl_locale_set(const char *locale) #endif } std::locale::global(_locale); - // Note: boost always uses "C" LC_NUMERIC by default! + /* NOTE: boost always uses "C" LC_NUMERIC by default! */ bl_locale_global_cache(); - // Generate the locale string - // (useful to know which locale we are actually using in case of "default" one). + /* Generate the locale string + * (useful to know which locale we are actually using in case of "default" one). */ #define LOCALE_INFO std::use_facet<boost::locale::info>(_locale) locale_str = LOCALE_INFO.language(); @@ -117,10 +117,9 @@ void bl_locale_set(const char *locale) #undef LOCALE_INFO } - // Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions - // like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are - // not caught by their ancestor `std::exception`. See - // https://developer.blender.org/T88877#1177108 . + /* Extra catch on `std::runtime_error` is needed for macOS/Clang as it seems that exceptions + * like `boost::locale::conv::conversion_error` (which inherit from `std::runtime_error`) are + * not caught by their ancestor `std::exception`. See T88877#1177108 */ catch (std::runtime_error const &e) { std::cout << "bl_locale_set(" << locale << "): " << e.what() << " \n"; } diff --git a/intern/sky/include/sky_model.h b/intern/sky/include/sky_model.h index 983b90fed35..752b5c13785 100644 --- a/intern/sky/include/sky_model.h +++ b/intern/sky/include/sky_model.h @@ -133,7 +133,7 @@ function which generates skydome states for different solar emission spectra and solar radii: 'arhosekskymodelstate_alienworld_alloc_init()'. See the notes about the "Alien World" functionality provided further down for a -discussion of the usefulness and limits of that second initalisation function. +discussion of the usefulness and limits of that second initialisation function. Sky model states that have been initialized with either function behave in a completely identical fashion during use and cleanup. @@ -368,7 +368,7 @@ SKY_ArHosekSkyModelState *SKY_arhosekskymodelstate_alloc_init(const double solar with a sun of a surface temperature given in 'kelvin'. The parameter 'solar_intensity' controls the overall brightness of the sky, relative to the solar irradiance on Earth. A value of 1.0 yields a sky dome that - is, on average over the wavelenghts covered in the model (!), as bright + is, on average over the wavelengths covered in the model (!), as bright as the terrestrial sky in radiometric terms. Which means that the solar radius has to be adjusted, since the diff --git a/release/datafiles/colormanagement/config.ocio b/release/datafiles/colormanagement/config.ocio index bb9fd27fb84..bd342a0577e 100644 --- a/release/datafiles/colormanagement/config.ocio +++ b/release/datafiles/colormanagement/config.ocio @@ -42,7 +42,7 @@ roles: # For interop between configs, and to determine XYZ for rendering aces_interchange: Linear ACES - # Specifed by OCIO, not used in Blender + # Specified by OCIO, not used in Blender color_timing: Filmic Log compositing_log: Filmic Log default: Linear diff --git a/release/datafiles/locale b/release/datafiles/locale -Subproject 6178bad247c69c9c4e1a98c5f35765752341b3a +Subproject 24c2b84192564c2c06a9ab98d8e310433266c2a diff --git a/release/datafiles/splash.png b/release/datafiles/splash.png Binary files differindex 74e239b0f98..7189380bbd9 100644 --- a/release/datafiles/splash.png +++ b/release/datafiles/splash.png diff --git a/release/datafiles/userdef/userdef_default_theme.c b/release/datafiles/userdef/userdef_default_theme.c index da01f65131c..055a2e37c6c 100644 --- a/release/datafiles/userdef/userdef_default_theme.c +++ b/release/datafiles/userdef/userdef_default_theme.c @@ -647,7 +647,7 @@ const bTheme U_theme_default = { .facedot_size = 4, .movie = RGBA(0x4d6890ff), .movieclip = RGBA(0x8f4c4cff), - .mask = RGBA(0x666666ff), + .mask = RGBA(0x8f5656ff), .image = RGBA(0x8f744bff), .scene = RGBA(0x808033ff), .audio = RGBA(0x448080ff), diff --git a/release/freedesktop/snap/README.md b/release/freedesktop/snap/README.md index 742b265ada6..f6c662e9f1e 100644 --- a/release/freedesktop/snap/README.md +++ b/release/freedesktop/snap/README.md @@ -12,6 +12,6 @@ Build pipeline snap tracks and channels - Test builds for the upcoming stable release - *not used for now* <track>/beta - Nightly automated builds provided by a release branch - <track>/egde/<branch> + <track>/edge/<branch> - Nightly or on demand builds - will also make use of branch ``` diff --git a/release/lts/create_release_notes.py b/release/lts/create_release_notes.py index 2a396dca6b0..2d35a71c263 100755 --- a/release/lts/create_release_notes.py +++ b/release/lts/create_release_notes.py @@ -97,7 +97,7 @@ def extract_release_notes(version: str, task_id: int): # Process - 1. Retrieval of description of the gived `task_id`. + 1. Retrieval of description of the given `task_id`. 2. Find rows for the given `version` and convert to `ReleaseLogLine`. 3. based on the associated task or commit retrieves the title of the log line. diff --git a/release/scripts/addons b/release/scripts/addons -Subproject f6107e2fd9a92b55ac110c7db941e287e2f6604 +Subproject 4de1bcce5a2caa31131c40cc19f0a1851c2eb63 diff --git a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py index 00edd7d523d..cf904a1a88b 100644 --- a/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py +++ b/release/scripts/modules/bl_i18n_utils/bl_extract_messages.py @@ -877,7 +877,7 @@ def dump_messages(do_messages, do_checks, settings): addons = utils.enable_addons(support={"OFFICIAL"}) # Note this is not needed if we have been started with factory settings, but just in case... # XXX This is not working well, spent a whole day trying to understand *why* we still have references of - # those removed calsses in things like `bpy.types.OperatorProperties.__subclasses__()` + # those removed classes in things like `bpy.types.OperatorProperties.__subclasses__()` # (could not even reproduce it from regular py console in Blender with UI...). # For some reasons, cleanup does not happen properly, *and* we have no way to tell which class is valid # and which has been unregistered. So for now, just go for the dirty, easy way: do not disable add-ons. :( diff --git a/release/scripts/modules/bl_i18n_utils/utils.py b/release/scripts/modules/bl_i18n_utils/utils.py index 13fb87d386a..e13eb15dfd2 100644 --- a/release/scripts/modules/bl_i18n_utils/utils.py +++ b/release/scripts/modules/bl_i18n_utils/utils.py @@ -778,7 +778,7 @@ class I18nMessages: try: import bpy except ModuleNotFoundError: - print("Could not import bpy, find_best_messages_matches must be run from whithin Blender.") + print("Could not import bpy, find_best_messages_matches must be run from within Blender.") return # Build helper mappings. diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index 3f0248970c6..b009c38edb4 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -26,6 +26,7 @@ not associated with blenders internal data. __all__ = ( "blend_paths", "escape_identifier", + "flip_name", "unescape_identifier", "keyconfig_init", "keyconfig_set", @@ -61,6 +62,7 @@ from _bpy import ( _utils_units as units, blend_paths, escape_identifier, + flip_name, unescape_identifier, register_class, resource_path, @@ -106,7 +108,7 @@ def execfile(filepath, *, mod=None): mod_orig = modules.get(mod_name, None) modules[mod_name] = mod - # No error supression, just ensure `sys.modules[mod_name]` is properly restored in the case of an error. + # No error suppression, just ensure `sys.modules[mod_name]` is properly restored in the case of an error. try: mod_spec.loader.exec_module(mod) finally: diff --git a/release/scripts/modules/bpy_types.py b/release/scripts/modules/bpy_types.py index 26efb6e3307..b477f624b7b 100644 --- a/release/scripts/modules/bpy_types.py +++ b/release/scripts/modules/bpy_types.py @@ -720,7 +720,7 @@ class Gizmo(StructRNA): # Dummy class to keep the reference in `bpy_types_dict` and avoid -# erros like: "TypeError: expected GizmoGroup subclass of class ..." +# errors like: "TypeError: expected GizmoGroup subclass of class ..." class GizmoGroup(StructRNA): __slots__ = () diff --git a/release/scripts/presets/keyconfig/Blender.py b/release/scripts/presets/keyconfig/Blender.py index 35c920b3f40..1ac7626f926 100644 --- a/release/scripts/presets/keyconfig/Blender.py +++ b/release/scripts/presets/keyconfig/Blender.py @@ -202,7 +202,7 @@ class Prefs(bpy.types.KeyConfigPreferences): update=update_fn, ) - # Developer note, this is an experemental option. + # Developer note, this is an experimental option. use_pie_click_drag: BoolProperty( name="Pie Menu on Drag", description=( diff --git a/release/scripts/presets/keyconfig/keymap_data/blender_default.py b/release/scripts/presets/keyconfig/keymap_data/blender_default.py index d6032a3ecce..dbc93cb6caa 100644 --- a/release/scripts/presets/keyconfig/keymap_data/blender_default.py +++ b/release/scripts/presets/keyconfig/keymap_data/blender_default.py @@ -1097,6 +1097,7 @@ def km_outliner(params): # Fall through to generic context menu if the item(s) selected have no type specific actions. ("outliner.operation", {"type": 'RIGHTMOUSE', "value": 'PRESS'}, None), op_menu("OUTLINER_MT_context_menu", {"type": 'RIGHTMOUSE', "value": 'PRESS'}), + op_menu_pie("OUTLINER_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY'}, None), ("outliner.item_drag_drop", {"type": 'EVT_TWEAK_L', "value": 'ANY', "shift": True}, None), ("outliner.show_hierarchy", {"type": 'HOME', "value": 'PRESS'}, None), @@ -1748,6 +1749,7 @@ def km_graph_editor(params): ("graph.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), ("graph.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ("graph.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + op_menu_pie("GRAPH_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("graph.fmodifier_add", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, {"properties": [("only_active", False)]}), ("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None), @@ -1815,6 +1817,7 @@ def km_image_generic(params): ("image.cycle_render_slot", {"type": 'J', "value": 'PRESS', "repeat": True}, None), ("image.cycle_render_slot", {"type": 'J', "value": 'PRESS', "alt": True, "repeat": True}, {"properties": [("reverse", True)]}), + op_menu_pie("IMAGE_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ]) if not params.legacy: @@ -2027,6 +2030,7 @@ def km_node_editor(params): ("node.view_all", {"type": 'HOME', "value": 'PRESS'}, None), ("node.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), ("node.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), + op_menu_pie("NODE_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("node.delete", {"type": 'X', "value": 'PRESS'}, None), ("node.delete", {"type": 'DEL', "value": 'PRESS'}, None), ("node.delete_reconnect", {"type": 'X', "value": 'PRESS', "ctrl": True}, None), @@ -2389,6 +2393,7 @@ def km_dopesheet(params): ("action.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), ("action.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ("action.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + op_menu_pie("DOPESHEET_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("anim.channels_editable_toggle", {"type": 'TAB', "value": 'PRESS'}, None), ("anim.channels_select_filter", {"type": 'F', "value": 'PRESS', "ctrl": True}, None), ("transform.transform", {"type": 'G', "value": 'PRESS'}, @@ -2503,6 +2508,7 @@ def km_nla_editor(params): ("nla.view_all", {"type": 'NDOF_BUTTON_FIT', "value": 'PRESS'}, None), ("nla.view_selected", {"type": 'NUMPAD_PERIOD', "value": 'PRESS'}, None), ("nla.view_frame", {"type": 'NUMPAD_0', "value": 'PRESS'}, None), + op_menu_pie("NLA_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("nla.actionclip_add", {"type": 'A', "value": 'PRESS', "shift": True}, None), ("nla.transition_add", {"type": 'T', "value": 'PRESS', "shift": True}, None), ("nla.soundclip_add", {"type": 'K', "value": 'PRESS', "shift": True}, None), @@ -2835,6 +2841,7 @@ def km_sequencer(params): ("sequencer.select_grouped", {"type": 'G', "value": 'PRESS', "shift": True}, None), op_menu("SEQUENCER_MT_add", {"type": 'A', "value": 'PRESS', "shift": True}), op_menu("SEQUENCER_MT_change", {"type": 'C', "value": 'PRESS'}), + op_menu_pie("SEQUENCER_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ("sequencer.slip", {"type": 'S', "value": 'PRESS'}, None), ("wm.context_set_int", {"type": 'O', "value": 'PRESS'}, {"properties": [("data_path", 'scene.sequence_editor.overlay_frame'), ("value", 0)]}), @@ -2892,6 +2899,7 @@ def km_sequencerpreview(params): {"properties": [("ratio", 0.25)]}), ("sequencer.view_zoom_ratio", {"type": 'NUMPAD_8', "value": 'PRESS'}, {"properties": [("ratio", 0.125)]}), + op_menu_pie("SEQUENCER_MT_preview_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), # Edit. ("transform.translate", {"type": params.select_tweak, "value": 'ANY'}, None), @@ -3042,6 +3050,7 @@ def km_clip(_params): op_menu_pie("CLIP_MT_solving_pie", {"type": 'S', "value": 'PRESS', "shift": True}), op_menu_pie("CLIP_MT_marker_pie", {"type": 'E', "value": 'PRESS', "shift": True}), op_menu_pie("CLIP_MT_reconstruction_pie", {"type": 'W', "value": 'PRESS', "shift": True}), + op_menu_pie("CLIP_MT_view_pie", {"type": 'ACCENT_GRAVE', "value": 'PRESS'}), ]) return keymap diff --git a/release/scripts/startup/bl_operators/userpref.py b/release/scripts/startup/bl_operators/userpref.py index 67a02f6e1f4..1363bcf60e4 100644 --- a/release/scripts/startup/bl_operators/userpref.py +++ b/release/scripts/startup/bl_operators/userpref.py @@ -100,14 +100,6 @@ class PREFERENCES_OT_copy_prev(Operator): version_new = ((version[0] * 100) + version[1]) version_old = ((version[0] * 100) + version[1]) - 1 - # Special case, remove when the version is > 3.0. - if version_new == 300: - version_new = 294 - version_old = 293 - else: - print("TODO: remove exception!") - # End special case. - # Ensure we only try to copy files from a point release. # The check below ensures the second numbers match. while (version_new % 100) // 10 == (version_old % 100) // 10: diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 28bb0a58c02..d9ea991f976 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1030,7 +1030,7 @@ class WM_OT_url_open_preset(Operator): "Report a bug in an add-on"), _url_from_bug_addon), (('RELEASE_NOTES', "Release Notes", - "Read about whats new in this version of Blender"), + "Read about what's new in this version of Blender"), _url_from_release_notes), (('MANUAL', "Manual", "The reference manual for this version of Blender"), @@ -1430,7 +1430,7 @@ class WM_OT_properties_edit(Operator): type_items = rna_custom_property_type_items subtype_items = rna_vector_subtype_items - # Helper method to avoid repetative code to retrieve a single value from sequences and non-sequences. + # Helper method to avoid repetitive code to retrieve a single value from sequences and non-sequences. @staticmethod def _convert_new_value_single(old_value, new_type): if hasattr(old_value, "__len__") and len(old_value) > 0: diff --git a/release/scripts/startup/bl_ui/properties_data_gpencil.py b/release/scripts/startup/bl_ui/properties_data_gpencil.py index 793c4a52350..34e83573bc9 100644 --- a/release/scripts/startup/bl_ui/properties_data_gpencil.py +++ b/release/scripts/startup/bl_ui/properties_data_gpencil.py @@ -110,7 +110,8 @@ class GPENCIL_MT_layer_context_menu(Menu): layout.separator() - layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down") + layout.operator("gpencil.layer_merge", icon='SORT_ASC', text="Merge Down").mode = 'ACTIVE' + layout.operator("gpencil.layer_merge", text="Merge All").mode = 'ALL' layout.separator() layout.operator("gpencil.layer_duplicate_object", text="Copy Layer to Selected").only_active = True diff --git a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py index 26fe215b17d..9afe8415cf4 100644 --- a/release/scripts/startup/bl_ui/properties_physics_rigidbody.py +++ b/release/scripts/startup/bl_ui/properties_physics_rigidbody.py @@ -261,7 +261,7 @@ class PHYSICS_PT_rigid_body_dynamics(PHYSICS_PT_rigidbody_panel, Panel): # col = layout.column(align=True) # col.label(text="Activation:") - # XXX: settings such as activate on collison/etc. + # XXX: settings such as activate on collision/etc. col = flow.column() col.prop(rbo, "linear_damping", text="Damping Translation") diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index c18d77987ad..86e9ef3d664 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -1858,6 +1858,43 @@ class CLIP_MT_reconstruction_pie(Menu): pie.operator("clip.apply_solution_scale", icon='ARROW_LEFTRIGHT') +class CLIP_MT_view_pie(Menu): + bl_label = "View" + + @classmethod + def poll(cls, context): + space = context.space_data + + # View operators are not yet implemented in Dopesheet mode. + return space.view != 'DOPESHEET' + + def draw(self, context): + layout = self.layout + sc = context.space_data + + pie = layout.menu_pie() + + if sc.view == 'CLIP': + pie.operator("clip.view_all") + pie.operator("clip.view_selected", icon='ZOOM_SELECTED') + + if sc.mode == 'MASK': + pie.operator("clip.view_center_cursor") + pie.separator() + else: + # Add spaces so items stay in the same position through all modes. + pie.separator() + pie.separator() + + pie.operator("clip.view_all", text="Frame All Fit").fit_view = True + + if sc.view == 'GRAPH': + pie.operator_context = 'INVOKE_REGION_PREVIEW' + pie.operator("clip.graph_view_all") + pie.separator() + pie.operator("clip.graph_center_current_frame") + + classes = ( CLIP_UL_tracking_objects, CLIP_HT_header, @@ -1925,6 +1962,7 @@ classes = ( CLIP_MT_tracking_pie, CLIP_MT_reconstruction_pie, CLIP_MT_solving_pie, + CLIP_MT_view_pie, ) if __name__ == "__main__": # only for live edit. diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 781c430a752..9b8f1cfeb0d 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -379,6 +379,18 @@ class DOPESHEET_MT_view(Menu): layout.menu("INFO_MT_area") +class DOPESHEET_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("action.view_all") + pie.operator("action.view_selected", icon='ZOOM_SELECTED') + pie.operator("action.view_frame") + + class DOPESHEET_MT_select(Menu): bl_label = "Select" @@ -778,6 +790,7 @@ classes = ( DOPESHEET_MT_context_menu, DOPESHEET_MT_channel_context_menu, DOPESHEET_MT_snap_pie, + DOPESHEET_MT_view_pie, DOPESHEET_PT_filters, DOPESHEET_PT_gpencil_mode, DOPESHEET_PT_gpencil_layer_masks, diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 612b7ba2b09..1562870d64f 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -338,6 +338,18 @@ class GRAPH_MT_key_snap(Menu): layout.operator("graph.snap_cursor_value", text="Cursor Value to Selection") +class GRAPH_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("graph.view_all") + pie.operator("graph.view_selected", icon='ZOOM_SELECTED') + pie.operator("graph.view_frame") + + class GRAPH_MT_delete(Menu): bl_label = "Delete" @@ -468,6 +480,7 @@ classes = ( GRAPH_MT_channel_context_menu, GRAPH_MT_pivot_pie, GRAPH_MT_snap_pie, + GRAPH_MT_view_pie, GRAPH_PT_filters, ) diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index 6a769b1aecc..8e82b07716c 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -591,6 +591,31 @@ class IMAGE_MT_uvs_snap_pie(Menu): ).target = 'ADJACENT_UNSELECTED' +class IMAGE_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + sima = context.space_data + show_uvedit = sima.show_uvedit + show_maskedit = sima.show_maskedit + + pie = layout.menu_pie() + pie.operator("image.view_all") + + if show_uvedit or show_maskedit: + pie.operator("image.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + pie.operator("image.view_center_cursor", text="Center View to Cursor") + else: + # Add spaces so items stay in the same position through all modes. + pie.separator() + pie.separator() + + pie.operator("image.view_zoom_ratio", text="Zoom 1:1").ratio = 1 + pie.operator("image.view_all", text="Frame All Fit").fit_view = True + + class IMAGE_HT_tool_header(Header): bl_space_type = 'IMAGE_EDITOR' bl_region_type = 'TOOL_HEADER' @@ -1633,6 +1658,7 @@ classes = ( IMAGE_MT_mask_context_menu, IMAGE_MT_pivot_pie, IMAGE_MT_uvs_snap_pie, + IMAGE_MT_view_pie, IMAGE_HT_tool_header, IMAGE_HT_header, IMAGE_MT_editor_menus, diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index d472352084c..9507d8296a9 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -247,6 +247,18 @@ class NLA_MT_snap_pie(Menu): pie.operator("nla.snap", text="Selection to Nearest Marker").type = 'NEAREST_MARKER' +class NLA_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("nla.view_all") + pie.operator("nla.view_selected", icon='ZOOM_SELECTED') + pie.operator("nla.view_frame") + + class NLA_MT_context_menu(Menu): bl_label = "NLA Context Menu" @@ -300,6 +312,7 @@ classes = ( NLA_MT_add, NLA_MT_edit_transform, NLA_MT_snap_pie, + NLA_MT_view_pie, NLA_MT_context_menu, NLA_MT_channel_context_menu, NLA_PT_filters, diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 2fda13184da..afbd7e61aaa 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -367,6 +367,17 @@ class NODE_MT_node(Menu): layout.operator("node.read_viewlayers") +class NODE_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("node.view_all") + pie.operator("node.view_selected", icon='ZOOM_SELECTED') + + class NODE_PT_active_tool(ToolActivePanelHelper, Panel): bl_space_type = 'NODE_EDITOR' bl_region_type = 'UI' @@ -710,6 +721,10 @@ class NODE_PT_overlay(Panel): col.prop(snode, "show_annotation", text="Annotations") + if snode.tree_type == 'GeometryNodeTree': + col.separator() + col.prop(overlay, "show_timing", text="Timings") + class NODE_UL_interface_sockets(bpy.types.UIList): def draw_item(self, context, layout, _data, item, icon, _active_data, _active_propname, _index): @@ -877,6 +892,7 @@ classes = ( NODE_MT_node, NODE_MT_node_color_context_menu, NODE_MT_context_menu, + NODE_MT_view_pie, NODE_PT_material_slots, NODE_PT_node_color_presets, NODE_PT_active_node_generic, diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 07fa2220915..d85538a37e0 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -142,6 +142,17 @@ class OUTLINER_MT_context_menu_view(Menu): layout.operator("outliner.show_one_level", text="Hide One Level").open = False +class OUTLINER_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("outliner.show_hierarchy") + pie.operator("outliner.show_active", icon='ZOOM_SELECTED') + + class OUTLINER_MT_edit_datablocks(Menu): bl_label = "Edit" @@ -471,6 +482,7 @@ classes = ( OUTLINER_MT_asset, OUTLINER_MT_context_menu, OUTLINER_MT_context_menu_view, + OUTLINER_MT_view_pie, OUTLINER_PT_filter, ) diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 7117f28c1a7..401ff9b64c2 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -1173,6 +1173,31 @@ class SEQUENCER_MT_pivot_pie(Menu): pie.prop_enum(sequencer_tool_settings, "pivot_point", value='MEDIAN') +class SEQUENCER_MT_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator("sequencer.view_all") + pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + + +class SEQUENCER_MT_preview_view_pie(Menu): + bl_label = "View" + + def draw(self, context): + layout = self.layout + + pie = layout.menu_pie() + pie.operator_context = 'INVOKE_REGION_PREVIEW' + pie.operator("sequencer.view_all_preview") + pie.operator("sequencer.view_selected", text="Frame Selected", icon='ZOOM_SELECTED') + pie.separator() + pie.operator("sequencer.view_zoom_ratio", text="Zoom 1:1").ratio = 1 + + class SequencerButtonsPanel: bl_space_type = 'SEQUENCE_EDITOR' bl_region_type = 'UI' @@ -2615,6 +2640,8 @@ classes = ( SEQUENCER_MT_context_menu, SEQUENCER_MT_preview_context_menu, SEQUENCER_MT_pivot_pie, + SEQUENCER_MT_view_pie, + SEQUENCER_MT_preview_view_pie, SEQUENCER_PT_color_tag_picker, diff --git a/release/scripts/startup/bl_ui/space_toolsystem_common.py b/release/scripts/startup/bl_ui/space_toolsystem_common.py index 9d41a0fa02f..c4dabb5b5bc 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_common.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_common.py @@ -64,7 +64,7 @@ from collections import namedtuple ToolDef = namedtuple( "ToolDef", ( - # Unique tool name (withing space & mode context). + # Unique tool name (within space & mode context). "idname", # The name to display in the interface. "label", @@ -106,7 +106,7 @@ ToolDef = namedtuple( # Keep this functionality since it's likely useful for add-on key-maps. # # Warning: currently 'from_dict' this is a list of one item, - # so internally we can swap the key-map function for the key-map it's self. + # so internally we can swap the key-map function for the key-map itself. # This isn't very nice and may change, tool definitions shouldn't care about this. "keymap", # Optional data-block associated with this tool. diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index e7f93bddac3..92d1e8e2586 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -477,6 +477,16 @@ class USERPREF_PT_edit_weight_paint(EditingPanel, CenterAlignMixIn, Panel): col.active = view.use_weight_color_range col.template_color_ramp(view, "weight_color_range", expand=True) +class USERPREF_PT_edit_text_editor(EditingPanel, CenterAlignMixIn, Panel): + bl_label = "Text Editor" + bl_options = {'DEFAULT_CLOSED'} + + def draw_centered(self, context, layout): + prefs = context.preferences + edit = prefs.edit + + layout.prop(edit, "use_text_edit_auto_close") + class USERPREF_PT_edit_misc(EditingPanel, CenterAlignMixIn, Panel): bl_label = "Miscellaneous" @@ -2358,6 +2368,7 @@ classes = ( USERPREF_PT_edit_annotations, USERPREF_PT_edit_weight_paint, USERPREF_PT_edit_gpencil, + USERPREF_PT_edit_text_editor, USERPREF_PT_edit_misc, USERPREF_PT_animation_timeline, diff --git a/source/blender/blenfont/BLF_api.h b/source/blender/blenfont/BLF_api.h index 78252bdb08b..fa8e764139d 100644 --- a/source/blender/blenfont/BLF_api.h +++ b/source/blender/blenfont/BLF_api.h @@ -43,6 +43,8 @@ void BLF_exit(void); void BLF_cache_clear(void); +void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void)); + /* Loads a font, or returns an already loaded font and increments its reference count. */ int BLF_load(const char *name) ATTR_NONNULL(); int BLF_load_mem(const char *name, const unsigned char *mem, int mem_size) ATTR_NONNULL(); @@ -63,7 +65,7 @@ void BLF_metrics_attach(int fontid, unsigned char *mem, int mem_size); void BLF_aspect(int fontid, float x, float y, float z); void BLF_position(int fontid, float x, float y, float z); -void BLF_size(int fontid, int size, int dpi); +void BLF_size(int fontid, float size, int dpi); /* goal: small but useful color API */ void BLF_color4ubv(int fontid, const unsigned char rgba[4]); @@ -250,6 +252,7 @@ void BLF_thumb_preview(const char *filename, /* blf_default.c */ void BLF_default_dpi(int dpi); +void BLF_default_size(int size); void BLF_default_set(int fontid); int BLF_default(void); /* get default font ID so we can pass it to other functions */ /* Draw the string using the default font, size and dpi. */ diff --git a/source/blender/blenfont/CMakeLists.txt b/source/blender/blenfont/CMakeLists.txt index 59a9072de57..cc6e298b322 100644 --- a/source/blender/blenfont/CMakeLists.txt +++ b/source/blender/blenfont/CMakeLists.txt @@ -23,7 +23,6 @@ set(INC ../blenkernel ../blenlib ../blentranslation - ../editors/include ../gpu ../imbuf ../makesdna diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 34ddb6f22d2..d6773916abd 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -363,7 +363,7 @@ void BLF_position(int fontid, float x, float y, float z) } } -void BLF_size(int fontid, int size, int dpi) +void BLF_size(int fontid, float size, int dpi) { FontBLF *font = blf_get(fontid); @@ -910,7 +910,7 @@ void BLF_state_print(int fontid) if (font) { printf("fontid %d %p\n", fontid, (void *)font); printf(" name: '%s'\n", font->name); - printf(" size: %u\n", font->size); + printf(" size: %f\n", font->size); printf(" dpi: %u\n", font->dpi); printf(" pos: %.6f %.6f %.6f\n", UNPACK3(font->pos)); printf(" aspect: (%d) %.6f %.6f %.6f\n", diff --git a/source/blender/blenfont/intern/blf_default.c b/source/blender/blenfont/intern/blf_default.c index 2bac0bf8904..57eeaa6768d 100644 --- a/source/blender/blenfont/intern/blf_default.c +++ b/source/blender/blenfont/intern/blf_default.c @@ -29,8 +29,6 @@ #include "BLF_api.h" -#include "UI_interface.h" - #include "blf_internal.h" /* call BLF_default_set first! */ @@ -39,12 +37,19 @@ /* Default size and dpi, for BLF_draw_default. */ static int global_font_default = -1; static int global_font_dpi = 72; +/* Keep in sync with `UI_style_get()->widgetlabel.points` */ +static int global_font_size = 11; void BLF_default_dpi(int dpi) { global_font_dpi = dpi; } +void BLF_default_size(int size) +{ + global_font_size = size; +} + void BLF_default_set(int fontid) { if ((fontid == -1) || blf_font_id_is_valid(fontid)) { @@ -62,8 +67,7 @@ int BLF_set_default(void) { ASSERT_DEFAULT_SET; - const uiStyle *style = UI_style_get(); - BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); + BLF_size(global_font_default, global_font_size, global_font_dpi); return global_font_default; } @@ -71,9 +75,7 @@ int BLF_set_default(void) void BLF_draw_default(float x, float y, float z, const char *str, const size_t str_len) { ASSERT_DEFAULT_SET; - - const uiStyle *style = UI_style_get(); - BLF_size(global_font_default, style->widgetlabel.points, global_font_dpi); + BLF_size(global_font_default, global_font_size, global_font_dpi); BLF_position(global_font_default, x, y, z); BLF_draw(global_font_default, str, str_len); } diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index 27478bd7f8e..c81d18ba7de 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -34,6 +34,7 @@ #include FT_FREETYPE_H #include FT_GLYPH_H +#include FT_ADVANCES_H /* For FT_Get_Advance */ #include "MEM_guardedalloc.h" @@ -49,8 +50,6 @@ #include "BLF_api.h" -#include "UI_interface.h" - #include "GPU_batch.h" #include "GPU_matrix.h" @@ -71,6 +70,9 @@ static FT_Library ft_lib; static SpinLock ft_lib_mutex; static SpinLock blf_glyph_cache_mutex; +/* May be set to #UI_widgetbase_draw_cache_flush. */ +static void (*blf_draw_cache_flush)(void) = NULL; + /* -------------------------------------------------------------------- */ /** \name FreeType Utilities (Internal) * \{ */ @@ -254,10 +256,10 @@ void blf_batch_draw(void) GPU_blend(GPU_BLEND_ALPHA); -#ifndef BLF_STANDALONE /* We need to flush widget base first to ensure correct ordering. */ - UI_widgetbase_draw_cache_flush(); -#endif + if (blf_draw_cache_flush != NULL) { + blf_draw_cache_flush(); + } GPUTexture *texture = blf_batch_cache_texture_load(); GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len); @@ -297,44 +299,27 @@ static void blf_batch_draw_end(void) * characters. */ -BLI_INLINE GlyphBLF *blf_utf8_next_fast( - FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p, uint *r_c) +BLI_INLINE GlyphBLF *blf_glyph_from_utf8_and_step( + FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t str_len, size_t *i_p) { - GlyphBLF *g; - if ((*r_c = str[*i_p]) < GLYPH_ASCII_TABLE_SIZE) { - g = (gc->glyph_ascii_table)[*r_c]; - if (UNLIKELY(g == NULL)) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); - gc->glyph_ascii_table[*r_c] = g; - } - (*i_p)++; - } - else { - *r_c = BLI_str_utf8_as_unicode_step(str, str_len, i_p); - g = blf_glyph_search(gc, *r_c); - if (UNLIKELY(g == NULL)) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, *r_c), *r_c); - } - } - return g; + uint charcode = BLI_str_utf8_as_unicode_step(str, str_len, i_p); + /* Invalid unicode sequences return the byte value, stepping forward one. + * This allows `latin1` to display (which is sometimes used for file-paths). */ + BLI_assert(charcode != BLI_UTF8_ERR); + return blf_glyph_ensure(font, gc, charcode); } -BLI_INLINE void blf_kerning_step_fast(FontBLF *font, - const GlyphBLF *g_prev, - const GlyphBLF *g, - const uint c_prev, - const uint c, - int *pen_x_p) +BLI_INLINE int blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g) { if (!FT_HAS_KERNING(font->face) || g_prev == NULL) { - return; + return 0; } FT_Vector delta = {KERNING_ENTRY_UNSET}; /* Get unscaled kerning value from our cache if ASCII. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - delta.x = font->kerning_cache->ascii_table[c][c_prev]; + if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) { + delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c]; } /* If not ASCII or not found in cache, ask FreeType for kerning. */ @@ -344,14 +329,16 @@ BLI_INLINE void blf_kerning_step_fast(FontBLF *font, } /* If ASCII we save this value to our cache for quicker access next time. */ - if ((c_prev < KERNING_CACHE_TABLE_SIZE) && (c < GLYPH_ASCII_TABLE_SIZE)) { - font->kerning_cache->ascii_table[c][c_prev] = (int)delta.x; + if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < GLYPH_ASCII_TABLE_SIZE)) { + font->kerning_cache->ascii_table[g->c][g_prev->c] = (int)delta.x; } if (delta.x != 0) { /* Convert unscaled design units to pixels and move pen. */ - *pen_x_p += blf_unscaled_F26Dot6_to_pixels(font, delta.x); + return blf_unscaled_F26Dot6_to_pixels(font, delta.x); } + + return 0; } /** \} */ @@ -367,7 +354,6 @@ static void blf_font_draw_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0; @@ -380,22 +366,18 @@ static void blf_font_draw_ex(FontBLF *font, blf_batch_draw_begin(font); while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); /* do not return this loop if clipped, we want every character tested */ - blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); + blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y); pen_x += g->advance_i; g_prev = g; - c_prev = c; } blf_batch_draw_end(); @@ -415,7 +397,6 @@ void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, struct /* use fixed column width, but an utf8 character may occupy multiple columns */ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth) { - unsigned int c; GlyphBLF *g; int col, columns = 0; int pen_x = 0, pen_y = 0; @@ -426,19 +407,15 @@ int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int blf_batch_draw_begin(font); while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - /* do not return this loop if clipped, we want every character tested */ - blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y); + blf_glyph_draw(font, gc, g, (float)pen_x, (float)pen_y); - col = BLI_wcwidth((char32_t)c); + col = BLI_wcwidth((char32_t)g->c); if (col < 0) { col = 1; } @@ -467,7 +444,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = (int)font->pos[0]; int pen_y_basis = (int)font->pos[1] + pen_y; @@ -483,15 +459,12 @@ static void blf_font_draw_buffer_ex(FontBLF *font, /* another buffer specific call for color conversion */ while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); chx = pen_x + ((int)g->pos[0]); chy = pen_y_basis + g->dims[1]; @@ -588,7 +561,6 @@ static void blf_font_draw_buffer_ex(FontBLF *font, pen_x += g->advance_i; g_prev = g; - c_prev = c; } if (r_info) { @@ -610,38 +582,29 @@ void blf_font_draw_buffer(FontBLF *font, /** \} */ /* -------------------------------------------------------------------- */ -/** \name Text Evaluation: Width to Sting Length +/** \name Text Evaluation: Width to String Length * * Use to implement exported functions: * - #BLF_width_to_strlen * - #BLF_width_to_rstrlen * \{ */ -static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, - const uint c_prev, - const uint c, - GlyphBLF *g_prev, - GlyphBLF *g, - int *pen_x, - const int width_i) +static bool blf_font_width_to_strlen_glyph_process( + FontBLF *font, GlyphBLF *g_prev, GlyphBLF *g, int *pen_x, const int width_i) { - if (UNLIKELY(c == BLI_UTF8_ERR)) { - return true; /* break the calling loop. */ - } if (UNLIKELY(g == NULL)) { return false; /* continue the calling loop. */ } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, pen_x); - + *pen_x += blf_kerning(font, g_prev, g); *pen_x += g->advance_i; + /* When true, break the calling loop. */ return (*pen_x >= width_i); } size_t blf_font_width_to_strlen( FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; int pen_x, width_new; size_t i, i_prev; @@ -649,11 +612,11 @@ size_t blf_font_width_to_strlen( GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); const int width_i = (int)width; - for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < str_len) && str[i]; - i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL; (i < str_len) && str[i]; + i_prev = i, width_new = pen_x, g_prev = g) { + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) { break; } } @@ -669,7 +632,6 @@ size_t blf_font_width_to_strlen( size_t blf_font_width_to_rstrlen( FontBLF *font, const char *str, const size_t str_len, float width, float *r_width) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev; int pen_x, width_new; size_t i, i_prev, i_tmp; @@ -685,19 +647,19 @@ size_t blf_font_width_to_rstrlen( i_prev = (size_t)(s_prev - str); i_tmp = i; - g = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp); for (width_new = pen_x = 0; (s != NULL); - i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { + i = i_prev, s = s_prev, g = g_prev, g_prev = NULL, width_new = pen_x) { s_prev = BLI_str_find_prev_char_utf8(s, str); i_prev = (size_t)(s_prev - str); if (s_prev != NULL) { i_tmp = i_prev; - g_prev = blf_utf8_next_fast(font, gc, str, str_len, &i_tmp, &c_prev); + g_prev = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i_tmp); BLI_assert(i_tmp == i); } - if (blf_font_width_to_strlen_glyph_process(font, c_prev, c, g_prev, g, &pen_x, width_i)) { + if (blf_font_width_to_strlen_glyph_process(font, g_prev, g, &pen_x, width_i)) { break; } } @@ -724,7 +686,6 @@ static void blf_font_boundbox_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0; @@ -736,15 +697,12 @@ static void blf_font_boundbox_ex(FontBLF *font, box->ymax = -32000.0f; while ((i < str_len) && str[i]) { - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); gbox.xmin = (float)pen_x; gbox.xmax = (float)pen_x + g->advance; @@ -767,7 +725,6 @@ static void blf_font_boundbox_ex(FontBLF *font, pen_x += g->advance_i; g_prev = g; - c_prev = c; } if (box->xmin > box->xmax) { @@ -869,22 +826,7 @@ float blf_font_height(FontBLF *font, float blf_font_fixed_width(FontBLF *font) { - const unsigned int c = ' '; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - GlyphBLF *g = blf_glyph_search(gc, c); - if (!g) { - g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c); - - /* if we don't find the glyph. */ - if (!g) { - blf_glyph_cache_release(font); - return 0.0f; - } - } - - blf_glyph_cache_release(font); - return g->advance; + return (float)font->fixed_width; } static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, @@ -896,7 +838,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, struct ResultBLF *r_info, int pen_y) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0; size_t i = 0, i_curr; @@ -909,15 +850,12 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, while ((i < str_len) && str[i]) { i_curr = i; - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); gbox.xmin = pen_x; gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]); @@ -931,7 +869,6 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font, } g_prev = g; - c_prev = c; } if (r_info) { @@ -978,7 +915,6 @@ static void blf_font_wrap_apply(FontBLF *font, void *userdata), void *userdata) { - unsigned int c, c_prev = BLI_UTF8_ERR; GlyphBLF *g, *g_prev = NULL; int pen_x = 0, pen_y = 0; size_t i = 0; @@ -999,15 +935,12 @@ static void blf_font_wrap_apply(FontBLF *font, size_t i_curr = i; bool do_draw = false; - g = blf_utf8_next_fast(font, gc, str, str_len, &i, &c); + g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i); - if (UNLIKELY(c == BLI_UTF8_ERR)) { - break; - } if (UNLIKELY(g == NULL)) { continue; } - blf_kerning_step_fast(font, g_prev, g, c_prev, c, &pen_x); + pen_x += blf_kerning(font, g_prev, g); /** * Implementation Detail (utf8). @@ -1045,16 +978,14 @@ static void blf_font_wrap_apply(FontBLF *font, wrap.start = wrap.last[0]; i = wrap.last[1]; pen_x = 0; - pen_y -= gc->glyph_height_max; + pen_y -= blf_font_height_max(font); g_prev = NULL; - c_prev = BLI_UTF8_ERR; lines += 1; continue; } pen_x = pen_x_next; g_prev = g; - c_prev = c; } // printf("done! lines: %d, width, %d\n", lines, pen_x_next); @@ -1170,45 +1101,41 @@ int blf_font_count_missing_chars(FontBLF *font, int blf_font_height_max(FontBLF *font) { int height_max; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - height_max = gc->glyph_height_max; - - blf_glyph_cache_release(font); - return height_max; + if (FT_IS_SCALABLE(font->face)) { + height_max = (int)((float)(font->face->ascender - font->face->descender) * + (((float)font->face->size->metrics.y_ppem) / + ((float)font->face->units_per_EM))); + } + else { + height_max = (int)(((float)font->face->size->metrics.height) / 64.0f); + } + /* can happen with size 1 fonts */ + return MAX2(height_max, 1); } int blf_font_width_max(FontBLF *font) { int width_max; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - width_max = gc->glyph_width_max; - - blf_glyph_cache_release(font); - return width_max; + if (FT_IS_SCALABLE(font->face)) { + width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) * + (((float)font->face->size->metrics.x_ppem) / + ((float)font->face->units_per_EM))); + } + else { + width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f); + } + /* can happen with size 1 fonts */ + return MAX2(width_max, 1); } float blf_font_descender(FontBLF *font) { - float descender; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - descender = gc->descender; - - blf_glyph_cache_release(font); - return descender; + return ((float)font->face->size->metrics.descender) / 64.0f; } float blf_font_ascender(FontBLF *font) { - float ascender; - - GlyphCacheBLF *gc = blf_glyph_cache_acquire(font); - ascender = gc->ascender; - - blf_glyph_cache_release(font); - return ascender; + return ((float)font->face->size->metrics.ascender) / 64.0f; } char *blf_display_name(FontBLF *font) @@ -1241,6 +1168,14 @@ void blf_font_exit(void) blf_batch_draw_exit(); } +/** + * Optional cache flushing function, called before #blf_batch_draw. + */ +void BLF_cache_flush_set_fn(void (*cache_flush_fn)(void)) +{ + blf_draw_cache_flush = cache_flush_fn; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1415,19 +1350,24 @@ void blf_font_free(FontBLF *font) /** \name Font Configure * \{ */ -void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) +void blf_font_size(FontBLF *font, float size, unsigned int dpi) { blf_glyph_cache_acquire(font); + /* FreeType uses fixed-point integers in 64ths. */ + FT_F26Dot6 ft_size = lroundf(size * 64.0f); + /* Adjust our size to be on even 64ths. */ + size = (float)ft_size / 64.0f; + GlyphCacheBLF *gc = blf_glyph_cache_find(font, size, dpi); if (gc && (font->size == size && font->dpi == dpi)) { /* Optimization: do not call FT_Set_Char_Size if size did not change. */ } else { - const FT_Error err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi); + const FT_Error err = FT_Set_Char_Size(font->face, 0, ft_size, dpi, dpi); if (err) { /* FIXME: here we can go through the fixed size and choice a close one */ - printf("The current font don't support the size, %u and dpi, %u\n", size, dpi); + printf("The current font don't support the size, %f and dpi, %u\n", size, dpi); } else { font->size = size; @@ -1439,6 +1379,22 @@ void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi) } blf_glyph_cache_release(font); + + /* Set fixed-width size for monospaced output. */ + FT_UInt gindex = FT_Get_Char_Index(font->face, U'0'); + if (gindex) { + FT_Fixed advance = 0; + FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance); + /* Use CSS 'ch unit' width, advance of zero character. */ + font->fixed_width = (int)(advance >> 16); + } + else { + /* Font does not contain "0" so use CSS fallback of 1/2 of em. */ + font->fixed_width = (int)((font->face->size->metrics.height / 2) >> 6); + } + if (font->fixed_width < 1) { + font->fixed_width = 1; + } } /** \} */ diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 6cdf5fc5996..5f14ef433e9 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -55,27 +55,47 @@ #include "BLI_math_vector.h" #include "BLI_strict_flags.h" -GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, unsigned int size, unsigned int dpi) +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ + +/** + * Convert a floating point value to a FreeType 16.16 fixed point value. + */ +static FT_Fixed to_16dot16(double val) { - GlyphCacheBLF *p; + return (FT_Fixed)(lround(val * 65536.0)); +} - p = (GlyphCacheBLF *)font->cache.first; - while (p) { - if (p->size == size && p->dpi == dpi && (p->bold == ((font->flags & BLF_BOLD) != 0)) && - (p->italic == ((font->flags & BLF_ITALIC) != 0))) { - return p; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Cache + * \{ */ + +/** + * Find a glyph cache that matches a size, DPI & styles. + */ +GlyphCacheBLF *blf_glyph_cache_find(FontBLF *font, float size, unsigned int dpi) +{ + GlyphCacheBLF *gc = (GlyphCacheBLF *)font->cache.first; + while (gc) { + if (gc->size == size && gc->dpi == dpi && (gc->bold == ((font->flags & BLF_BOLD) != 0)) && + (gc->italic == ((font->flags & BLF_ITALIC) != 0))) { + return gc; } - p = p->next; + gc = gc->next; } return NULL; } -/* Create a new glyph cache for the current size, dpi, bold, italic. */ +/** + * Create a new glyph cache for the current size, DPI & styles. + */ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) { - GlyphCacheBLF *gc; + GlyphCacheBLF *gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); - gc = (GlyphCacheBLF *)MEM_callocN(sizeof(GlyphCacheBLF), "blf_glyph_cache_new"); gc->next = NULL; gc->prev = NULL; gc->size = font->size; @@ -86,27 +106,6 @@ GlyphCacheBLF *blf_glyph_cache_new(FontBLF *font) memset(gc->glyph_ascii_table, 0, sizeof(gc->glyph_ascii_table)); memset(gc->bucket, 0, sizeof(gc->bucket)); - gc->ascender = ((float)font->face->size->metrics.ascender) / 64.0f; - gc->descender = ((float)font->face->size->metrics.descender) / 64.0f; - - if (FT_IS_SCALABLE(font->face)) { - gc->glyph_width_max = (int)((float)(font->face->bbox.xMax - font->face->bbox.xMin) * - (((float)font->face->size->metrics.x_ppem) / - ((float)font->face->units_per_EM))); - - gc->glyph_height_max = (int)((float)(font->face->bbox.yMax - font->face->bbox.yMin) * - (((float)font->face->size->metrics.y_ppem) / - ((float)font->face->units_per_EM))); - } - else { - gc->glyph_width_max = (int)(((float)font->face->size->metrics.max_advance) / 64.0f); - gc->glyph_height_max = (int)(((float)font->face->size->metrics.height) / 64.0f); - } - - /* can happen with size 1 fonts */ - CLAMP_MIN(gc->glyph_width_max, 1); - CLAMP_MIN(gc->glyph_height_max, 1); - BLI_addhead(&font->cache, gc); return gc; } @@ -159,59 +158,95 @@ void blf_glyph_cache_free(GlyphCacheBLF *gc) MEM_freeN(gc); } -GlyphBLF *blf_glyph_search(GlyphCacheBLF *gc, unsigned int c) +/** + * Try to find a glyph in cache. + * + * \return NULL if not found. + */ +static GlyphBLF *blf_glyph_cache_find_glyph(GlyphCacheBLF *gc, uint charcode) { - GlyphBLF *p; - unsigned int key; - - key = blf_hash(c); - p = gc->bucket[key].first; - while (p) { - if (p->c == c) { - return p; + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + return gc->glyph_ascii_table[charcode]; + } + + GlyphBLF *g = gc->bucket[blf_hash(charcode)].first; + while (g) { + if (g->c == charcode) { + return g; } - p = p->next; + g = g->next; } return NULL; } -GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, unsigned int c) +/** + * Add a rendered glyph to a cache. + */ +static GlyphBLF *blf_glyph_cache_add_glyph( + FontBLF *font, GlyphCacheBLF *gc, FT_GlyphSlot glyph, uint charcode, FT_UInt glyph_index) { - FT_GlyphSlot slot; - GlyphBLF *g; - FT_Error err; - FT_Bitmap bitmap, tempbitmap; + GlyphBLF *g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_get"); + g->c = charcode; + g->idx = glyph_index; + g->advance = ((float)glyph->advance.x) / 64.0f; + g->advance_i = (int)g->advance; + g->pos[0] = glyph->bitmap_left; + g->pos[1] = glyph->bitmap_top; + g->dims[0] = (int)glyph->bitmap.width; + g->dims[1] = (int)glyph->bitmap.rows; + g->pitch = glyph->bitmap.pitch; + FT_BBox bbox; - unsigned int key; + FT_Outline_Get_CBox(&(glyph->outline), &bbox); + g->box.xmin = ((float)bbox.xMin) / 64.0f; + g->box.xmax = ((float)bbox.xMax) / 64.0f; + g->box.ymin = ((float)bbox.yMin) / 64.0f; + g->box.ymax = ((float)bbox.yMax) / 64.0f; - g = blf_glyph_search(gc, c); - if (g) { - return g; + const int buffer_size = (int)(glyph->bitmap.width * glyph->bitmap.rows); + if (buffer_size != 0) { + if (font->flags & BLF_MONOCHROME) { + /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range. */ + for (int i = 0; i < buffer_size; i++) { + glyph->bitmap.buffer[i] = glyph->bitmap.buffer[i] ? 255 : 0; + } + } + g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); + memcpy(g->bitmap, glyph->bitmap.buffer, (size_t)buffer_size); } - /* glyphs are dynamically created as needed by font rendering. this means that - * to make font rendering thread safe we have to do locking here. note that this - * must be a lock for the whole library and not just per font, because the font - * renderer uses a shared buffer internally */ - BLI_spin_lock(font->ft_lib_mutex); - - /* search again after locking */ - g = blf_glyph_search(gc, c); - if (g) { - BLI_spin_unlock(font->ft_lib_mutex); - return g; + unsigned int key = blf_hash(g->c); + BLI_addhead(&(gc->bucket[key]), g); + if (charcode < GLYPH_ASCII_TABLE_SIZE) { + gc->glyph_ascii_table[charcode] = g; } + return g; +} + +/** + * Return a glyph index from `charcode`. Not found returns zero, which is a valid + * printable character (`.notdef` or `tofu`). Font is allowed to change here. + */ +static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode) +{ + FT_UInt glyph_index = FT_Get_Char_Index((*font)->face, charcode); + /* TODO: If not found in this font, check others, update font pointer. */ + return glyph_index; +} + +/** + * Load a glyph into the glyph slot of a font's face object. + */ +static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index) +{ int load_flags; - int render_mode; if (font->flags & BLF_MONOCHROME) { load_flags = FT_LOAD_TARGET_MONO; - render_mode = FT_RENDER_MODE_MONO; } else { load_flags = FT_LOAD_NO_BITMAP; - render_mode = FT_RENDER_MODE_NORMAL; if (font->flags & BLF_HINTING_NONE) { load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING; } @@ -228,104 +263,222 @@ GlyphBLF *blf_glyph_add(FontBLF *font, GlyphCacheBLF *gc, unsigned int index, un } } - err = FT_Load_Glyph(font->face, (FT_UInt)index, load_flags); - - /* Do not oblique a font that is designed to be italic! */ - if (((font->flags & BLF_ITALIC) != 0) && !(font->face->style_flags & FT_STYLE_FLAG_ITALIC) && - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* For (fake) italic: a shear transform with a 6 degree angle. */ - FT_Matrix transform; - transform.xx = 0x10000L; - transform.yx = 0x00000L; - transform.xy = 0x03000L; - transform.yy = 0x10000L; - FT_Outline_Transform(&font->face->glyph->outline, &transform); - } - - /* Do not embolden an already bold font! */ - if (((font->flags & BLF_BOLD) != 0) && - !(font->face->style_flags & FT_STYLE_FLAG_BOLD) & - (font->face->glyph->format == FT_GLYPH_FORMAT_OUTLINE)) { - /* Strengthen the width more than the height. */ - const FT_Pos extra_x = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.x_scale) / - 14; - const FT_Pos extra_y = FT_MulFix(font->face->units_per_EM, font->face->size->metrics.y_scale) / - 28; - FT_Outline_EmboldenXY(&font->face->glyph->outline, extra_x, extra_y); - if ((font->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH) == 0) { - /* Need to increase advance, but not for fixed-width fonts. */ - font->face->glyph->advance.x += (FT_Pos)(((float)extra_x) * 1.05f); - font->face->glyph->advance.y += extra_y; - } - else { - /* Widened fixed-pitch font gets a nudge left. */ - FT_Outline_Translate(&font->face->glyph->outline, (extra_x / -2), 0); - } + if (FT_Load_Glyph(font->face, glyph_index, load_flags) == 0) { + return font->face->glyph; + } + return NULL; +} + +/** + * Convert a glyph from outlines to a bitmap that we can display. + */ +static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph) +{ + int render_mode; + + if (font->flags & BLF_MONOCHROME) { + render_mode = FT_RENDER_MODE_MONO; + } + else { + render_mode = FT_RENDER_MODE_NORMAL; } - if (err) { - BLI_spin_unlock(font->ft_lib_mutex); - return NULL; + /* Render the glyph curves to a bitmap. */ + FT_Error err = FT_Render_Glyph(glyph, render_mode); + if (err != 0) { + return false; } - /* get the glyph. */ - slot = font->face->glyph; - err = FT_Render_Glyph(slot, render_mode); + FT_Bitmap tempbitmap; if (font->flags & BLF_MONOCHROME) { /* Convert result from 1 bit per pixel to 8 bit per pixel */ - /* Accum errors for later, fine if not interested beyond "ok vs any error" */ + /* Accumulate errors for later, fine if not interested beyond "ok vs any error" */ FT_Bitmap_New(&tempbitmap); /* Does Blender use Pitch 1 always? It works so far */ - err += FT_Bitmap_Convert(font->ft_lib, &slot->bitmap, &tempbitmap, 1); - err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &slot->bitmap); + err += FT_Bitmap_Convert(font->ft_lib, &glyph->bitmap, &tempbitmap, 1); + err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &glyph->bitmap); err += FT_Bitmap_Done(font->ft_lib, &tempbitmap); } - if (err || slot->format != FT_GLYPH_FORMAT_BITMAP) { - BLI_spin_unlock(font->ft_lib_mutex); - return NULL; + if (err || glyph->format != FT_GLYPH_FORMAT_BITMAP) { + return false; } - g = (GlyphBLF *)MEM_callocN(sizeof(GlyphBLF), "blf_glyph_add"); - g->c = c; - g->idx = (FT_UInt)index; - bitmap = slot->bitmap; - g->dims[0] = (int)bitmap.width; - g->dims[1] = (int)bitmap.rows; + return true; +} - const int buffer_size = g->dims[0] * g->dims[1]; +/** \} */ - if (buffer_size != 0) { - if (font->flags & BLF_MONOCHROME) { - /* Font buffer uses only 0 or 1 values, Blender expects full 0..255 range */ - for (int i = 0; i < buffer_size; i++) { - bitmap.buffer[i] = bitmap.buffer[i] ? 255 : 0; - } +/* -------------------------------------------------------------------- */ +/** \name Glyph Transformations + * \{ */ + +/** + * Adjust the glyphs weight by a factor. + * + * \param factor: -1 (min stroke width) <= 0 (normal) => 1 (max boldness). + */ +static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float factor, bool monospaced) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + /* Fake bold if the font does not have this variable axis. */ + const FT_Pos average_width = FT_MulFix(glyph->face->units_per_EM, + glyph->face->size->metrics.x_scale); + FT_Pos change = (FT_Pos)((float)average_width * factor * 0.1f); + FT_Outline_EmboldenXY(&glyph->outline, change, change / 2); + if (monospaced) { + /* Widened fixed-pitch font needs a nudge left. */ + FT_Outline_Translate(&glyph->outline, change / -2, 0); + } + else { + /* Need to increase advance. */ + glyph->advance.x += change; + glyph->advance.y += change / 2; } + return true; + } + return false; +} - g->bitmap = MEM_mallocN((size_t)buffer_size, "glyph bitmap"); - memcpy(g->bitmap, bitmap.buffer, (size_t)buffer_size); +/** + * Adjust the glyphs slant by a factor (making it oblique). + * + * \param factor: -1 (max negative) <= 0 (no slant) => 1 (max positive). + * + * \note that left-leaning italics are possible in some RTL writing systems. + */ +static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + FT_Matrix transform = {to_16dot16(1), to_16dot16(factor / 2.0f), 0, to_16dot16(1)}; + FT_Outline_Transform(&glyph->outline, &transform); + return true; } + return false; +} - g->advance = ((float)slot->advance.x) / 64.0f; - g->advance_i = (int)g->advance; - g->pos[0] = slot->bitmap_left; - g->pos[1] = slot->bitmap_top; - g->pitch = slot->bitmap.pitch; +/** + * Adjust the glyph width by factor. + * + * \param factor: -1 (min width) <= 0 (normal) => 1 (max width). + */ +static bool UNUSED_FUNCTION(blf_glyph_transform_width)(FT_GlyphSlot glyph, float factor) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + float scale = (factor * 0.4f) + 1.0f; /* 0.6f - 1.4f */ + FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)}; + FT_Outline_Transform(&glyph->outline, &matrix); + glyph->advance.x = (FT_Pos)((double)glyph->advance.x * scale); + return true; + } + return false; +} - FT_Outline_Get_CBox(&(slot->outline), &bbox); - g->box.xmin = ((float)bbox.xMin) / 64.0f; - g->box.xmax = ((float)bbox.xMax) / 64.0f; - g->box.ymin = ((float)bbox.yMin) / 64.0f; - g->box.ymax = ((float)bbox.yMax) / 64.0f; +/** + * Transform glyph to fit nicely within a fixed column width. + */ +static bool UNUSED_FUNCTION(blf_glyph_transform_monospace)(FT_GlyphSlot glyph, int width) +{ + if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) { + int gwidth = (int)(glyph->linearHoriAdvance >> 16); + if (gwidth > width) { + float scale = (float)width / (float)gwidth; + FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)}; + /* Narrowing all points also thins vertical strokes. */ + FT_Outline_Transform(&glyph->outline, &matrix); + const FT_Pos extra_x = (int)((float)(gwidth - width) * 5.65f); + /* Horizontally widen strokes to counteract narrowing. */ + FT_Outline_EmboldenXY(&glyph->outline, extra_x, 0); + } + else if (gwidth < width) { + /* Narrow glyphs only need to be centered. */ + int nudge = (width - gwidth) / 2; + FT_Outline_Translate(&glyph->outline, (FT_Pos)nudge * 64, 0); + } + return true; + } + return false; +} - key = blf_hash(g->c); - BLI_addhead(&(gc->bucket[key]), g); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Access (Ensure/Free) + * \{ */ + +/** + * Create and return a fully-rendered bitmap glyph. + */ +static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, + FontBLF *glyph_font, + FT_UInt glyph_index) +{ + if (glyph_font != settings_font) { + FT_Set_Char_Size(glyph_font->face, + 0, + ((FT_F26Dot6)(settings_font->size)) * 64, + settings_font->dpi, + settings_font->dpi); + glyph_font->size = settings_font->size; + glyph_font->dpi = settings_font->dpi; + } + + FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index); + if (!glyph) { + return NULL; + } - BLI_spin_unlock(font->ft_lib_mutex); + if ((settings_font->flags & BLF_ITALIC) != 0) { + /* 37.5% of maximum rightward slant results in 6 degree slope, matching italic + * version (`DejaVuSans-Oblique.ttf`) of our current font. But a nice median when + * checking others. Worth reevaluating if we change default font. We could also + * narrow the glyph slightly as most italics do, but this one does not. */ + blf_glyph_transform_slant(glyph, 0.375f); + } + if ((settings_font->flags & BLF_BOLD) != 0) { + /* 70% of maximum weight results in the same amount of boldness and horizontal + * expansion as the bold version (`DejaVuSans-Bold.ttf`) of our default font. + * Worth reevaluating if we change default font. */ + blf_glyph_transform_weight(glyph, 0.7f, glyph->face->face_flags & FT_FACE_FLAG_FIXED_WIDTH); + } + + if (blf_glyph_render_bitmap(glyph_font, glyph)) { + return glyph; + } + return NULL; +} + +/** + * Create (or load from cache) a fully-rendered bitmap glyph. + */ +GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode) +{ + GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode); + if (g) { + return g; + } + + /* Glyph might not come from the initial font. */ + FontBLF *font_with_glyph = font; + FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode); + + /* Glyphs are dynamically created as needed by font rendering. this means that + * to make font rendering thread safe we have to do locking here. note that this + * must be a lock for the whole library and not just per font, because the font + * renderer uses a shared buffer internally. */ + BLI_spin_lock(font_with_glyph->ft_lib_mutex); + + FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index); + + if (glyph) { + /* Save this glyph in the initial font's cache. */ + g = blf_glyph_cache_add_glyph(font, gc, glyph, charcode, glyph_index); + } + + BLI_spin_unlock(font_with_glyph->ft_lib_mutex); return g; } @@ -337,6 +490,42 @@ void blf_glyph_free(GlyphBLF *g) MEM_freeN(g); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Bounds Calculation + * \{ */ + +static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) +{ + rect->xmin = floorf(x + (float)g->pos[0]); + rect->xmax = rect->xmin + (float)g->dims[0]; + rect->ymin = floorf(y + (float)g->pos[1]); + rect->ymax = rect->ymin - (float)g->dims[1]; +} + +static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) +{ + /* Intentionally check with `g->advance`, because this is the + * width used by BLF_width. This allows that the text slightly + * overlaps the clipping border to achieve better alignment. */ + rect->xmin = floorf(x); + rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]); + rect->ymin = floorf(y); + rect->ymax = rect->ymin - (float)g->dims[1]; +} + +static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font) +{ + blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Glyph Drawing + * \{ */ + static void blf_texture_draw(const unsigned char color[4], const int glyph_size[2], const int offset, @@ -395,31 +584,7 @@ static void blf_texture3_draw(const unsigned char color_in[4], blf_texture_draw(color_in, glyph_size_flag, offset, x1, y1, x2, y2); } -static void blf_glyph_calc_rect(rctf *rect, GlyphBLF *g, float x, float y) -{ - rect->xmin = floorf(x + (float)g->pos[0]); - rect->xmax = rect->xmin + (float)g->dims[0]; - rect->ymin = floorf(y + (float)g->pos[1]); - rect->ymax = rect->ymin - (float)g->dims[1]; -} - -static void blf_glyph_calc_rect_test(rctf *rect, GlyphBLF *g, float x, float y) -{ - /* Intentionally check with g->advance, because this is the - * width used by BLF_width. This allows that the text slightly - * overlaps the clipping border to achieve better alignment. */ - rect->xmin = floorf(x); - rect->xmax = rect->xmin + MIN2(g->advance, (float)g->dims[0]); - rect->ymin = floorf(y); - rect->ymax = rect->ymin - (float)g->dims[1]; -} - -static void blf_glyph_calc_rect_shadow(rctf *rect, GlyphBLF *g, float x, float y, FontBLF *font) -{ - blf_glyph_calc_rect(rect, g, x + (float)font->shadow_x, y + (float)font->shadow_y); -} - -void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y) +void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, float y) { if ((!g->dims[0]) || (!g->dims[1])) { return; @@ -526,3 +691,5 @@ void blf_glyph_render(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, float x, fl blf_texture_draw(font->color, g->dims, g->offset, rect.xmin, rect.ymin, rect.xmax, rect.ymax); #endif } + +/** \} */ diff --git a/source/blender/blenfont/intern/blf_internal.h b/source/blender/blenfont/intern/blf_internal.h index 6fd5e8b7503..cec20995dc6 100644 --- a/source/blender/blenfont/intern/blf_internal.h +++ b/source/blender/blenfont/intern/blf_internal.h @@ -52,7 +52,7 @@ struct FontBLF *blf_font_new(const char *name, const char *filename); struct FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size); void blf_font_attach_from_mem(struct FontBLF *font, const unsigned char *mem, int mem_size); -void blf_font_size(struct FontBLF *font, unsigned int size, unsigned int dpi); +void blf_font_size(struct FontBLF *font, float size, unsigned int dpi); void blf_font_draw(struct FontBLF *font, const char *str, size_t str_len, @@ -130,23 +130,17 @@ int blf_font_count_missing_chars(struct FontBLF *font, void blf_font_free(struct FontBLF *font); -struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, - unsigned int size, - unsigned int dpi); +struct GlyphCacheBLF *blf_glyph_cache_find(struct FontBLF *font, float size, unsigned int dpi); struct GlyphCacheBLF *blf_glyph_cache_new(struct FontBLF *font); struct GlyphCacheBLF *blf_glyph_cache_acquire(struct FontBLF *font); void blf_glyph_cache_release(struct FontBLF *font); void blf_glyph_cache_clear(struct FontBLF *font); void blf_glyph_cache_free(struct GlyphCacheBLF *gc); -struct GlyphBLF *blf_glyph_search(struct GlyphCacheBLF *gc, unsigned int c); -struct GlyphBLF *blf_glyph_add(struct FontBLF *font, - struct GlyphCacheBLF *gc, - unsigned int index, - unsigned int c); +struct GlyphBLF *blf_glyph_ensure(struct FontBLF *font, struct GlyphCacheBLF *gc, uint charcode); void blf_glyph_free(struct GlyphBLF *g); -void blf_glyph_render( +void blf_glyph_draw( struct FontBLF *font, struct GlyphCacheBLF *gc, struct GlyphBLF *g, float x, float y); #ifdef WIN32 diff --git a/source/blender/blenfont/intern/blf_internal_types.h b/source/blender/blenfont/intern/blf_internal_types.h index e90f82da7f3..46156edbb1f 100644 --- a/source/blender/blenfont/intern/blf_internal_types.h +++ b/source/blender/blenfont/intern/blf_internal_types.h @@ -65,7 +65,7 @@ typedef struct GlyphCacheBLF { struct GlyphCacheBLF *prev; /* font size. */ - unsigned int size; + float size; /* and dpi. */ unsigned int dpi; @@ -86,13 +86,6 @@ typedef struct GlyphCacheBLF { int bitmap_len_landed; int bitmap_len_alloc; - /* and the bigger glyph in the font. */ - int glyph_width_max; - int glyph_height_max; - - /* ascender and descender value. */ - float ascender; - float descender; } GlyphCacheBLF; typedef struct GlyphBLF { @@ -212,7 +205,10 @@ typedef struct FontBLF { unsigned int dpi; /* font size. */ - unsigned int size; + float size; + + /* Column width when printing monospaced. */ + int fixed_width; /* max texture size. */ int tex_size_max; diff --git a/source/blender/blenfont/intern/blf_thumbs.c b/source/blender/blenfont/intern/blf_thumbs.c index 3153a55b697..bbdb26a61b6 100644 --- a/source/blender/blenfont/intern/blf_thumbs.c +++ b/source/blender/blenfont/intern/blf_thumbs.c @@ -95,7 +95,7 @@ void BLF_thumb_preview(const char *filename, const size_t draw_str_i18n_len = strlen(draw_str_i18n); int draw_str_i18n_nbr = 0; - blf_font_size(font, (unsigned int)MAX2(font_size_min, font_size_curr), dpi); + blf_font_size(font, (float)MAX2(font_size_min, font_size_curr), dpi); gc = blf_glyph_cache_find(font, font->size, font->dpi); /* There will be no matching glyph cache if blf_font_size() failed to set font size. */ if (!gc) { @@ -106,7 +106,7 @@ void BLF_thumb_preview(const char *filename, font_size_curr -= (font_size_curr / font_shrink); font_shrink += 1; - font->pos[1] -= gc->ascender * 1.1f; + font->pos[1] -= blf_font_ascender(font) * 1.1f; /* We fallback to default english strings in case not enough chars are available in current * font for given translated string (useful in non-latin i18n context, like Chinese, diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index db55daddba6..763e540fdd9 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -128,11 +128,12 @@ void action_groups_clear_tempflags(struct bAction *act); /** * Return whether the action has one unique point in time keyed. * - * This is mostly for the pose library, which will have different behaviour depending on whether an + * This is mostly for the pose library, which will have different behavior depending on whether an * Action corresponds to a "pose" (one keyframe) or "animation snippet" (multiple keyframes). * * \return `false` when there is no keyframe at all or keys on different points in time, `true` - * when exactly one point in time is keyed. */ + * when exactly one point in time is keyed. + */ bool BKE_action_has_single_frame(const struct bAction *act); /* Pose API ----------------- */ diff --git a/source/blender/blenkernel/BKE_asset_catalog.hh b/source/blender/blenkernel/BKE_asset_catalog.hh index bdb77571711..d071f782bd6 100644 --- a/source/blender/blenkernel/BKE_asset_catalog.hh +++ b/source/blender/blenkernel/BKE_asset_catalog.hh @@ -443,7 +443,9 @@ class AssetCatalog { * Simple, human-readable name for the asset catalog. This is stored on assets alongside the * catalog ID; the catalog ID is a UUID that is not human-readable, * so to avoid complete data-loss when the catalog definition file gets lost, - * we also store a human-readable simple name for the catalog. */ + * we also store a human-readable simple name for the catalog. + * + * It should fit in sizeof(AssetMetaData::catalog_simple_name) bytes. */ std::string simple_name; struct Flags { diff --git a/source/blender/blenkernel/BKE_attribute.h b/source/blender/blenkernel/BKE_attribute.h index 7476474258b..2c83bef7517 100644 --- a/source/blender/blenkernel/BKE_attribute.h +++ b/source/blender/blenkernel/BKE_attribute.h @@ -43,12 +43,13 @@ struct ReportList; * Arrays may be initialized from this (e.g. #DATASET_layout_hierarchy). */ typedef enum AttributeDomain { - ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ - ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ - ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ - ATTR_DOMAIN_FACE = 2, /* Mesh Face */ - ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ - ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_AUTO = -1, /* Use for nodes to choose automatically based on other data. */ + ATTR_DOMAIN_POINT = 0, /* Mesh, Hair or PointCloud Point */ + ATTR_DOMAIN_EDGE = 1, /* Mesh Edge */ + ATTR_DOMAIN_FACE = 2, /* Mesh Face */ + ATTR_DOMAIN_CORNER = 3, /* Mesh Corner */ + ATTR_DOMAIN_CURVE = 4, /* Hair Curve */ + ATTR_DOMAIN_INSTANCE = 5, /* Instance */ ATTR_DOMAIN_NUM } AttributeDomain; diff --git a/source/blender/blenkernel/BKE_attribute_access.hh b/source/blender/blenkernel/BKE_attribute_access.hh index 6a87375e5e2..47f62b52a0f 100644 --- a/source/blender/blenkernel/BKE_attribute_access.hh +++ b/source/blender/blenkernel/BKE_attribute_access.hh @@ -115,10 +115,10 @@ struct AttributeInitDefault : public AttributeInit { * Note that this can be used to fill the new attribute with the default */ struct AttributeInitVArray : public AttributeInit { - const blender::fn::GVArray *varray; + blender::fn::GVArray varray; - AttributeInitVArray(const blender::fn::GVArray *varray) - : AttributeInit(Type::VArray), varray(varray) + AttributeInitVArray(blender::fn::GVArray varray) + : AttributeInit(Type::VArray), varray(std::move(varray)) { } }; @@ -150,9 +150,7 @@ namespace blender::bke { using fn::CPPType; using fn::GVArray; -using fn::GVArrayPtr; using fn::GVMutableArray; -using fn::GVMutableArrayPtr; const CPPType *custom_data_type_to_cpp_type(const CustomDataType type); CustomDataType cpp_type_to_custom_data_type(const CPPType &type); @@ -164,14 +162,14 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) */ struct ReadAttributeLookup { /* The virtual array that is used to read from this attribute. */ - GVArrayPtr varray; + GVArray varray; /* Domain the attribute lives on in the geometry. */ AttributeDomain domain; /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -180,7 +178,7 @@ struct ReadAttributeLookup { */ struct WriteAttributeLookup { /* The virtual array that is used to read from and write to the attribute. */ - GVMutableArrayPtr varray; + GVMutableArray varray; /* Domain the attributes lives on in the geometry. */ AttributeDomain domain; /* Call this after changing the attribute to invalidate caches that depend on this attribute. */ @@ -189,7 +187,7 @@ struct WriteAttributeLookup { /* Convenience function to check if the attribute has been found. */ operator bool() const { - return this->varray.get() != nullptr; + return this->varray; } }; @@ -209,7 +207,7 @@ class OutputAttribute { using SaveFn = std::function<void(OutputAttribute &)>; private: - GVMutableArrayPtr varray_; + GVMutableArray varray_; AttributeDomain domain_ = ATTR_DOMAIN_AUTO; SaveFn save_; std::unique_ptr<fn::GVMutableArray_GSpan> optional_span_varray_; @@ -219,7 +217,7 @@ class OutputAttribute { public: OutputAttribute(); OutputAttribute(OutputAttribute &&other); - OutputAttribute(GVMutableArrayPtr varray, + OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values); @@ -229,7 +227,7 @@ class OutputAttribute { operator bool() const; GVMutableArray &operator*(); - GVMutableArray *operator->(); + fn::GVMutableArray *operator->(); GVMutableArray &varray(); AttributeDomain domain() const; const CPPType &cpp_type() const; @@ -247,16 +245,14 @@ class OutputAttribute { template<typename T> class OutputAttribute_Typed { private: OutputAttribute attribute_; - std::unique_ptr<fn::GVMutableArray_Typed<T>> optional_varray_; - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: OutputAttribute_Typed(); OutputAttribute_Typed(OutputAttribute attribute) : attribute_(std::move(attribute)) { if (attribute_) { - optional_varray_ = std::make_unique<fn::GVMutableArray_Typed<T>>(attribute_.varray()); - varray_ = &**optional_varray_; + varray_ = attribute_.varray().template typed<T>(); } } @@ -275,22 +271,22 @@ template<typename T> class OutputAttribute_Typed { operator bool() const { - return varray_ != nullptr; + return varray_; } VMutableArray<T> &operator*() { - return *varray_; + return varray_; } VMutableArray<T> *operator->() { - return varray_; + return &varray_; } VMutableArray<T> &varray() { - return *varray_; + return varray_; } AttributeDomain domain() const @@ -351,18 +347,17 @@ class CustomDataAttributes { std::optional<blender::fn::GSpan> get_for_read(const AttributeIDRef &attribute_id) const; - blender::fn::GVArrayPtr get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const; + blender::fn::GVArray get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const; template<typename T> - blender::fn::GVArray_Typed<T> get_for_read(const AttributeIDRef &attribute_id, - const T &default_value) const + blender::VArray<T> get_for_read(const AttributeIDRef &attribute_id, const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - GVArrayPtr varray = this->get_for_read(attribute_id, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_for_read(attribute_id, type, &default_value); + return varray.typed<T>(); } std::optional<blender::fn::GMutableSpan> get_for_write(const AttributeIDRef &attribute_id); @@ -465,7 +460,7 @@ inline bool AttributeIDRef::should_be_kept() const inline OutputAttribute::OutputAttribute() = default; inline OutputAttribute::OutputAttribute(OutputAttribute &&other) = default; -inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, +inline OutputAttribute::OutputAttribute(GVMutableArray varray, AttributeDomain domain, SaveFn save, const bool ignore_old_values) @@ -478,22 +473,22 @@ inline OutputAttribute::OutputAttribute(GVMutableArrayPtr varray, inline OutputAttribute::operator bool() const { - return varray_.get() != nullptr; + return varray_; } inline GVMutableArray &OutputAttribute::operator*() { - return *varray_; + return varray_; } -inline GVMutableArray *OutputAttribute::operator->() +inline fn::GVMutableArray *OutputAttribute::operator->() { - return varray_.get(); + return &varray_; } inline GVMutableArray &OutputAttribute::varray() { - return *varray_; + return varray_; } inline AttributeDomain OutputAttribute::domain() const @@ -503,7 +498,7 @@ inline AttributeDomain OutputAttribute::domain() const inline const CPPType &OutputAttribute::cpp_type() const { - return varray_->type(); + return varray_.type(); } inline CustomDataType OutputAttribute::custom_data_type() const diff --git a/source/blender/blenkernel/BKE_blender_copybuffer.h b/source/blender/blenkernel/BKE_blender_copybuffer.h index 1dd6d495276..4dd7145e66d 100644 --- a/source/blender/blenkernel/BKE_blender_copybuffer.h +++ b/source/blender/blenkernel/BKE_blender_copybuffer.h @@ -31,16 +31,18 @@ struct ReportList; struct bContext; /* copybuffer (wrapper for BKE_blendfile_write_partial) */ -void BKE_copybuffer_begin(struct Main *bmain_src); -void BKE_copybuffer_tag_ID(struct ID *id); -bool BKE_copybuffer_save(struct Main *bmain_src, const char *filename, struct ReportList *reports); +void BKE_copybuffer_copy_begin(struct Main *bmain_src); +void BKE_copybuffer_copy_tag_ID(struct ID *id); +bool BKE_copybuffer_copy_end(struct Main *bmain_src, + const char *filename, + struct ReportList *reports); bool BKE_copybuffer_read(struct Main *bmain_dst, const char *libname, struct ReportList *reports, const uint64_t id_types_mask); int BKE_copybuffer_paste(struct bContext *C, const char *libname, - const short flag, + const int flag, struct ReportList *reports, const uint64_t id_types_mask); diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 326ca746292..966d6c95421 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -31,15 +31,15 @@ extern "C" { */ /* Blender major and minor version. */ -#define BLENDER_VERSION 300 +#define BLENDER_VERSION 301 /* Blender patch version for bugfix releases. */ #define BLENDER_VERSION_PATCH 0 /** Blender release cycle stage: alpha/beta/rc/release. */ -#define BLENDER_VERSION_CYCLE beta +#define BLENDER_VERSION_CYCLE alpha /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 42 +#define BLENDER_FILE_SUBVERSION 3 /* 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_blendfile_link_append.h b/source/blender/blenkernel/BKE_blendfile_link_append.h new file mode 100644 index 00000000000..9e4a498f5e7 --- /dev/null +++ b/source/blender/blenkernel/BKE_blendfile_link_append.h @@ -0,0 +1,112 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#pragma once + +/** \file + * \ingroup bke + */ + +#ifdef __cplusplus +extern "C" { +#endif + +struct BlendHandle; +struct ID; +struct Library; +struct LibraryLink_Params; +struct Main; +struct ReportList; +struct Scene; +struct ViewLayer; +struct View3D; + +typedef struct BlendfileLinkAppendContext BlendfileLinkAppendContext; +typedef struct BlendfileLinkAppendContextItem BlendfileLinkAppendContextItem; + +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new( + struct LibraryLink_Params *params); +void BKE_blendfile_link_append_context_free(struct BlendfileLinkAppendContext *lapp_context); +void BKE_blendfile_link_append_context_flag_set(struct BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set); + +void BKE_blendfile_link_append_context_embedded_blendfile_set( + struct BlendfileLinkAppendContext *lapp_context, + const void *blendfile_mem, + int blendfile_memsize); +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + struct BlendfileLinkAppendContext *lapp_context); + +void BKE_blendfile_link_append_context_library_add(struct BlendfileLinkAppendContext *lapp_context, + const char *libname, + struct BlendHandle *blo_handle); +struct BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + struct BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata); +void BKE_blendfile_link_append_context_item_library_index_enable( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + const int library_index); +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context); + +void *BKE_blendfile_link_append_context_item_userdata_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +struct ID *BKE_blendfile_link_append_context_item_newid_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *lapp_context, struct BlendfileLinkAppendContextItem *item); + +typedef enum eBlendfileLinkAppendForeachItemFlag { + /** Loop over directly linked items (i.e. those explicitely defined by user code). */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT = 1 << 0, + /** Loop over indirectly linked items (i.e. those defined by internal code, as dependencies of + * direct ones). + * + * IMPORTANT: Those 'indirect' items currently may not cover **all** indrectly linked data. See + * comments in #foreach_libblock_link_append_callback. */ + BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT = 1 << 0, +} eBlendfileLinkAppendForeachItemFlag; +/** Callback called by #BKE_blendfile_link_append_context_item_foreach over each (or a subset of + * each) of the items in given #BlendfileLinkAppendContext. + * + * \param userdata: An opaque void pointer passed to the `callback_function`. + * + * \return `true` if iteration should continue, `false` otherwise. */ +typedef bool (*BKE_BlendfileLinkAppendContexteItemFunction)( + struct BlendfileLinkAppendContext *lapp_context, + struct BlendfileLinkAppendContextItem *item, + void *userdata); +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata); + +void BKE_blendfile_append(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); +void BKE_blendfile_link(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports); + +void BKE_blendfile_library_relocate(struct BlendfileLinkAppendContext *lapp_context, + struct ReportList *reports, + struct Library *library, + const bool do_reload); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index 452a08bc9c8..c5f1af4c755 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -78,7 +78,7 @@ void BKE_brush_randomize_texture_coords(struct UnifiedPaintSettings *ups, bool m /* brush curve */ void BKE_brush_curve_preset(struct Brush *b, enum eCurveMappingPreset preset); -float BKE_brush_curve_strength_clamped(struct Brush *br, float p, const float len); +float BKE_brush_curve_strength_clamped(const struct Brush *br, float p, const float len); float BKE_brush_curve_strength(const struct Brush *br, float p, const float len); /* sampling */ diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index 58a89d0207a..35e66908d54 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -119,10 +119,21 @@ class GeometryComponent { /* Get a read-only attribute for the domain based on the given attribute. This can be used to * interpolate from one domain to another. * Returns null if the interpolation is not implemented. */ - virtual std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const; + blender::fn::GVArray attribute_try_adapt_domain(const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain); + } + + template<typename T> + blender::VArray<T> attribute_try_adapt_domain(const blender::VArray<T> &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const + { + return this->attribute_try_adapt_domain_impl(varray, from_domain, to_domain) + .template typed<T>(); + } /* Returns true when the attribute has been deleted. */ bool attribute_try_delete(const blender::bke::AttributeIDRef &attribute_id); @@ -146,16 +157,15 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute on the given domain and data type. * Returns null when the attribute does not exist or cannot be converted to the requested domain * and data type. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type) const; /* Get a virtual array to read the data of an attribute on the given domain. The data type is * left unchanged. Returns null when the attribute does not exist or cannot be adapted to the * requested domain. */ - std::unique_ptr<blender::fn::GVArray> attribute_try_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, const AttributeDomain domain) const; + blender::fn::GVArray attribute_try_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain) const; /* Get a virtual array to read data of an attribute with the given data type. The domain is * left unchanged. Returns null when the attribute does not exist or cannot be converted to the @@ -165,25 +175,22 @@ class GeometryComponent { /* Get a virtual array to read the data of an attribute. If that is not possible, the returned * virtual array will contain a default value. This never returns null. */ - std::unique_ptr<blender::fn::GVArray> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value = nullptr) const; + blender::fn::GVArray attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value = nullptr) const; /* Should be used instead of the method above when the requested data type is known at compile * time for better type safety. */ template<typename T> - blender::fn::GVArray_Typed<T> attribute_get_for_read( - const blender::bke::AttributeIDRef &attribute_id, - const AttributeDomain domain, - const T &default_value) const + blender::VArray<T> attribute_get_for_read(const blender::bke::AttributeIDRef &attribute_id, + const AttributeDomain domain, + const T &default_value) const { const blender::fn::CPPType &cpp_type = blender::fn::CPPType::get<T>(); const CustomDataType type = blender::bke::cpp_type_to_custom_data_type(cpp_type); - std::unique_ptr varray = this->attribute_get_for_read( - attribute_id, domain, type, &default_value); - return blender::fn::GVArray_Typed<T>(std::move(varray)); + return this->attribute_get_for_read(attribute_id, domain, type, &default_value) + .template typed<T>(); } /** @@ -234,6 +241,11 @@ class GeometryComponent { private: virtual const blender::bke::ComponentAttributeProviders *get_attribute_providers() const; + + virtual blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const; }; template<typename T> @@ -391,10 +403,6 @@ class MeshComponent : public GeometryComponent { Mesh *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -405,6 +413,11 @@ class MeshComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; /** A geometry component that stores a point cloud. */ @@ -469,10 +482,6 @@ class CurveComponent : public GeometryComponent { CurveEval *get_for_write(); int attribute_domain_size(const AttributeDomain domain) const final; - std::unique_ptr<blender::fn::GVArray> attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const final; bool is_empty() const final; @@ -485,6 +494,11 @@ class CurveComponent : public GeometryComponent { private: const blender::bke::ComponentAttributeProviders *get_attribute_providers() const final; + + blender::fn::GVArray attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const final; }; class InstanceReference { @@ -637,6 +651,8 @@ class InstancesComponent : public GeometryComponent { mutable std::mutex almost_unique_ids_mutex_; mutable blender::Array<int> almost_unique_ids_; + blender::bke::CustomDataAttributes attributes_; + public: InstancesComponent(); ~InstancesComponent() = default; @@ -671,6 +687,9 @@ class InstancesComponent : public GeometryComponent { blender::Span<int> almost_unique_ids() const; + blender::bke::CustomDataAttributes &attributes(); + const blender::bke::CustomDataAttributes &attributes() const; + int attribute_domain_size(const AttributeDomain domain) const final; void foreach_referenced_geometry( @@ -759,9 +778,9 @@ class AttributeFieldInput : public fn::FieldInput { return name_; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -776,9 +795,9 @@ class IDAttributeFieldInput : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; @@ -815,9 +834,9 @@ class AnonymousAttributeFieldInput : public fn::FieldInput { return fn::Field<T>{field_input}; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const override; + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const override; std::string socket_inspection_name() const override; diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index bacdd4adc76..d6cabbc1236 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -45,7 +45,6 @@ typedef struct Global { /** When set: `G_MAIN->name` contains valid relative base path. */ bool relbase_valid; - bool file_loaded; bool save_over; /** Strings of recent opened files. */ @@ -212,9 +211,9 @@ enum { G_TRANSFORM_FCURVES = (1 << 3), G_TRANSFORM_WM = (1 << 4), /** - * Set when transforming the cursor it's self. + * Set when transforming the cursor itself. * Used as a hint to draw the cursor (even when hidden). - * Otherwise it's not possible to see whats being transformed. + * Otherwise it's not possible to see what's being transformed. */ G_TRANSFORM_CURSOR = (1 << 5), }; diff --git a/source/blender/blenkernel/BKE_gpencil_geom.h b/source/blender/blenkernel/BKE_gpencil_geom.h index a9cd553a8fe..41b1bba10ba 100644 --- a/source/blender/blenkernel/BKE_gpencil_geom.h +++ b/source/blender/blenkernel/BKE_gpencil_geom.h @@ -128,8 +128,9 @@ struct bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(struct bGPdata *gpd, struct bGPDstroke *gps, struct bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit); + const bool select, + const bool flat_cap, + const int limit); void BKE_gpencil_curve_delete_tagged_points(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index 7a8c55071df..77f1d197844 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -47,9 +47,6 @@ struct anim; #define IMA_MAX_SPACE 64 #define IMA_UDIM_MAX 2000 -void BKE_images_init(void); -void BKE_images_exit(void); - void BKE_image_free_packedfiles(struct Image *image); void BKE_image_free_views(struct Image *image); void BKE_image_free_buffers(struct Image *image); diff --git a/source/blender/blenkernel/BKE_layer.h b/source/blender/blenkernel/BKE_layer.h index c8af1a91725..08b44959096 100644 --- a/source/blender/blenkernel/BKE_layer.h +++ b/source/blender/blenkernel/BKE_layer.h @@ -328,7 +328,7 @@ void BKE_view_layer_visible_bases_iterator_end(BLI_Iterator *iter); { \ Object *_instance; \ Base *_base; \ - for (_base = (view_layer)->object_bases.first; _base; _base = _base->next) { \ + for (_base = (Base *)(view_layer)->object_bases.first; _base; _base = _base->next) { \ _instance = _base->object; #define FOREACH_OBJECT_END \ diff --git a/source/blender/blenkernel/BKE_lib_id.h b/source/blender/blenkernel/BKE_lib_id.h index 68399959a37..359fb72534a 100644 --- a/source/blender/blenkernel/BKE_lib_id.h +++ b/source/blender/blenkernel/BKE_lib_id.h @@ -137,8 +137,10 @@ enum { LIB_ID_COPY_SHAPEKEY = 1 << 26, /** EXCEPTION! Specific deep-copy of node trees used e.g. for rendering purposes. */ LIB_ID_COPY_NODETREE_LOCALIZE = 1 << 27, - /** EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we - duplicate scene/collections, or objects. */ + /** + * EXCEPTION! Specific handling of RB objects regarding collections differs depending whether we + * duplicate scene/collections, or objects. + */ LIB_ID_COPY_RIGID_BODY_NO_COLLECTION_HANDLING = 1 << 28, /* *** Helper 'defines' gathering most common flag sets. *** */ diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index 957a623577e..30c742e3af6 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -143,7 +143,8 @@ enum { typedef struct LibraryForeachIDData LibraryForeachIDData; -bool BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data, +bool BKE_lib_query_foreachid_iter_stop(struct LibraryForeachIDData *data); +void BKE_lib_query_foreachid_process(struct LibraryForeachIDData *data, struct ID **id_pp, int cb_flag); int BKE_lib_query_foreachid_process_flags_get(struct LibraryForeachIDData *data); @@ -154,7 +155,8 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach #define BKE_LIB_FOREACHID_PROCESS_ID(_data, _id, _cb_flag) \ { \ CHECK_TYPE_ANY((_id), ID *, void *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return; \ } \ } \ @@ -163,13 +165,23 @@ int BKE_lib_query_foreachid_process_callback_flag_override(struct LibraryForeach #define BKE_LIB_FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \ { \ CHECK_TYPE(&((_id_super)->id), ID *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return; \ } \ } \ ((void)0) -bool BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp); +#define BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(_data, _func_call) \ + { \ + _func_call; \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ + return; \ + } \ + } \ + ((void)0) + +void BKE_library_foreach_ID_embedded(struct LibraryForeachIDData *data, struct ID **id_pp); void BKE_lib_query_idpropertiesForeachIDLink_callback(struct IDProperty *id_prop, void *user_data); /* Loop over all of the ID's this datablock links to. */ diff --git a/source/blender/blenkernel/BKE_lib_remap.h b/source/blender/blenkernel/BKE_lib_remap.h index c70521f9593..5e154459a6c 100644 --- a/source/blender/blenkernel/BKE_lib_remap.h +++ b/source/blender/blenkernel/BKE_lib_remap.h @@ -89,6 +89,12 @@ enum { * dealing with IDs temporarily out of Main, but which will be put in it ultimately). */ ID_REMAP_FORCE_USER_REFCOUNT = 1 << 8, + /** + * Force obdata pointers to also be processed, even when object (`id_owner`) is in Edit mode. + * This is required by some tools creating/deleting IDs while operating in Edit mode, like e.g. + * the 'separate' mesh operator. + */ + ID_REMAP_FORCE_OBDATA_IN_EDITMODE = 1 << 9, }; /* NOTE: Requiring new_id to be non-null, this *may* not be the case ultimately, @@ -111,8 +117,8 @@ void BKE_libblock_relink_ex(struct Main *bmain, void *new_idv, const short remap_flags) ATTR_NONNULL(1, 2); -void BKE_libblock_relink_to_newid(struct ID *id) ATTR_NONNULL(); -void BKE_libblock_relink_to_newid_new(struct Main *bmain, struct ID *id) ATTR_NONNULL(); +void BKE_libblock_relink_to_newid(struct Main *bmain, struct ID *id, const int remap_flag) + ATTR_NONNULL(); typedef void (*BKE_library_free_notifier_reference_cb)(const void *); typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 58fea6d462c..5ed1b512fd5 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -121,12 +121,11 @@ class MFDataType; } // namespace fn } // namespace blender +using CPPTypeHandle = blender::fn::CPPType; using NodeMultiFunctionBuildFunction = void (*)(blender::nodes::NodeMultiFunctionBuilder &builder); using NodeGeometryExecFunction = void (*)(blender::nodes::GeoNodeExecParams params); using NodeDeclareFunction = void (*)(blender::nodes::NodeDeclarationBuilder &builder); -using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); -using SocketGetGeometryNodesCPPTypeFunction = const blender::fn::CPPType *(*)(); using SocketGetGeometryNodesCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value); @@ -138,6 +137,7 @@ typedef void *SocketGetCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPTypeFunction; typedef void *SocketGetGeometryNodesCPPValueFunction; typedef void *SocketGetCPPValueFunction; +typedef struct CPPTypeHandle CPPTypeHandle; #endif /** @@ -197,11 +197,11 @@ typedef struct bNodeSocketType { void (*free_self)(struct bNodeSocketType *stype); /* Return the CPPType of this socket. */ - SocketGetCPPTypeFunction get_base_cpp_type; + const CPPTypeHandle *base_cpp_type; /* Get the value of this socket in a generic way. */ SocketGetCPPValueFunction get_base_cpp_value; /* Get geometry nodes cpp type. */ - SocketGetGeometryNodesCPPTypeFunction get_geometry_nodes_cpp_type; + const CPPTypeHandle *geometry_nodes_cpp_type; /* Get geometry nodes cpp value. */ SocketGetGeometryNodesCPPValueFunction get_geometry_nodes_cpp_value; } bNodeSocketType; @@ -318,8 +318,6 @@ typedef struct bNodeType { /* optional handling of link insertion */ void (*insert_link)(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); - /* Update the internal links list, for muting and disconnect operators. */ - void (*update_internal_links)(struct bNodeTree *, struct bNode *node); void (*free_self)(struct bNodeType *ntype); @@ -344,6 +342,9 @@ typedef struct bNodeType { /* Declaration to be used when it is not dynamic. */ NodeDeclarationHandle *fixed_declaration; + /** True when the node cannot be muted. */ + bool no_muting; + /* RNA integration */ ExtensionRNA rna_ext; } bNodeType; @@ -731,11 +732,15 @@ void nodeUpdateInternalLinks(struct bNodeTree *ntree, struct bNode *node); int nodeSocketIsHidden(const struct bNodeSocket *sock); void ntreeTagUsedSockets(struct bNodeTree *ntree); -void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available); +void nodeSetSocketAvailability(struct bNodeTree *ntree, + struct bNodeSocket *sock, + bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); -void nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node); +bool nodeDeclarationEnsure(struct bNodeTree *ntree, struct bNode *node); +bool nodeDeclarationEnsureOnOutdatedNode(struct bNodeTree *ntree, struct bNode *node); +void nodeSocketDeclarationsUpdate(struct bNode *node); /* Node Clipboard */ void BKE_node_clipboard_init(const struct bNodeTree *ntree); @@ -887,8 +892,6 @@ void node_type_exec(struct bNodeType *ntype, NodeFreeExecFunction free_exec_fn, NodeExecFunction exec_fn); void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); -void node_type_internal_links(struct bNodeType *ntype, - void (*update_internal_links)(struct bNodeTree *, struct bNode *)); /** \} */ diff --git a/source/blender/blenkernel/BKE_spline.hh b/source/blender/blenkernel/BKE_spline.hh index 55a4f6ffcfd..67eaa7c12c9 100644 --- a/source/blender/blenkernel/BKE_spline.hh +++ b/source/blender/blenkernel/BKE_spline.hh @@ -187,14 +187,14 @@ class Spline { blender::MutableSpan<T> dst) const { this->sample_with_index_factors( - blender::fn::GVArray_For_VArray(src), index_factors, blender::fn::GMutableSpan(dst)); + blender::fn::GVArray(src), index_factors, blender::fn::GMutableSpan(dst)); } template<typename T> void sample_with_index_factors(blender::Span<T> src, blender::Span<float> index_factors, blender::MutableSpan<T> dst) const { - this->sample_with_index_factors(blender::VArray_For_Span(src), index_factors, dst); + this->sample_with_index_factors(blender::VArray<T>::ForSpan(src), index_factors, dst); } /** @@ -202,13 +202,11 @@ class Spline { * evaluated points. For poly splines, the lifetime of the returned virtual array must not * exceed the lifetime of the input data. */ - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( - const blender::fn::GVArray &src) const = 0; - blender::fn::GVArrayPtr interpolate_to_evaluated(blender::fn::GSpan data) const; - template<typename T> - blender::fn::GVArray_Typed<T> interpolate_to_evaluated(blender::Span<T> data) const + virtual blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const = 0; + blender::fn::GVArray interpolate_to_evaluated(blender::fn::GSpan data) const; + template<typename T> blender::VArray<T> interpolate_to_evaluated(blender::Span<T> data) const { - return blender::fn::GVArray_Typed<T>(this->interpolate_to_evaluated(blender::fn::GSpan(data))); + return this->interpolate_to_evaluated(blender::fn::GSpan(data)).typed<T>(); } protected: @@ -307,20 +305,20 @@ class BezierSpline final : public Spline { blender::MutableSpan<HandleType> handle_types_left(); blender::Span<blender::float3> handle_positions_left() const; /** - * Get writable access to the hande position. + * Get writable access to the handle position. * * \param write_only: pass true for an uninitialized spline, this prevents accessing - * uninitialized memory while autogenerating handles. + * uninitialized memory while auto-generating handles. */ blender::MutableSpan<blender::float3> handle_positions_left(bool write_only = false); blender::Span<HandleType> handle_types_right() const; blender::MutableSpan<HandleType> handle_types_right(); blender::Span<blender::float3> handle_positions_right() const; /** - * Get writable access to the hande position. + * Get writable access to the handle position. * * \param write_only: pass true for an uninitialized spline, this prevents accessing - * uninitialized memory while autogenerating handles. + * uninitialized memory while auto-generating handles. */ blender::MutableSpan<blender::float3> handle_positions_right(bool write_only = false); void ensure_auto_handles() const; @@ -350,7 +348,7 @@ class BezierSpline final : public Spline { }; InterpolationData interpolation_data_from_index_factor(const float index_factor) const; - virtual blender::fn::GVArrayPtr interpolate_to_evaluated( + virtual blender::fn::GVArray interpolate_to_evaluated( const blender::fn::GVArray &src) const override; void evaluate_segment(const int index, @@ -487,7 +485,7 @@ class NURBSpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -538,7 +536,7 @@ class PolySpline final : public Spline { blender::Span<blender::float3> evaluated_positions() const final; - blender::fn::GVArrayPtr interpolate_to_evaluated(const blender::fn::GVArray &src) const final; + blender::fn::GVArray interpolate_to_evaluated(const blender::fn::GVArray &src) const final; protected: void correct_end_tangents() const final; @@ -582,6 +580,9 @@ struct CurveEval { blender::Array<int> evaluated_point_offsets() const; blender::Array<float> accumulated_spline_lengths() const; + float total_length() const; + int total_control_point_size() const; + void mark_cache_invalid(); void assert_valid_point_attributes() const; diff --git a/source/blender/blenkernel/BKE_volume_to_mesh.hh b/source/blender/blenkernel/BKE_volume_to_mesh.hh index 9532da8c23c..dd8ae7ea554 100644 --- a/source/blender/blenkernel/BKE_volume_to_mesh.hh +++ b/source/blender/blenkernel/BKE_volume_to_mesh.hh @@ -14,6 +14,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#pragma once + #include "BLI_span.hh" #include "DNA_modifier_types.h" diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index d4ec7fd703d..a08f1b81dbe 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -100,6 +100,7 @@ set(SRC intern/blender_undo.c intern/blender_user_menu.c intern/blendfile.c + intern/blendfile_link_append.c intern/boids.c intern/bpath.c intern/brush.c @@ -192,7 +193,7 @@ set(SRC intern/material.c intern/mball.c intern/mball_tessellate.c - intern/mesh.c + intern/mesh.cc intern/mesh_boolean_convert.cc intern/mesh_convert.cc intern/mesh_evaluate.cc @@ -326,6 +327,7 @@ set(SRC BKE_blender_user_menu.h BKE_blender_version.h BKE_blendfile.h + BKE_blendfile_link_append.h BKE_boids.h BKE_bpath.h BKE_brush.h diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index 842902b51ed..2cc1cba99cd 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -176,7 +176,7 @@ static void action_foreach_id(ID *id, LibraryForeachIDData *data) bAction *act = (bAction *)id; LISTBASE_FOREACH (FCurve *, fcu, &act->curves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (TimeMarker *, marker, &act->markers) { diff --git a/source/blender/blenkernel/intern/anim_data.c b/source/blender/blenkernel/intern/anim_data.c index 23d2c4fe55f..21887d514d9 100644 --- a/source/blender/blenkernel/intern/anim_data.c +++ b/source/blender/blenkernel/intern/anim_data.c @@ -294,7 +294,7 @@ bool BKE_animdata_id_is_animated(const struct ID *id) void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data) { LISTBASE_FOREACH (FCurve *, fcu, &adt->drivers) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER); diff --git a/source/blender/blenkernel/intern/appdir.c b/source/blender/blenkernel/intern/appdir.c index 08a3b7d0bbb..d872dc67dcb 100644 --- a/source/blender/blenkernel/intern/appdir.c +++ b/source/blender/blenkernel/intern/appdir.c @@ -279,23 +279,31 @@ bool BKE_appdir_folder_caches(char *r_path, const size_t path_len) /** * Gets a good default directory for fonts. */ -bool BKE_appdir_font_folder_default( - /* This parameter can only be `const` on non-windows platforms. - * NOLINTNEXTLINE: readability-non-const-parameter. */ - char *dir) +bool BKE_appdir_font_folder_default(char *dir) { - bool success = false; + char test_dir[FILE_MAXDIR]; + test_dir[0] = '\0'; + #ifdef WIN32 wchar_t wpath[FILE_MAXDIR]; - success = SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0); - if (success) { + if (SHGetSpecialFolderPathW(0, wpath, CSIDL_FONTS, 0)) { wcscat(wpath, L"\\"); - BLI_strncpy_wchar_as_utf8(dir, wpath, FILE_MAXDIR); + BLI_strncpy_wchar_as_utf8(test_dir, wpath, sizeof(test_dir)); + } +#elif defined(__APPLE__) + const char *home = BLI_getenv("HOME"); + if (home) { + BLI_path_join(test_dir, sizeof(test_dir), home, "Library", "Fonts", NULL); } +#else + STRNCPY(test_dir, "/usr/share/fonts"); #endif - /* TODO: Values for other platforms. */ - UNUSED_VARS(dir); - return success; + + if (test_dir[0] && BLI_exists(test_dir)) { + BLI_strncpy(dir, test_dir, FILE_MAXDIR); + return true; + } + return false; } /** \} */ diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index b64b050f4e7..b830c9de5f5 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -161,30 +161,36 @@ static void armature_free_data(struct ID *id) static void armature_foreach_id_bone(Bone *bone, LibraryForeachIDData *data) { - IDP_foreach_property( - bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); LISTBASE_FOREACH (Bone *, curbone, &bone->childbase) { - armature_foreach_id_bone(curbone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(curbone, data)); } } static void armature_foreach_id_editbone(EditBone *edit_bone, LibraryForeachIDData *data) { - IDP_foreach_property( - edit_bone->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(edit_bone->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } static void armature_foreach_id(ID *id, LibraryForeachIDData *data) { bArmature *arm = (bArmature *)id; LISTBASE_FOREACH (Bone *, bone, &arm->bonebase) { - armature_foreach_id_bone(bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_bone(bone, data)); } if (arm->edbo != NULL) { LISTBASE_FOREACH (EditBone *, edit_bone, arm->edbo) { - armature_foreach_id_editbone(edit_bone, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, armature_foreach_id_editbone(edit_bone, data)); } } } diff --git a/source/blender/blenkernel/intern/asset.cc b/source/blender/blenkernel/intern/asset.cc index 7bea089b9bf..59e402b6680 100644 --- a/source/blender/blenkernel/intern/asset.cc +++ b/source/blender/blenkernel/intern/asset.cc @@ -21,14 +21,12 @@ #include <cstring> #include "DNA_ID.h" -#include "DNA_asset_types.h" #include "DNA_defaults.h" #include "BLI_listbase.h" #include "BLI_string.h" #include "BLI_string_ref.hh" #include "BLI_string_utils.h" -#include "BLI_utildefines.h" #include "BLI_uuid.h" #include "BKE_asset.h" diff --git a/source/blender/blenkernel/intern/asset_catalog.cc b/source/blender/blenkernel/intern/asset_catalog.cc index 33405c9aeae..9ef66d23aea 100644 --- a/source/blender/blenkernel/intern/asset_catalog.cc +++ b/source/blender/blenkernel/intern/asset_catalog.cc @@ -18,25 +18,20 @@ * \ingroup bke */ +#include <fstream> +#include <set> + #include "BKE_asset_catalog.hh" #include "BKE_asset_library.h" -#include "BKE_preferences.h" #include "BLI_fileops.h" #include "BLI_path_util.h" -#include "BLI_set.hh" -#include "BLI_string_ref.hh" - -#include "DNA_userdef_types.h" /* For S_ISREG() and S_ISDIR() on Windows. */ #ifdef WIN32 # include "BLI_winstuff.h" #endif -#include <fstream> -#include <set> - namespace blender::bke { const CatalogFilePath AssetCatalogService::DEFAULT_CATALOG_FILENAME = "blender_assets.cats.txt"; diff --git a/source/blender/blenkernel/intern/asset_catalog_test.cc b/source/blender/blenkernel/intern/asset_catalog_test.cc index 2cef34966f8..ba8f8716823 100644 --- a/source/blender/blenkernel/intern/asset_catalog_test.cc +++ b/source/blender/blenkernel/intern/asset_catalog_test.cc @@ -24,6 +24,7 @@ #include "BLI_fileops.h" #include "BLI_path_util.h" +#include "DNA_asset_types.h" #include "DNA_userdef_types.h" #include "testing/testing.h" @@ -930,6 +931,28 @@ TEST_F(AssetCatalogTest, update_catalog_path_simple_name) << "Changing the path should update the simplename of children."; } +TEST_F(AssetCatalogTest, update_catalog_path_longer_than_simplename) +{ + AssetCatalogService service(asset_library_root_); + service.load_from_disk(asset_library_root_ + "/" + + AssetCatalogService::DEFAULT_CATALOG_FILENAME); + const std::string new_path = + "this/is/a/very/long/path/that/exceeds/the/simple-name/length/of/assets"; + ASSERT_GT(new_path.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "This test case should work with paths longer than AssetMetaData::catalog_simple_name"; + + service.update_catalog_path(UUID_POSES_RUZENA, new_path); + + const std::string new_simple_name = service.find_catalog(UUID_POSES_RUZENA)->simple_name; + EXPECT_LT(new_simple_name.length(), sizeof(AssetMetaData::catalog_simple_name)) + << "The new simple name should fit in the asset metadata."; + EXPECT_EQ("...very-long-path-that-exceeds-the-simple-name-length-of-assets", new_simple_name) + << "Changing the path should update the simplename."; + EXPECT_EQ("...long-path-that-exceeds-the-simple-name-length-of-assets-face", + service.find_catalog(UUID_POSES_RUZENA_FACE)->simple_name) + << "Changing the path should update the simplename of children."; +} + TEST_F(AssetCatalogTest, update_catalog_path_add_slashes) { AssetCatalogService service(asset_library_root_); diff --git a/source/blender/blenkernel/intern/asset_library.cc b/source/blender/blenkernel/intern/asset_library.cc index aae8a289d32..68e43852a21 100644 --- a/source/blender/blenkernel/intern/asset_library.cc +++ b/source/blender/blenkernel/intern/asset_library.cc @@ -18,9 +18,9 @@ * \ingroup bke */ -#include "BKE_asset_catalog.hh" +#include <memory> + #include "BKE_asset_library.hh" -#include "BKE_callbacks.h" #include "BKE_main.h" #include "BKE_preferences.h" @@ -29,12 +29,8 @@ #include "DNA_asset_types.h" #include "DNA_userdef_types.h" -#include "MEM_guardedalloc.h" - #include "asset_library_service.hh" -#include <memory> - bool blender::bke::AssetLibrary::save_catalogs_when_file_is_saved = true; /** diff --git a/source/blender/blenkernel/intern/asset_library_service.cc b/source/blender/blenkernel/intern/asset_library_service.cc index 7cf95ee4cc1..d202d6462cf 100644 --- a/source/blender/blenkernel/intern/asset_library_service.cc +++ b/source/blender/blenkernel/intern/asset_library_service.cc @@ -20,16 +20,12 @@ #include "asset_library_service.hh" -#include "BKE_asset_library.hh" #include "BKE_blender.h" -#include "BKE_callbacks.h" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BLI_string_ref.hh" -#include "MEM_guardedalloc.h" - #include "CLG_log.h" static CLG_LogRef LOG = {"bke.asset_service"}; diff --git a/source/blender/blenkernel/intern/asset_library_service_test.cc b/source/blender/blenkernel/intern/asset_library_service_test.cc index e26ae05301e..ee910cab945 100644 --- a/source/blender/blenkernel/intern/asset_library_service_test.cc +++ b/source/blender/blenkernel/intern/asset_library_service_test.cc @@ -19,7 +19,7 @@ #include "asset_library_service.hh" -#include "BLI_fileops.h" +#include "BLI_fileops.h" /* For PATH_MAX (at least on Windows). */ #include "BLI_path_util.h" #include "BKE_appdir.h" diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index cd394a4ca42..3f2c1f13337 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -50,9 +50,7 @@ using blender::bke::AttributeIDRef; using blender::bke::OutputAttribute; using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_SingleValue; -using blender::fn::GVMutableArray_For_GMutableSpan; +using blender::fn::GVMutableArrayImpl_For_GMutableSpan; namespace blender::bke { @@ -166,16 +164,18 @@ CustomDataType attribute_data_type_highest_complexity(Span<CustomDataType> data_ static int attribute_domain_priority(const AttributeDomain domain) { switch (domain) { - case ATTR_DOMAIN_CURVE: + case ATTR_DOMAIN_INSTANCE: return 0; - case ATTR_DOMAIN_FACE: + case ATTR_DOMAIN_CURVE: return 1; - case ATTR_DOMAIN_EDGE: + case ATTR_DOMAIN_FACE: return 2; - case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_EDGE: return 3; - case ATTR_DOMAIN_CORNER: + case ATTR_DOMAIN_POINT: return 4; + case ATTR_DOMAIN_CORNER: + return 5; default: /* Domain not supported in nodes yet. */ BLI_assert_unreachable(); @@ -207,7 +207,7 @@ fn::GMutableSpan OutputAttribute::as_span() { if (!optional_span_varray_) { const bool materialize_old_values = !ignore_old_values_; - optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(*varray_, + optional_span_varray_ = std::make_unique<fn::GVMutableArray_GSpan>(varray_, materialize_old_values); } fn::GVMutableArray_GSpan &span_varray = *optional_span_varray_; @@ -257,8 +257,8 @@ static bool add_builtin_type_custom_data_layer_from_init(CustomData &custom_data if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -313,8 +313,8 @@ static bool add_custom_data_layer_from_attribute_init(const AttributeIDRef &attr if (data == nullptr) { return false; } - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), data); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), data); return true; } case AttributeInit::Type::MoveArray: { @@ -345,8 +345,7 @@ static bool custom_data_layer_matches_attribute_id(const CustomDataLayer &layer, return layer.name == attribute_id.name(); } -GVArrayPtr BuiltinCustomDataLayerProvider::try_get_for_read( - const GeometryComponent &component) const +GVArray BuiltinCustomDataLayerProvider::try_get_for_read(const GeometryComponent &component) const { const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); if (custom_data == nullptr) { @@ -511,7 +510,7 @@ ReadAttributeLookup CustomDataAttributeProvider::try_get_for_read( continue; } GSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVArray_For_GSpan>(data), domain_}; + return {GVArray::ForSpan(data), domain_}; } return {}; } @@ -541,7 +540,7 @@ WriteAttributeLookup CustomDataAttributeProvider::try_get_for_write( continue; } GMutableSpan data{*type, layer.data, domain_size}; - return {std::make_unique<GVMutableArray_For_GMutableSpan>(data), domain_}; + return {GVMutableArray::ForSpan(data), domain_}; } return {}; } @@ -751,25 +750,25 @@ std::optional<GSpan> CustomDataAttributes::get_for_read(const AttributeIDRef &at * value if the attribute doesn't exist. If no default value is provided, the default value for the * type will be used. */ -GVArrayPtr CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, - const CustomDataType data_type, - const void *default_value) const +GVArray CustomDataAttributes::get_for_read(const AttributeIDRef &attribute_id, + const CustomDataType data_type, + const void *default_value) const { const CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); std::optional<GSpan> attribute = this->get_for_read(attribute_id); if (!attribute) { const int domain_size = this->size_; - return std::make_unique<GVArray_For_SingleValue>( + return GVArray::ForSingle( *type, domain_size, (default_value == nullptr) ? type->default_value() : default_value); } if (attribute->type() == *type) { - return std::make_unique<GVArray_For_GSpan>(*attribute); + return GVArray::ForSpan(*attribute); } const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - return conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), *type); + return conversions.try_convert(GVArray::ForSpan(*attribute), *type); } std::optional<GMutableSpan> CustomDataAttributes::get_for_write(const AttributeIDRef &attribute_id) @@ -922,8 +921,8 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {}; } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_adapt_domain( - std::unique_ptr<blender::fn::GVArray> varray, +blender::fn::GVArray GeometryComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { @@ -1110,15 +1109,15 @@ std::optional<AttributeMetaData> GeometryComponent::attribute_get_meta_data( return result; } -static std::unique_ptr<blender::fn::GVArray> try_adapt_data_type( - std::unique_ptr<blender::fn::GVArray> varray, const blender::fn::CPPType &to_type) +static blender::fn::GVArray try_adapt_data_type(blender::fn::GVArray varray, + const blender::fn::CPPType &to_type) { const blender::nodes::DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); return conversions.try_convert(std::move(varray), to_type); } -std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain, const CustomDataType data_type) const @@ -1128,7 +1127,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return {}; } - std::unique_ptr<blender::fn::GVArray> varray = std::move(attribute.varray); + blender::fn::GVArray varray = std::move(attribute.varray); if (!ELEM(domain, ATTR_DOMAIN_AUTO, attribute.domain)) { varray = this->attribute_try_adapt_domain(std::move(varray), attribute.domain, domain); if (!varray) { @@ -1138,7 +1137,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r const blender::fn::CPPType *cpp_type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(cpp_type != nullptr); - if (varray->type() != *cpp_type) { + if (varray.type() != *cpp_type) { varray = try_adapt_data_type(std::move(varray), *cpp_type); if (!varray) { return {}; @@ -1148,7 +1147,7 @@ std::unique_ptr<blender::fn::GVArray> GeometryComponent::attribute_try_get_for_r return varray; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_try_get_for_read( +blender::fn::GVArray GeometryComponent::attribute_try_get_for_read( const AttributeIDRef &attribute_id, const AttributeDomain domain) const { if (!this->attribute_domain_supported(domain)) { @@ -1176,7 +1175,7 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( } const blender::fn::CPPType *type = blender::bke::custom_data_type_to_cpp_type(data_type); BLI_assert(type != nullptr); - if (attribute.varray->type() == *type) { + if (attribute.varray.type() == *type) { return attribute; } const blender::nodes::DataTypeConversions &conversions = @@ -1184,14 +1183,12 @@ blender::bke::ReadAttributeLookup GeometryComponent::attribute_try_get_for_read( return {conversions.try_convert(std::move(attribute.varray), *type), attribute.domain}; } -std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read( - const AttributeIDRef &attribute_id, - const AttributeDomain domain, - const CustomDataType data_type, - const void *default_value) const +blender::fn::GVArray GeometryComponent::attribute_get_for_read(const AttributeIDRef &attribute_id, + const AttributeDomain domain, + const CustomDataType data_type, + const void *default_value) const { - std::unique_ptr<blender::bke::GVArray> varray = this->attribute_try_get_for_read( - attribute_id, domain, data_type); + blender::fn::GVArray varray = this->attribute_try_get_for_read(attribute_id, domain, data_type); if (varray) { return varray; } @@ -1200,11 +1197,11 @@ std::unique_ptr<blender::bke::GVArray> GeometryComponent::attribute_get_for_read default_value = type->default_value(); } const int domain_size = this->attribute_domain_size(domain); - return std::make_unique<blender::fn::GVArray_For_SingleValue>(*type, domain_size, default_value); + return blender::fn::GVArray::ForSingle(*type, domain_size, default_value); } class GVMutableAttribute_For_OutputAttribute - : public blender::fn::GVMutableArray_For_GMutableSpan { + : public blender::fn::GVMutableArrayImpl_For_GMutableSpan { public: GeometryComponent *component; std::string attribute_name; @@ -1213,7 +1210,7 @@ class GVMutableAttribute_For_OutputAttribute GVMutableAttribute_For_OutputAttribute(GMutableSpan data, GeometryComponent &component, const AttributeIDRef &attribute_id) - : blender::fn::GVMutableArray_For_GMutableSpan(data), component(&component) + : blender::fn::GVMutableArrayImpl_For_GMutableSpan(data), component(&component) { if (attribute_id.is_named()) { this->attribute_name = attribute_id.name(); @@ -1239,7 +1236,8 @@ static void save_output_attribute(OutputAttribute &output_attribute) using namespace blender::bke; GVMutableAttribute_For_OutputAttribute &varray = - dynamic_cast<GVMutableAttribute_For_OutputAttribute &>(output_attribute.varray()); + dynamic_cast<GVMutableAttribute_For_OutputAttribute &>( + *output_attribute.varray().get_implementation()); GeometryComponent &component = *varray.component; AttributeIDRef attribute_id; @@ -1267,7 +1265,7 @@ static void save_output_attribute(OutputAttribute &output_attribute) BUFFER_FOR_CPP_TYPE_VALUE(varray.type(), buffer); for (const int i : IndexRange(varray.size())) { varray.get(i, buffer); - write_attribute.varray->set_by_relocate(i, buffer); + write_attribute.varray.set_by_relocate(i, buffer); } if (write_attribute.tag_modified_fn) { write_attribute.tag_modified_fn(); @@ -1310,9 +1308,9 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, if (!attribute) { if (default_value) { const int64_t domain_size = component.attribute_domain_size(domain); - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; - component.attribute_try_create_builtin(attribute_name, - AttributeInitVArray(&default_varray)); + component.attribute_try_create_builtin( + attribute_name, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create_builtin(attribute_name, AttributeInitDefault()); @@ -1327,9 +1325,8 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, /* Builtin attribute is on different domain. */ return {}; } - - GVMutableArrayPtr varray = std::move(attribute.varray); - if (varray->type() == *cpp_type) { + GVMutableArray varray = std::move(attribute.varray); + if (varray.type() == *cpp_type) { /* Builtin attribute matches exactly. */ return OutputAttribute(std::move(varray), domain, @@ -1349,9 +1346,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, WriteAttributeLookup attribute = component.attribute_try_get_for_write(attribute_id); if (!attribute) { if (default_value) { - const GVArray_For_SingleValueRef default_varray{*cpp_type, domain_size, default_value}; component.attribute_try_create( - attribute_id, domain, data_type, AttributeInitVArray(&default_varray)); + attribute_id, + domain, + data_type, + AttributeInitVArray(GVArray::ForSingleRef(*cpp_type, domain_size, default_value))); } else { component.attribute_try_create(attribute_id, domain, data_type, AttributeInitDefault()); @@ -1363,7 +1362,7 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, return {}; } } - if (attribute.domain == domain && attribute.varray->type() == *cpp_type) { + if (attribute.domain == domain && attribute.varray.type() == *cpp_type) { /* Existing generic attribute matches exactly. */ return OutputAttribute(std::move(attribute.varray), @@ -1382,11 +1381,11 @@ static OutputAttribute create_output_attribute(GeometryComponent &component, } else { /* Fill the temporary array with values from the existing attribute. */ - GVArrayPtr old_varray = component.attribute_get_for_read( + GVArray old_varray = component.attribute_get_for_read( attribute_id, domain, data_type, default_value); - old_varray->materialize_to_uninitialized(IndexRange(domain_size), data); + old_varray.materialize_to_uninitialized(IndexRange(domain_size), data); } - GVMutableArrayPtr varray = std::make_unique<GVMutableAttribute_For_OutputAttribute>( + GVMutableArray varray = GVMutableArray::For<GVMutableAttribute_For_OutputAttribute>( GMutableSpan{*cpp_type, data, domain_size}, component, attribute_id); return OutputAttribute(std::move(varray), domain, save_output_attribute, true); @@ -1410,21 +1409,21 @@ OutputAttribute GeometryComponent::attribute_try_get_for_output_only( namespace blender::bke { -const GVArray *AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const +GVArray AttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read(name_, domain, data_type); + GVArray attribute = component.attribute_try_get_for_read(name_, domain, data_type); if (attribute) { - return scope.add(std::move(attribute)); + return attribute; } } - return nullptr; + return {}; } std::string AttributeFieldInput::socket_inspection_name() const @@ -1451,31 +1450,32 @@ static StringRef get_random_id_attribute_name(const AttributeDomain domain) { switch (domain) { case ATTR_DOMAIN_POINT: + case ATTR_DOMAIN_INSTANCE: return "id"; default: return ""; } } -const GVArray *IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const +GVArray IDAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const StringRef name = get_random_id_attribute_name(domain); - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); + GVArray attribute = component.attribute_try_get_for_read(name, domain, CD_PROP_INT32); if (attribute) { - BLI_assert(attribute->size() == component.attribute_domain_size(domain)); - return scope.add(std::move(attribute)); + BLI_assert(attribute.size() == component.attribute_domain_size(domain)); + return attribute; } /* Use the index as the fallback if no random ID attribute exists. */ return fn::IndexFieldInput::get_index_varray(mask, scope); } - return nullptr; + return {}; } std::string IDAttributeFieldInput::socket_inspection_name() const @@ -1495,19 +1495,20 @@ bool IDAttributeFieldInput::is_equal_to(const fn::FieldNode &other) const return dynamic_cast<const IDAttributeFieldInput *>(&other) != nullptr; } -const GVArray *AnonymousAttributeFieldInput::get_varray_for_context( - const fn::FieldContext &context, IndexMask UNUSED(mask), ResourceScope &scope) const +GVArray AnonymousAttributeFieldInput::get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); const CustomDataType data_type = cpp_type_to_custom_data_type(*type_); - GVArrayPtr attribute = component.attribute_try_get_for_read( + GVArray attribute = component.attribute_try_get_for_read( anonymous_id_.get(), domain, data_type); - return scope.add(std::move(attribute)); + return attribute; } - return nullptr; + return {}; } std::string AnonymousAttributeFieldInput::socket_inspection_name() const diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh index 140498bdb01..b77d7010efa 100644 --- a/source/blender/blenkernel/intern/attribute_access_intern.hh +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -24,9 +24,6 @@ namespace blender::bke { -using fn::GVArrayPtr; -using fn::GVMutableArrayPtr; - /** * Utility to group together multiple functions that are used to access custom data on geometry * components in a generic way. @@ -86,7 +83,7 @@ class BuiltinAttributeProvider { { } - virtual GVArrayPtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual GVArray try_get_for_read(const GeometryComponent &component) const = 0; virtual WriteAttributeLookup try_get_for_write(GeometryComponent &component) const = 0; virtual bool try_delete(GeometryComponent &component) const = 0; virtual bool try_create(GeometryComponent &UNUSED(component), @@ -188,8 +185,8 @@ class CustomDataAttributeProvider final : public DynamicAttributesProvider { */ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { private: - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); const AttributeDomain domain_; const CustomDataType attribute_type_; const CustomDataType stored_type_; @@ -232,8 +229,8 @@ class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { * if the stored type is the same as the attribute type. */ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = GVMutableArrayPtr (*)(void *data, const int domain_size); + using AsReadAttribute = GVArray (*)(const void *data, const int domain_size); + using AsWriteAttribute = GVMutableArray (*)(void *data, const int domain_size); using UpdateOnRead = void (*)(const GeometryComponent &component); using UpdateOnWrite = void (*)(GeometryComponent &component); const CustomDataType stored_type_; @@ -266,7 +263,7 @@ class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final; + GVArray try_get_for_read(const GeometryComponent &component) const final; WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final; bool try_delete(GeometryComponent &component) const final; bool try_create(GeometryComponent &component, const AttributeInit &initializer) const final; diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 97f8bddc043..fb65a9bec7e 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -90,7 +90,6 @@ void BKE_blender_free(void) IMB_exit(); BKE_cachefiles_exit(); - BKE_images_exit(); DEG_free_node_types(); BKE_brush_system_exit(); diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 9c9f898afef..f8b943d3479 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -57,20 +57,26 @@ /** \name Copy/Paste `.blend`, partial saves. * \{ */ -void BKE_copybuffer_begin(Main *bmain_src) +/** Initialize a copy operation. */ +void BKE_copybuffer_copy_begin(Main *bmain_src) { BKE_blendfile_write_partial_begin(bmain_src); } -void BKE_copybuffer_tag_ID(ID *id) +/** Mark an ID to be copied. Should only be called after a call to #BKE_copybuffer_copy_begin. */ +void BKE_copybuffer_copy_tag_ID(ID *id) { BKE_blendfile_write_partial_tag_ID(id, true); } /** - * \return Success. + * Finalize a copy operation into given .blend file 'buffer'. + * + * \param filename: Full path to the .blend file used as copy/paste buffer. + * + * \return true on success, false otherwise. */ -bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *reports) +bool BKE_copybuffer_copy_end(Main *bmain_src, const char *filename, ReportList *reports) { const int write_flags = 0; const eBLO_WritePathRemap remap_mode = BLO_WRITE_PATH_REMAP_RELATIVE; @@ -82,6 +88,16 @@ bool BKE_copybuffer_save(Main *bmain_src, const char *filename, ReportList *repo return retval; } +/** + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Unlike #BKE_copybuffer_paste, it does not perform any instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return true on success, false otherwise. + */ bool BKE_copybuffer_read(Main *bmain_dst, const char *libname, ReportList *reports, @@ -116,12 +132,22 @@ bool BKE_copybuffer_read(Main *bmain_dst, } /** - * \return Number of IDs directly pasted from the buffer - * (does not includes indirectly pulled out ones). + * Paste datablocks from the given .blend file 'buffer' (i.e. append them). + * + * Similar to #BKE_copybuffer_read, but also handles instantiation of collections/objects/etc. + * + * \param libname: Full path to the .blend file used as copy/paste buffer. + * \param flag: A combination of #eBLOLibLinkFlags and ##eFileSel_Params_Flag to control + * link/append behavior. + * \note: Ignores #FILE_LINK flag, since it always appends IDs. + * \param id_types_mask: Only directly link IDs of those types from the given .blend file buffer. + * + * \return Number of IDs directly pasted from the buffer (does not includes indirectly linked + * ones). */ int BKE_copybuffer_paste(bContext *C, const char *libname, - const short flag, + const int flag, ReportList *reports, const uint64_t id_types_mask) { diff --git a/source/blender/blenkernel/intern/blendfile_link_append.c b/source/blender/blenkernel/intern/blendfile_link_append.c new file mode 100644 index 00000000000..36f03990953 --- /dev/null +++ b/source/blender/blenkernel/intern/blendfile_link_append.c @@ -0,0 +1,1566 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup bke + * + * High level `.blend` file link/append code, + * including linking/appending several IDs from different libraries, handling instanciations of + * collections/objects/obdata in current scene. + */ + +#include <stdlib.h> +#include <string.h> + +#include "CLG_log.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_ID.h" +#include "DNA_collection_types.h" +#include "DNA_key_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "BLI_bitmap.h" +#include "BLI_blenlib.h" +#include "BLI_ghash.h" +#include "BLI_linklist.h" +#include "BLI_math.h" +#include "BLI_memarena.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "BKE_idtype.h" +#include "BKE_key.h" +#include "BKE_layer.h" +#include "BKE_lib_id.h" +#include "BKE_lib_override.h" +#include "BKE_lib_query.h" +#include "BKE_lib_remap.h" +#include "BKE_main.h" +#include "BKE_material.h" +#include "BKE_object.h" +#include "BKE_report.h" +#include "BKE_rigidbody.h" +#include "BKE_scene.h" + +#include "BKE_blendfile_link_append.h" + +#include "BLO_readfile.h" +#include "BLO_writefile.h" + +static CLG_LogRef LOG = {"bke.blendfile_link_append"}; + +/* -------------------------------------------------------------------- */ +/** \name Link/append context implementation and public management API. + * \{ */ + +typedef struct BlendfileLinkAppendContextItem { + /** Name of the ID (without the heading two-chars IDcode). */ + char *name; + /** All libs (from BlendfileLinkAppendContext.libraries) to try to load this ID from. */ + BLI_bitmap *libraries; + /** ID type. */ + short idcode; + + /** Type of action to perform on this item, and general status tag information. + * NOTE: Mostly used by append post-linking processing. */ + char action; + char tag; + + /** Newly linked ID (NULL until it has been successfully linked). */ + ID *new_id; + /** Library ID from which the #new_id has been linked (NULL until it has been successfully + * linked). */ + Library *source_library; + /** Opaque user data pointer. */ + void *userdata; +} BlendfileLinkAppendContextItem; + +/* A blendfile library entry in the `libraries` list of #BlendfileLinkAppendContext. */ +typedef struct BlendfileLinkAppendContextLibrary { + char *path; /* Absolute .blend file path. */ + BlendHandle *blo_handle; /* Blend file handle, if any. */ + bool blo_handle_is_owned; /* Whether the blend file handle is owned, or borrowed. */ + /* The blendfile report associated with the `blo_handle`, if owned. */ + BlendFileReadReport bf_reports; +} BlendfileLinkAppendContextLibrary; + +typedef struct BlendfileLinkAppendContext { + /** List of library paths to search IDs in. */ + LinkNodePair libraries; + /** List of all ID to try to link from #libraries. */ + LinkNodePair items; + int num_libraries; + int num_items; + /** Linking/appending parameters. Including bmain, scene, viewlayer and view3d. */ + LibraryLink_Params *params; + + /** Allows to easily find an existing items from an ID pointer. */ + GHash *new_id_to_item; + + /** Runtime info used by append code to manage re-use of already appended matching IDs. */ + GHash *library_weak_reference_mapping; + + /** Embedded blendfile and its size, if needed. */ + const void *blendfile_mem; + size_t blendfile_memsize; + + /** Internal 'private' data */ + MemArena *memarena; +} BlendfileLinkAppendContext; + +typedef struct BlendfileLinkAppendContextCallBack { + BlendfileLinkAppendContext *lapp_context; + BlendfileLinkAppendContextItem *item; + ReportList *reports; + +} BlendfileLinkAppendContextCallBack; + +/* Actions to apply to an item (i.e. linked ID). */ +enum { + LINK_APPEND_ACT_UNSET = 0, + LINK_APPEND_ACT_KEEP_LINKED, + LINK_APPEND_ACT_REUSE_LOCAL, + LINK_APPEND_ACT_MAKE_LOCAL, + LINK_APPEND_ACT_COPY_LOCAL, +}; + +/* Various status info about an item (i.e. linked ID). */ +enum { + /* An indirectly linked ID. */ + LINK_APPEND_TAG_INDIRECT = 1 << 0, +}; + +static BlendHandle *link_append_context_library_blohandle_ensure( + BlendfileLinkAppendContext *lapp_context, + BlendfileLinkAppendContextLibrary *lib_context, + ReportList *reports) +{ + if (reports != NULL) { + lib_context->bf_reports.reports = reports; + } + + char *libname = lib_context->path; + BlendHandle *blo_handle = lib_context->blo_handle; + if (blo_handle == NULL) { + if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { + blo_handle = BLO_blendhandle_from_memory(lapp_context->blendfile_mem, + (int)lapp_context->blendfile_memsize, + &lib_context->bf_reports); + } + else { + blo_handle = BLO_blendhandle_from_file(libname, &lib_context->bf_reports); + } + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = true; + } + + return blo_handle; +} + +static void link_append_context_library_blohandle_release( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextLibrary *lib_context) +{ + if (lib_context->blo_handle_is_owned && lib_context->blo_handle != NULL) { + BLO_blendhandle_close(lib_context->blo_handle); + lib_context->blo_handle = NULL; + } +} + +/** Allocate and initialize a new context to link/append datablocks. + * + * \param flag a combination of #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags + * from BLO_readfile.h + */ +BlendfileLinkAppendContext *BKE_blendfile_link_append_context_new(LibraryLink_Params *params) +{ + MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); + BlendfileLinkAppendContext *lapp_context = BLI_memarena_calloc(ma, sizeof(*lapp_context)); + + lapp_context->params = params; + lapp_context->memarena = ma; + + return lapp_context; +} + +/** Free a link/append context. */ +void BKE_blendfile_link_append_context_free(BlendfileLinkAppendContext *lapp_context) +{ + if (lapp_context->new_id_to_item != NULL) { + BLI_ghash_free(lapp_context->new_id_to_item, NULL, NULL); + } + + for (LinkNode *liblink = lapp_context->libraries.list; liblink != NULL; + liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + BLI_assert(lapp_context->library_weak_reference_mapping == NULL); + + BLI_memarena_free(lapp_context->memarena); +} + +/** Set or clear flags in given \a lapp_context. + * + * \param do_set Set the given \a flag if true, clear it otherwise. + */ +void BKE_blendfile_link_append_context_flag_set(BlendfileLinkAppendContext *lapp_context, + const int flag, + const bool do_set) +{ + if (do_set) { + lapp_context->params->flag |= flag; + } + else { + lapp_context->params->flag &= ~flag; + } +} + +/** Store reference to a Blender's embedded memfile into the context. + * + * \note This is required since embedded startup blender file is handled in `ED` module, which + * cannot be linked in BKE code. + */ +void BKE_blendfile_link_append_context_embedded_blendfile_set( + BlendfileLinkAppendContext *lapp_context, const void *blendfile_mem, int blendfile_memsize) +{ + BLI_assert_msg(lapp_context->blendfile_mem == NULL, + "Please explicitely clear reference to an embedded blender memfile before " + "setting a new one"); + lapp_context->blendfile_mem = blendfile_mem; + lapp_context->blendfile_memsize = (size_t)blendfile_memsize; +} + +/** Clear reference to Blender's embedded startup file into the context. */ +void BKE_blendfile_link_append_context_embedded_blendfile_clear( + BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->blendfile_mem = NULL; + lapp_context->blendfile_memsize = 0; +} + +/** Add a new source library to search for items to be linked to the given link/append context. + * + * \param libname: the absolute path to the library blend file. + * \param blo_handle: the blend file handle of the library, NULL is not available. Note that this + * is only borrowed for linking purpose, no releasing or other management will + * be performed by #BKE_blendfile_link_append code on it. + * + * \note *Never* call BKE_blendfile_link_append_context_library_add() after having added some + * items. */ +void BKE_blendfile_link_append_context_library_add(BlendfileLinkAppendContext *lapp_context, + const char *libname, + BlendHandle *blo_handle) +{ + BLI_assert(lapp_context->items.list == NULL); + + BlendfileLinkAppendContextLibrary *lib_context = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*lib_context)); + + size_t len = strlen(libname) + 1; + char *libpath = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(libpath, libname, len); + + lib_context->path = libpath; + lib_context->blo_handle = blo_handle; + lib_context->blo_handle_is_owned = (blo_handle == NULL); + + BLI_linklist_append_arena(&lapp_context->libraries, lib_context, lapp_context->memarena); + lapp_context->num_libraries++; +} + +/** Add a new item (datablock name and idcode) to be searched and linked/appended from libraries + * associated to the given context. + * + * \param userdata: an opaque user-data pointer stored in generated link/append item. */ +BlendfileLinkAppendContextItem *BKE_blendfile_link_append_context_item_add( + BlendfileLinkAppendContext *lapp_context, + const char *idname, + const short idcode, + void *userdata) +{ + BlendfileLinkAppendContextItem *item = BLI_memarena_calloc(lapp_context->memarena, + sizeof(*item)); + size_t len = strlen(idname) + 1; + + item->name = BLI_memarena_alloc(lapp_context->memarena, len); + BLI_strncpy(item->name, idname, len); + item->idcode = idcode; + item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_context->memarena, lapp_context->num_libraries); + + item->new_id = NULL; + item->action = LINK_APPEND_ACT_UNSET; + item->userdata = userdata; + + BLI_linklist_append_arena(&lapp_context->items, item, lapp_context->memarena); + lapp_context->num_items++; + + return item; +} + +/** Enable search of the given \a item into the library stored at given index in the link/append + * context. */ +void BKE_blendfile_link_append_context_item_library_index_enable( + BlendfileLinkAppendContext *UNUSED(lapp_context), + BlendfileLinkAppendContextItem *item, + const int library_index) +{ + BLI_BITMAP_ENABLE(item->libraries, library_index); +} + +/** Check if given link/append context is empty (has no items to process) or not. */ +bool BKE_blendfile_link_append_context_is_empty(struct BlendfileLinkAppendContext *lapp_context) +{ + return lapp_context->num_items == 0; +} + +void *BKE_blendfile_link_append_context_item_userdata_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->userdata; +} + +ID *BKE_blendfile_link_append_context_item_newid_get( + BlendfileLinkAppendContext *UNUSED(lapp_context), BlendfileLinkAppendContextItem *item) +{ + return item->new_id; +} + +short BKE_blendfile_link_append_context_item_idcode_get( + struct BlendfileLinkAppendContext *UNUSED(lapp_context), + struct BlendfileLinkAppendContextItem *item) +{ + return item->idcode; +} + +/** Iterate over all (or a subset) of the items listed in given #BlendfileLinkAppendContext, and + * call the `callback_function` on them. + * + * \param flag: Control which type of items to process (see + * #eBlendfileLinkAppendForeachItemFlag enum flags). + * \param userdata: An opaque void pointer passed to the `callback_function`. + */ +void BKE_blendfile_link_append_context_item_foreach( + struct BlendfileLinkAppendContext *lapp_context, + BKE_BlendfileLinkAppendContexteItemFunction callback_function, + const eBlendfileLinkAppendForeachItemFlag flag, + void *userdata) +{ + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_DIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + continue; + } + if ((flag & BKE_BLENDFILE_LINK_APPEND_FOREACH_ITEM_FLAG_DO_INDIRECT) == 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) != 0) { + continue; + } + + if (!callback_function(lapp_context, item, userdata)) { + break; + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Library link/append helper functions. + * + * \{ */ + +/* Struct gathering all required data to handle instantiation of loose data-blocks. */ +typedef struct LooseDataInstantiateContext { + BlendfileLinkAppendContext *lapp_context; + + /* The collection in which to add loose collections/objects. */ + Collection *active_collection; +} LooseDataInstantiateContext; + +static bool object_in_any_scene(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { + if (BKE_scene_object_find(sce, ob)) { + return true; + } + } + + return false; +} + +static bool object_in_any_collection(Main *bmain, Object *ob) +{ + LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { + if (BKE_collection_has_object(collection, ob)) { + return true; + } + } + + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { + if (scene->master_collection != NULL && + BKE_collection_has_object(scene->master_collection, ob)) { + return true; + } + } + + return false; +} + +static ID *loose_data_instantiate_process_check(LooseDataInstantiateContext *instantiate_context, + BlendfileLinkAppendContextItem *item) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + /* In linking case, we always want to handle instantiation. */ + if (lapp_context->params->flag & FILE_LINK) { + return item->new_id; + } + + /* We consider that if we either kept it linked, or re-used already local data, instantiation + * status of those should not be modified. */ + if (!ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_MAKE_LOCAL)) { + return NULL; + } + + ID *id = item->new_id; + if (id == NULL) { + return NULL; + } + + if (item->action == LINK_APPEND_ACT_COPY_LOCAL) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + return NULL; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; + } + + BLI_assert(!ID_IS_LINKED(id)); + return id; +} + +static void loose_data_instantiate_ensure_active_collection( + LooseDataInstantiateContext *instantiate_context) +{ + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = instantiate_context->lapp_context->params->bmain; + Scene *scene = instantiate_context->lapp_context->params->context.scene; + ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer; + + /* Find or add collection as needed. */ + if (instantiate_context->active_collection == NULL) { + if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) { + LayerCollection *lc = BKE_layer_collection_get_active(view_layer); + instantiate_context->active_collection = lc->collection; + } + else { + if (lapp_context->params->flag & FILE_LINK) { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Linked Data")); + } + else { + instantiate_context->active_collection = BKE_collection_add( + bmain, scene->master_collection, DATA_("Appended Data")); + } + } + } +} + +static void loose_data_instantiate_object_base_instance_init(Main *bmain, + Collection *collection, + Object *ob, + ViewLayer *view_layer, + const View3D *v3d, + const int flag, + bool set_active) +{ + /* Auto-select and appending. */ + if ((flag & FILE_AUTOSELECT) && ((flag & FILE_LINK) == 0)) { + /* While in general the object should not be manipulated, + * when the user requests the object to be selected, ensure it's visible and selectable. */ + ob->visibility_flag &= ~(OB_HIDE_VIEWPORT | OB_HIDE_SELECT); + } + + BKE_collection_object_add(bmain, collection, ob); + + Base *base = BKE_view_layer_base_find(view_layer, ob); + + if (v3d != NULL) { + base->local_view_bits |= v3d->local_view_uuid; + } + + if (flag & FILE_AUTOSELECT) { + /* All objects that use #FILE_AUTOSELECT must be selectable (unless linking data). */ + BLI_assert((base->flag & BASE_SELECTABLE) || (flag & FILE_LINK)); + if (base->flag & BASE_SELECTABLE) { + base->flag |= BASE_SELECTED; + } + } + + if (set_active) { + view_layer->basact = base; + } + + BKE_scene_object_base_flag_sync_from_base(base); +} + +/* Tag obdata that actually need to be instantiated (those referenced by an object do not, since + * the object will be instantiated instaed if needed. */ +static void loose_data_instantiate_obdata_preprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + LinkNode *itemlink; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + + id->tag |= LIB_TAG_DOIT; + } + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + Object *new_ob = (Object *)id->newid; + if (ob->data != NULL) { + ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; + } + if (new_ob != NULL && new_ob->data != NULL) { + ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; + } + } +} + +static void loose_data_instantiate_collection_process( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* NOTE: For collections we only view_layer-instantiate duplicated collections that have + * non-instantiated objects in them. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_GR) { + continue; + } + + /* We do not want to force instantiation of indirectly appended collections. Users can now + * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ + /* We need to check that objects in that collections are already instantiated in a scene. + * Otherwise, it's better to add the collection to the scene's active collection, than to + * instantiate its objects in active scene's collection directly. See T61141. + * + * NOTE: We only check object directly into that collection, not recursively into its + * children. + */ + Collection *collection = (Collection *)id; + /* We always add collections directly selected by the user. */ + bool do_add_collection = (item->tag & LINK_APPEND_TAG_INDIRECT) == 0; + if (!do_add_collection) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + if (!object_in_any_scene(bmain, ob)) { + do_add_collection = true; + break; + } + } + } + if (!do_add_collection) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + /* In case user requested instantiation of collections as empties, we do so for the one they + * explicitly selected (originally directly linked IDs) only. */ + if ((lapp_context->params->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && + (item->tag & LINK_APPEND_TAG_INDIRECT) == 0) { + /* BKE_object_add(...) messes with the selection. */ + Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); + ob->type = OB_EMPTY; + ob->empty_drawsize = U.collection_instance_empty_size; + + const bool set_selected = (lapp_context->params->flag & FILE_AUTOSELECT) != 0; + /* TODO: why is it OK to make this active here but not in other situations? + * See other callers of #object_base_instance_init */ + const bool set_active = set_selected; + loose_data_instantiate_object_base_instance_init( + bmain, active_collection, ob, view_layer, v3d, lapp_context->params->flag, set_active); + + /* Assign the collection. */ + ob->instance_collection = collection; + id_us_plus(&collection->id); + ob->transflag |= OB_DUPLICOLLECTION; + copy_v3_v3(ob->loc, scene->cursor.location); + } + else { + /* Add collection as child of active collection. */ + BKE_collection_child_add(bmain, active_collection, collection); + + if ((lapp_context->params->flag & FILE_AUTOSELECT) != 0) { + LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { + Object *ob = coll_ob->ob; + Base *base = BKE_view_layer_base_find(view_layer, ob); + if (base) { + base->flag |= BASE_SELECTED; + BKE_scene_object_base_flag_sync_from_base(base); + } + } + } + } + } +} + +static void loose_data_instantiate_object_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used + * anywhere. */ + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + + Object *ob = (Object *)id; + + if (object_in_any_collection(bmain, ob)) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + CLAMP_MIN(ob->id.us, 0); + ob->mode = OB_MODE_OBJECT; + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + } +} + +static void loose_data_instantiate_obdata_process(LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + Scene *scene = lapp_context->params->context.scene; + ViewLayer *view_layer = lapp_context->params->context.view_layer; + const View3D *v3d = lapp_context->params->context.v3d; + + /* Do NOT make base active here! screws up GUI stuff, + * if you want it do it at the editor level. */ + const bool object_set_active = false; + + LinkNode *itemlink; + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL) { + continue; + } + const ID_Type idcode = GS(id->name); + if (!OB_DATA_SUPPORT_ID(idcode)) { + continue; + } + if ((id->tag & LIB_TAG_DOIT) == 0) { + continue; + } + + loose_data_instantiate_ensure_active_collection(instantiate_context); + Collection *active_collection = instantiate_context->active_collection; + + const int type = BKE_object_obdata_to_type(id); + BLI_assert(type != -1); + Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); + ob->data = id; + id_us_plus(id); + BKE_object_materials_test(bmain, ob, ob->data); + + loose_data_instantiate_object_base_instance_init(bmain, + active_collection, + ob, + view_layer, + v3d, + lapp_context->params->flag, + object_set_active); + + copy_v3_v3(ob->loc, scene->cursor.location); + + id->tag &= ~LIB_TAG_DOIT; + } +} + +static void loose_data_instantiate_object_rigidbody_postprocess( + LooseDataInstantiateContext *instantiate_context) +{ + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + Main *bmain = lapp_context->params->bmain; + + LinkNode *itemlink; + /* Add rigid body objects and constraints to current RB world(s). */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = loose_data_instantiate_process_check(instantiate_context, item); + if (id == NULL || GS(id->name) != ID_OB) { + continue; + } + BKE_rigidbody_ensure_local_object(bmain, (Object *)id); + } +} + +static void loose_data_instantiate(LooseDataInstantiateContext *instantiate_context) +{ + if (instantiate_context->lapp_context->params->context.scene == NULL) { + /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. + */ + return; + } + + BlendfileLinkAppendContext *lapp_context = instantiate_context->lapp_context; + const bool do_obdata = (lapp_context->params->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; + + /* First pass on obdata to enable their instantiation by default, then do a second pass on + * objects to clear it for any obdata already in use. */ + if (do_obdata) { + loose_data_instantiate_obdata_preprocess(instantiate_context); + } + + /* First do collections, then objects, then obdata. */ + loose_data_instantiate_collection_process(instantiate_context); + loose_data_instantiate_object_process(instantiate_context); + if (do_obdata) { + loose_data_instantiate_obdata_process(instantiate_context); + } + + loose_data_instantiate_object_rigidbody_postprocess(instantiate_context); +} + +static void new_id_to_item_mapping_add(BlendfileLinkAppendContext *lapp_context, + ID *id, + BlendfileLinkAppendContextItem *item) +{ + BLI_ghash_insert(lapp_context->new_id_to_item, id, item); + + /* This ensures that if a liboverride reference is also linked/used by some other appended + * data, it gets a local copy instead of being made directly local, so that the liboverride + * references remain valid (i.e. linked data). */ + if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { + id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; + } +} + +/* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as + * liboverride references as already existing. */ +static void new_id_to_item_mapping_create(BlendfileLinkAppendContext *lapp_context) +{ + lapp_context->new_id_to_item = BLI_ghash_new( + BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); + for (LinkNode *itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + new_id_to_item_mapping_add(lapp_context, id, item); + } +} + +static int foreach_libblock_link_append_callback(LibraryIDLinkCallbackData *cb_data) +{ + /* NOTE: It is important to also skip liboverride references here, as those should never be made + * local. */ + if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | + IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextCallBack *data = cb_data->user_data; + ID *id = *cb_data->id_pointer; + + if (id == NULL) { + return IDWALK_RET_NOP; + } + + if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { + /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, + * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be + * processed, so we need to recursively deal with them here. */ + /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it + * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of + * shapekey referencing the shapekey itself). */ + if (id != cb_data->id_self) { + BKE_library_foreach_ID_link( + cb_data->bmain, id, foreach_libblock_link_append_callback, data, IDWALK_NOP); + } + return IDWALK_RET_NOP; + } + + /* In linking case, we always consider all linked IDs, even indirectly ones, for instantiation, + * so we need to add them all to the items list. + * + * In appending case, when `do_recursive` is false, we only make local IDs from same + * library(-ies) as the initially directly linked ones. + * + * NOTE: Since in append case, linked IDs are also fully skipped during instantiation step (see + * #append_loose_data_instantiate_process_check), we can avoid adding them to the items list + * completely. */ + const bool do_link = (data->lapp_context->params->flag & FILE_LINK) != 0; + const bool do_recursive = (data->lapp_context->params->flag & BLO_LIBLINK_APPEND_RECURSIVE) != + 0 || + do_link; + if (!do_recursive && cb_data->id_owner->lib != id->lib) { + return IDWALK_RET_NOP; + } + + BlendfileLinkAppendContextItem *item = BLI_ghash_lookup(data->lapp_context->new_id_to_item, id); + if (item == NULL) { + item = BKE_blendfile_link_append_context_item_add( + data->lapp_context, id->name, GS(id->name), NULL); + item->new_id = id; + item->source_library = id->lib; + /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, + * it was rather linked indirectly. This info is important for instantiation of collections. */ + item->tag |= LINK_APPEND_TAG_INDIRECT; + /* In linking case we already know what we want to do with those items. */ + if (do_link) { + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + new_id_to_item_mapping_add(data->lapp_context, id, item); + } + + /* NOTE: currently there is no need to do anything else here, but in the future this would be + * the place to add specific per-usage decisions on how to append an ID. */ + + return IDWALK_RET_NOP; +} + +/** \} */ + +/** \name Library link/append code. + * \{ */ + +/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, + * made local, duplicated as local, re-used from local etc. + * + * TODO: Expose somehow this logic to the two other parts of code performing actual append + * (i.e. copy/paste and `bpy` link/append API). + * Then we can heavily simplify #BKE_library_make_local(). */ +void BKE_blendfile_append(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *bmain = lapp_context->params->bmain; + + BLI_assert((lapp_context->params->flag & FILE_LINK) == 0); + + const bool set_fakeuser = (lapp_context->params->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; + const bool do_reuse_local_id = (lapp_context->params->flag & + BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; + + const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | + ((lapp_context->params->flag & + BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != 0 ? + LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : + 0); + + LinkNode *itemlink; + + new_id_to_item_mapping_create(lapp_context); + lapp_context->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); + + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? + BKE_main_library_weak_reference_search_item( + lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name) : + NULL; + + if (item->action != LINK_APPEND_ACT_UNSET) { + /* Already set, pass. */ + } + if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); + item->action = LINK_APPEND_ACT_KEEP_LINKED; + } + else if (do_reuse_local_id && existing_local_id != NULL) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); + item->action = LINK_APPEND_ACT_REUSE_LOCAL; + item->userdata = existing_local_id; + } + else if (id->tag & LIB_TAG_PRE_EXISTING) { + CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); + item->action = LINK_APPEND_ACT_COPY_LOCAL; + } + else { + CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); + item->action = LINK_APPEND_ACT_MAKE_LOCAL; + } + + /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. + */ + if (!ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link( + bmain, id, foreach_libblock_link_append_callback, &cb_data, IDWALK_NOP); + } + + /* If we found a matching existing local id but are not re-using it, we need to properly clear + * its weak reference to linked data. */ + if (existing_local_id != NULL && + !ELEM(item->action, LINK_APPEND_ACT_KEEP_LINKED, LINK_APPEND_ACT_REUSE_LOCAL)) { + BKE_main_library_weak_reference_remove_item(lapp_context->library_weak_reference_mapping, + id->lib->filepath, + id->name, + existing_local_id); + } + } + + /* Effectively perform required operation on every linked ID. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + + ID *local_appended_new_id = NULL; + char lib_filepath[FILE_MAX]; + BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); + char lib_id_name[MAX_ID_NAME]; + BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); + + switch (item->action) { + case LINK_APPEND_ACT_COPY_LOCAL: + BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); + local_appended_new_id = id->newid; + break; + case LINK_APPEND_ACT_MAKE_LOCAL: + BKE_lib_id_make_local(bmain, + id, + make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | + LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); + BLI_assert(id->newid == NULL); + local_appended_new_id = id; + break; + case LINK_APPEND_ACT_KEEP_LINKED: + /* Nothing to do here. */ + break; + case LINK_APPEND_ACT_REUSE_LOCAL: + /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ + ID_NEW_SET(id, item->userdata); + /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ + break; + case LINK_APPEND_ACT_UNSET: + CLOG_ERROR( + &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); + break; + default: + BLI_assert(0); + } + + if (local_appended_new_id != NULL) { + if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { + BKE_main_library_weak_reference_add_item(lapp_context->library_weak_reference_mapping, + lib_filepath, + lib_id_name, + local_appended_new_id); + } + + if (set_fakeuser) { + if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { + /* Do not set fake user on objects nor collections (instancing). */ + id_fake_user_set(local_appended_new_id); + } + } + } + } + + BKE_main_library_weak_reference_destroy(lapp_context->library_weak_reference_mapping); + lapp_context->library_weak_reference_mapping = NULL; + + /* Remap IDs as needed. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action == LINK_APPEND_ACT_KEEP_LINKED) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + if (ELEM(item->action, LINK_APPEND_ACT_COPY_LOCAL, LINK_APPEND_ACT_REUSE_LOCAL)) { + BLI_assert(ID_IS_LINKED(id)); + id = id->newid; + if (id == NULL) { + continue; + } + } + + BLI_assert(!ID_IS_LINKED(id)); + + BKE_libblock_relink_to_newid(bmain, id, 0); + } + + /* Remove linked IDs when a local existing data has been reused instead. */ + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_REUSE_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + BLI_assert(id->newid != NULL); + + id->tag |= LIB_TAG_DOIT; + item->new_id = id->newid; + } + BKE_id_multi_tagged_delete(bmain); + + /* Instantiate newly created (duplicated) IDs as needed. */ + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + + /* Attempt to deal with object proxies. + * + * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not + * producing any useful result in any known use case), neither here nor in + * `BKE_library_make_local` currently. + * Proxies are end of life anyway, so not worth spending time on this. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + + if (item->action != LINK_APPEND_ACT_COPY_LOCAL) { + continue; + } + + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(ID_IS_LINKED(id)); + + /* Attempt to re-link copied proxy objects. This allows appending of an entire scene + * from another blend file into this one, even when that blend file contains proxified + * armatures that have local references. Since the proxified object needs to be linked + * (not local), this will only work when the "Localize all" checkbox is disabled. + * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ + if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { + Object *ob = (Object *)id; + Object *ob_new = (Object *)id->newid; + bool is_local = false, is_lib = false; + + /* Proxies only work when the proxified object is linked-in from a library. */ + if (!ID_IS_LINKED(ob->proxy)) { + CLOG_WARN(&LOG, + "Proxy object %s will lose its link to %s, because the " + "proxified object is local", + id->newid->name, + ob->proxy->id.name); + continue; + } + + BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); + + /* We can only switch the proxy'ing to a made-local proxy if it is no longer + * referred to from a library. Not checking for local use; if new local proxy + * was not used locally would be a nasty bug! */ + if (is_local || is_lib) { + CLOG_WARN(&LOG, + "Made-local proxy object %s will lose its link to %s, " + "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", + id->newid->name, + ob->proxy->id.name, + is_local, + is_lib); + } + else { + /* we can switch the proxy'ing from the linked-in to the made-local proxy. + * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that + * was already allocated by object_make_local() (which called BKE_object_copy). */ + ob_new->proxy = ob->proxy; + ob_new->proxy_group = ob->proxy_group; + ob_new->proxy_from = ob->proxy_from; + ob_new->proxy->proxy_from = ob_new; + ob->proxy = ob->proxy_from = ob->proxy_group = NULL; + } + } + } + + BKE_main_id_newptr_and_tag_clear(bmain); +} + +void BKE_blendfile_link(BlendfileLinkAppendContext *lapp_context, ReportList *reports) +{ + Main *mainl; + Library *lib; + + LinkNode *liblink, *itemlink; + int lib_idx, item_idx; + + BLI_assert(lapp_context->num_items && lapp_context->num_libraries); + + for (lib_idx = 0, liblink = lapp_context->libraries.list; liblink; + lib_idx++, liblink = liblink->next) { + BlendfileLinkAppendContextLibrary *lib_context = liblink->link; + char *libname = lib_context->path; + BlendHandle *blo_handle = link_append_context_library_blohandle_ensure( + lapp_context, lib_context, reports); + + if (blo_handle == NULL) { + /* Unlikely since we just browsed it, but possible + * Error reports will have been made by BLO_blendhandle_from_file() */ + continue; + } + + /* here appending/linking starts */ + + /* NOTE: This is temporary hotfix until whole code using link/append features has been moved to + * use new BKE code. */ + /* Do not handle instantiation in linking process anymore, we do it here in + * #loose_data_instantiate instead. */ + lapp_context->params->flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; + + mainl = BLO_library_link_begin(&blo_handle, libname, lapp_context->params); + lib = mainl->curlib; + BLI_assert(lib); + UNUSED_VARS_NDEBUG(lib); + + if (mainl->versionfile < 250) { + BKE_reportf(reports, + RPT_WARNING, + "Linking or appending from a very old .blend file format (%d.%d), no animation " + "conversion will " + "be done! You may want to re-save your lib file with current Blender", + mainl->versionfile, + mainl->subversionfile); + } + + /* For each lib file, we try to link all items belonging to that lib, + * and tag those successful to not try to load them again with the other libs. */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *new_id; + + if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { + continue; + } + + new_id = BLO_library_link_named_part( + mainl, &blo_handle, item->idcode, item->name, lapp_context->params); + + if (new_id) { + /* If the link is successful, clear item's libs 'todo' flags. + * This avoids trying to link same item with other libraries to come. */ + BLI_bitmap_set_all(item->libraries, false, lapp_context->num_libraries); + item->new_id = new_id; + item->source_library = new_id->lib; + } + } + + BLO_library_link_end(mainl, &blo_handle, lapp_context->params); + link_append_context_library_blohandle_release(lapp_context, lib_context); + } + + /* Instantiate newly linked IDs as needed, if no append is scheduled. */ + if ((lapp_context->params->flag & FILE_LINK) != 0 && + lapp_context->params->context.scene != NULL) { + new_id_to_item_mapping_create(lapp_context); + /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect + * dependencies), this list will grow and we will process those IDs later, leading to a flatten + * recursive processing of all the linked dependencies. */ + for (itemlink = lapp_context->items.list; itemlink; itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *id = item->new_id; + if (id == NULL) { + continue; + } + BLI_assert(item->userdata == NULL); + + /* Linked IDs should never be marked as needing post-processing (instantiation of loose + * objects etc.). + * NOTE: This is dev test check, can be removed once we get rid of instantiation code in BLO + * completely.*/ + BLI_assert((id->tag & LIB_TAG_DOIT) == 0); + + BlendfileLinkAppendContextCallBack cb_data = { + .lapp_context = lapp_context, .item = item, .reports = reports}; + BKE_library_foreach_ID_link(lapp_context->params->bmain, + id, + foreach_libblock_link_append_callback, + &cb_data, + IDWALK_NOP); + } + + LooseDataInstantiateContext instantiate_context = {.lapp_context = lapp_context, + .active_collection = NULL}; + loose_data_instantiate(&instantiate_context); + } +} + +/** \} */ + +/** \name Library relocating code. + * \{ */ + +static void blendfile_library_relocate_remap(Main *bmain, + ID *old_id, + ID *new_id, + ReportList *reports, + const bool do_reload, + const short remap_flags) +{ + BLI_assert(old_id); + if (do_reload) { + /* Since we asked for placeholders in case of missing IDs, + * we expect to always get a valid one. */ + BLI_assert(new_id); + } + if (new_id) { + CLOG_INFO(&LOG, + 4, + "Before remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); + + if (old_id->flag & LIB_FAKEUSER) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + CLOG_INFO(&LOG, + 4, + "After remap of %s, old_id users: %d, new_id users: %d", + old_id->name, + old_id->us, + new_id->us); + + /* In some cases, new_id might become direct link, remove parent of library in this case. */ + if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { + if (do_reload) { + BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ + } + new_id->lib->parent = NULL; + } + } + + if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { + /* Note that this *should* not happen - but better be safe than sorry in this area, + * at least until we are 100% sure this cannot ever happen. + * Also, we can safely assume names were unique so far, + * so just replacing '.' by '~' should work, + * but this does not totally rules out the possibility of name collision. */ + size_t len = strlen(old_id->name); + size_t dot_pos; + bool has_num = false; + + for (dot_pos = len; dot_pos--;) { + char c = old_id->name[dot_pos]; + if (c == '.') { + break; + } + if (c < '0' || c > '9') { + has_num = false; + break; + } + has_num = true; + } + + if (has_num) { + old_id->name[dot_pos] = '~'; + } + else { + len = MIN2(len, MAX_ID_NAME - 7); + BLI_strncpy(&old_id->name[len], "~000", 7); + } + + id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); + + BKE_reportf( + reports, + RPT_WARNING, + "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " + "old one (%d remaining users) had to be kept and was renamed to '%s'", + new_id->name, + old_id->us, + old_id->name); + } +} + +void BKE_blendfile_library_relocate(BlendfileLinkAppendContext *lapp_context, + ReportList *reports, + Library *library, + const bool do_reload) +{ + ListBase *lbarray[INDEX_ID_MAX]; + int lba_idx; + + LinkNode *itemlink; + int item_idx; + + Main *bmain = lapp_context->params->bmain; + + /* Remove all IDs to be reloaded from Main. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id = lbarray[lba_idx]->first; + const short idcode = id ? GS(id->name) : 0; + + if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { + /* No need to reload non-linkable datatypes, + * those will get relinked with their 'users ID'. */ + continue; + } + + for (; id; id = id->next) { + if (id->lib == library) { + BlendfileLinkAppendContextItem *item; + + /* We remove it from current Main, and add it to items to link... */ + /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ + BLI_remlink(lbarray[lba_idx], id); + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(id); + if (old_key != NULL) { + BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + + item = BKE_blendfile_link_append_context_item_add(lapp_context, id->name + 2, idcode, id); + BLI_bitmap_set_all(item->libraries, true, (size_t)lapp_context->num_libraries); + + CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); + } + } + } + + if (lapp_context->num_items == 0) { + /* Early out in case there is nothing to do. */ + return; + } + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instantiation here! */ + BKE_blendfile_link(lapp_context, reports); + + BKE_main_lock(bmain); + + /* We add back old id to bmain. + * We need to do this in a first, separated loop, otherwise some of those may not be handled by + * ID remapping, which means they would still reference old data to be deleted... */ + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + BLI_assert(old_id); + BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); + + /* Usual special code for ShapeKeys snowflakes... */ + Key *old_key = BKE_key_from_id(old_id); + if (old_key != NULL) { + BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); + } + } + + /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking + * code is wrong, we need to redo it here after adding them back to main. */ + BKE_main_id_refcount_recompute(bmain, false); + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | + ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | + (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + ID *new_id = item->new_id; + + blendfile_library_relocate_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); + if (new_id == NULL) { + continue; + } + /* Usual special code for ShapeKeys snowflakes... */ + Key **old_key_p = BKE_key_from_id_p(old_id); + if (old_key_p == NULL) { + continue; + } + Key *old_key = *old_key_p; + Key *new_key = BKE_key_from_id(new_id); + if (old_key != NULL) { + *old_key_p = NULL; + id_us_min(&old_key->id); + blendfile_library_relocate_remap( + bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); + *old_key_p = old_key; + id_us_plus_no_lib(&old_key->id); + } + } + + BKE_main_unlock(bmain); + + for (item_idx = 0, itemlink = lapp_context->items.list; itemlink; + item_idx++, itemlink = itemlink->next) { + BlendfileLinkAppendContextItem *item = itemlink->link; + ID *old_id = item->userdata; + + if (old_id->us == 0) { + BKE_id_free(bmain, old_id); + } + } + + /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable + * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id, *id_next; + for (id = lbarray[lba_idx]->first; id; id = id_next) { + id_next = id->next; + /* XXX That check may be a bit to generic/permissive? */ + if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { + BKE_id_free(bmain, id); + } + } + } + + /* Get rid of no more used libraries... */ + BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); + lba_idx = set_listbasepointers(bmain, lbarray); + while (lba_idx--) { + ID *id; + for (id = lbarray[lba_idx]->first; id; id = id->next) { + if (id->lib) { + id->lib->id.tag &= ~LIB_TAG_DOIT; + } + } + } + Library *lib, *lib_next; + for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { + lib_next = lib->id.next; + if (lib->id.tag & LIB_TAG_DOIT) { + id_us_clear_real(&lib->id); + if (lib->id.us == 0) { + BKE_id_free(bmain, (ID *)lib); + } + } + } + + /* Update overrides of reloaded linked data-blocks. */ + ID *id; + FOREACH_MAIN_ID_BEGIN (bmain, id) { + if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || + (id->tag & LIB_TAG_PRE_EXISTING) == 0) { + continue; + } + if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { + BKE_lib_override_library_update(bmain, id); + } + } + FOREACH_MAIN_ID_END; + + /* Resync overrides if needed. */ + if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { + BKE_lib_override_library_main_resync(bmain, + lapp_context->params->context.scene, + lapp_context->params->context.view_layer, + &(struct BlendFileReadReport){ + .reports = reports, + }); + /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ + BKE_lib_override_library_main_operations_create(bmain, true); + } + + BKE_main_collection_sync(bmain); +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 7d217d6907d..a682489b7cd 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -213,8 +213,9 @@ static void brush_foreach_id(ID *id, LibraryForeachIDData *data) if (brush->gpencil_settings) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, brush->gpencil_settings->material, IDWALK_CB_USER); } - BKE_texture_mtex_foreach_id(data, &brush->mtex); - BKE_texture_mtex_foreach_id(data, &brush->mask_mtex); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_texture_mtex_foreach_id(data, &brush->mtex)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, &brush->mask_mtex)); } static void brush_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -2474,7 +2475,7 @@ float BKE_brush_curve_strength(const Brush *br, float p, const float len) } /* Uses the brush curve control to find a strength value between 0 and 1 */ -float BKE_brush_curve_strength_clamped(Brush *br, float p, const float len) +float BKE_brush_curve_strength_clamped(const Brush *br, float p, const float len) { float strength = BKE_brush_curve_strength(br, p, len); diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 2dca5dcb75d..22b939d3cf9 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -716,7 +716,7 @@ Collection *BKE_collection_duplicate(Main *bmain, collection_new->id.tag &= ~LIB_TAG_NEW; /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&collection_new->id); + BKE_libblock_relink_to_newid(bmain, &collection_new->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index 7ddbaa0e9ee..3455baa9292 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2010,7 +2010,7 @@ static void rotlike_evaluate(bConstraint *con, bConstraintOb *cob, ListBase *tar /* We must get compatible eulers from the beginning because * some of them can be modified below (see bug T21875). * Additionally, since this constraint is based on euler rotation math, it doesn't work well - * with shear. The Y axis is chosen as the main axis when we orthoganalize the matrix because + * with shear. The Y axis is chosen as the main axis when we orthogonalize the matrix because * constraints are used most commonly on bones. */ float mat[4][4]; copy_m4_m4(mat, ct->matrix); diff --git a/source/blender/blenkernel/intern/curve_eval.cc b/source/blender/blenkernel/intern/curve_eval.cc index ff0478f2543..163f8b02b85 100644 --- a/source/blender/blenkernel/intern/curve_eval.cc +++ b/source/blender/blenkernel/intern/curve_eval.cc @@ -109,6 +109,24 @@ void CurveEval::bounds_min_max(float3 &min, float3 &max, const bool use_evaluate } } +float CurveEval::total_length() const +{ + float length = 0.0f; + for (const SplinePtr &spline : this->splines()) { + length += spline->length(); + } + return length; +} + +int CurveEval::total_control_point_size() const +{ + int count = 0; + for (const SplinePtr &spline : this->splines()) { + count += spline->size(); + } + return count; +} + /** * Return the start indices for each of the curve spline's control points, if they were part * of a flattened array. This can be used to facilitate parallelism by avoiding the need to diff --git a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc index 1ef205c6903..03525e32a52 100644 --- a/source/blender/blenkernel/intern/curve_to_mesh_convert.cc +++ b/source/blender/blenkernel/intern/curve_to_mesh_convert.cc @@ -32,8 +32,6 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; namespace blender::bke { @@ -76,7 +74,7 @@ static void vert_extrude_to_mesh_data(const Spline &spline, Span<float3> positions = spline.evaluated_positions(); Span<float3> tangents = spline.evaluated_tangents(); Span<float3> normals = spline.evaluated_normals(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); for (const int i : IndexRange(eval_size)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i], normals[i], tangents[i]); @@ -227,7 +225,7 @@ static void spline_extrude_to_mesh_data(const ResultInfo &info, Span<float3> normals = spline.evaluated_normals(); Span<float3> profile_positions = profile.evaluated_positions(); - GVArray_Typed<float> radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> radii = spline.interpolate_to_evaluated(spline.radii()); for (const int i_ring : IndexRange(info.spline_vert_len)) { float4x4 point_matrix = float4x4::from_normalized_axis_data( positions[i_ring], normals[i_ring], tangents[i_ring]); @@ -495,8 +493,8 @@ static void copy_curve_point_attribute_to_mesh(const GSpan src, const ResultInfo &info, ResultAttributeData &dst) { - GVArrayPtr interpolated_gvarray = info.spline.interpolate_to_evaluated(src); - GSpan interpolated = interpolated_gvarray->get_internal_span(); + GVArray interpolated_gvarray = info.spline.interpolate_to_evaluated(src); + GSpan interpolated = interpolated_gvarray.get_internal_span(); attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); @@ -561,8 +559,8 @@ static void copy_profile_point_attribute_to_mesh(const GSpan src, const ResultInfo &info, ResultAttributeData &dst) { - GVArrayPtr interpolated_gvarray = info.profile.interpolate_to_evaluated(src); - GSpan interpolated = interpolated_gvarray->get_internal_span(); + GVArray interpolated_gvarray = info.profile.interpolate_to_evaluated(src); + GSpan interpolated = interpolated_gvarray.get_internal_span(); attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 2ef7ef91160..05f1e9b286f 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -763,7 +763,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) copy_v3_v3(bData->dim, dim); min_dim = max_fff(td[0], td[1], td[2]) / 1000.0f; - /* deactivate zero axises */ + /* deactivate zero axes */ for (i = 0; i < 3; i++) { if (td[i] < min_dim) { td[i] = 1.0f; @@ -784,7 +784,7 @@ static void surfaceGenerateGrid(struct DynamicPaintSurface *surface) dim_factor = (float)pow((double)volume / ((double)sData->total_points / 10000.0), 1.0 / (double)axis); - /* define final grid size using dim_factor, use min 3 for active axises */ + /* define final grid size using dim_factor, use min 3 for active axes */ for (i = 0; i < 3; i++) { grid->dim[i] = (int)floor(td[i] / dim_factor); CLAMP(grid->dim[i], (dim[i] >= min_dim) ? 3 : 1, 100); diff --git a/source/blender/blenkernel/intern/fcurve.c b/source/blender/blenkernel/intern/fcurve.c index 1564eb3aa7b..bbf61c51bfb 100644 --- a/source/blender/blenkernel/intern/fcurve.c +++ b/source/blender/blenkernel/intern/fcurve.c @@ -205,12 +205,16 @@ void BKE_fcurve_foreach_id(FCurve *fcu, LibraryForeachIDData *data) FMod_Python *fcm_py = (FMod_Python *)fcm->data; BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, fcm_py->script, IDWALK_CB_NOP); - IDP_foreach_property(fcm_py->prop, - IDP_TYPE_FILTER_ID, - BKE_lib_query_idpropertiesForeachIDLink_callback, - data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(fcm_py->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); break; } + default: + break; } } } diff --git a/source/blender/blenkernel/intern/fcurve_driver.c b/source/blender/blenkernel/intern/fcurve_driver.c index d1bf523acef..3ac64dbf84b 100644 --- a/source/blender/blenkernel/intern/fcurve_driver.c +++ b/source/blender/blenkernel/intern/fcurve_driver.c @@ -326,7 +326,7 @@ static float dvar_eval_rotDiff(ChannelDriver *driver, DriverVar *dvar) float(*mat[2])[4]; - /* NOTE: for now, these are all just worldspace */ + /* NOTE: for now, these are all just world-space. */ for (int i = 0; i < 2; i++) { /* Get pointer to loc values to store in. */ DriverTarget *dtar = &dvar->targets[i]; @@ -422,7 +422,7 @@ static float dvar_eval_locDiff(ChannelDriver *driver, DriverVar *dvar) } } else { - /* Convert to worldspace. */ + /* Convert to world-space. */ copy_v3_v3(tmp_loc, pchan->pose_head); mul_m4_v3(ob->obmat, tmp_loc); } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 6b7594dcf36..9d26a1528f3 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -5090,7 +5090,7 @@ void BKE_fluid_modifier_copy(const struct FluidModifierData *fmd, copy_v4_v4(tfds->gridlines_range_color, fds->gridlines_range_color); tfds->gridlines_cell_filter = fds->gridlines_cell_filter; - /* -- Deprecated / unsed options (below)-- */ + /* -- Deprecated / unused options (below)-- */ /* pointcache options */ BKE_ptcache_free_list(&(tfds->ptcaches[0])); diff --git a/source/blender/blenkernel/intern/geometry_component_curve.cc b/source/blender/blenkernel/intern/geometry_component_curve.cc index 961265f3a16..598c61fd877 100644 --- a/source/blender/blenkernel/intern/geometry_component_curve.cc +++ b/source/blender/blenkernel/intern/geometry_component_curve.cc @@ -28,10 +28,8 @@ using blender::fn::GMutableSpan; using blender::fn::GSpan; -using blender::fn::GVArray_For_GSpan; +using blender::fn::GVArray; using blender::fn::GVArray_GSpan; -using blender::fn::GVArrayPtr; -using blender::fn::GVMutableArray_For_GMutableSpan; /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation @@ -253,15 +251,15 @@ void adapt_curve_domain_point_to_spline_impl(const CurveEval &curve, } } -static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_point_to_spline(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(curve.splines().size()); - adapt_curve_domain_point_to_spline_impl<T>(curve, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_curve_domain_point_to_spline_impl<T>(curve, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -272,29 +270,29 @@ static GVArrayPtr adapt_curve_domain_point_to_spline(const CurveEval &curve, GVA * attributes. The goal is to avoid copying the spline value for every one of its control points * unless it is necessary (in that case the materialize functions will be called). */ -template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { - GVArrayPtr original_varray_; +template<typename T> class VArray_For_SplineToPoint final : public VArrayImpl<T> { + GVArray original_varray_; /* Store existing data materialized if it was not already a span. This is expected * to be worth it because a single spline's value will likely be accessed many times. */ - fn::GVArray_Span<T> original_data_; + VArray_Span<T> original_data_; Array<int> offsets_; public: - VArray_For_SplineToPoint(GVArrayPtr original_varray, Array<int> offsets) - : VArray<T>(offsets.last()), + VArray_For_SplineToPoint(GVArray original_varray, Array<int> offsets) + : VArrayImpl<T>(offsets.last()), original_varray_(std::move(original_varray)), - original_data_(*original_varray_), + original_data_(original_varray_.typed<T>()), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return original_data_[indices.spline_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { const int total_size = offsets_.last(); if (mask.is_range() && mask.as_range() == IndexRange(total_size)) { @@ -315,7 +313,7 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { T *dst = r_span.data(); const int total_size = offsets_.last(); @@ -338,29 +336,29 @@ template<typename T> class VArray_For_SplineToPoint final : public VArray<T> { } }; -static GVArrayPtr adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArrayPtr varray) +static GVArray adapt_curve_domain_spline_to_point(const CurveEval &curve, GVArray varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); Array<int> offsets = curve.control_point_offsets(); - new_varray = std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplineToPoint<T>>>( - offsets.last(), std::move(varray), std::move(offsets)); + new_varray = VArray<T>::template For<VArray_For_SplineToPoint<T>>(std::move(varray), + std::move(offsets)); }); return new_varray; } } // namespace blender::bke -GVArrayPtr CurveComponent::attribute_try_adapt_domain(GVArrayPtr varray, - const AttributeDomain from_domain, - const AttributeDomain to_domain) const +GVArray CurveComponent::attribute_try_adapt_domain_impl(const GVArray &varray, + const AttributeDomain from_domain, + const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.is_empty()) { return {}; } if (from_domain == to_domain) { @@ -402,8 +400,8 @@ static const CurveEval *get_curve_from_component_for_read(const GeometryComponen namespace blender::bke { class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = GVArrayPtr (*)(const CurveEval &data); - using AsWriteAttribute = GVMutableArrayPtr (*)(CurveEval &data); + using AsReadAttribute = GVArray (*)(const CurveEval &data); + using AsWriteAttribute = GVMutableArray (*)(CurveEval &data); const AsReadAttribute as_read_attribute_; const AsWriteAttribute as_write_attribute_; @@ -424,7 +422,7 @@ class BuiltinSplineAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -483,19 +481,15 @@ static void set_spline_resolution(SplinePtr &spline, const int resolution) } } -static GVArrayPtr make_resolution_read_attribute(const CurveEval &curve) +static GVArray make_resolution_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, int, get_spline_resolution>>( - curve.splines()); + return VArray<int>::ForDerivedSpan<SplinePtr, get_spline_resolution>(curve.splines()); } -static GVMutableArrayPtr make_resolution_write_attribute(CurveEval &curve) +static GVMutableArray make_resolution_write_attribute(CurveEval &curve) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<SplinePtr, - int, - get_spline_resolution, - set_spline_resolution>>( - curve.splines()); + return VMutableArray<int>:: + ForDerivedSpan<SplinePtr, get_spline_resolution, set_spline_resolution>(curve.splines()); } static bool get_cyclic_value(const SplinePtr &spline) @@ -511,16 +505,14 @@ static void set_cyclic_value(SplinePtr &spline, const bool value) } } -static GVArrayPtr make_cyclic_read_attribute(const CurveEval &curve) +static GVArray make_cyclic_read_attribute(const CurveEval &curve) { - return std::make_unique<fn::GVArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value>>( - curve.splines()); + return VArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value>(curve.splines()); } -static GVMutableArrayPtr make_cyclic_write_attribute(CurveEval &curve) +static GVMutableArray make_cyclic_write_attribute(CurveEval &curve) { - return std::make_unique< - fn::GVMutableArray_For_DerivedSpan<SplinePtr, bool, get_cyclic_value, set_cyclic_value>>( + return VMutableArray<bool>::ForDerivedSpan<SplinePtr, get_cyclic_value, set_cyclic_value>( curve.splines()); } @@ -625,9 +617,9 @@ static void point_attribute_materialize_to_uninitialized(Span<Span<T>> data, } } -static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, - const CustomDataType data_type, - const Span<SplinePtr> splines) +static GVArray varray_from_initializer(const AttributeInit &initializer, + const CustomDataType data_type, + const Span<SplinePtr> splines) { switch (initializer.type) { case AttributeInit::Type::Default: @@ -636,16 +628,15 @@ static GVArrayPtr varray_from_initializer(const AttributeInit &initializer, BLI_assert_unreachable(); return {}; case AttributeInit::Type::VArray: - return static_cast<const AttributeInitVArray &>(initializer).varray->shallow_copy(); + return static_cast<const AttributeInitVArray &>(initializer).varray; case AttributeInit::Type::MoveArray: int total_size = 0; for (const SplinePtr &spline : splines) { total_size += spline->size(); } - return std::make_unique<fn::GVArray_For_GSpan>( - GSpan(*bke::custom_data_type_to_cpp_type(data_type), - static_cast<const AttributeInitMove &>(initializer).data, - total_size)); + return GVArray::ForSpan(GSpan(*bke::custom_data_type_to_cpp_type(data_type), + static_cast<const AttributeInitMove &>(initializer).data, + total_size)); } BLI_assert_unreachable(); return {}; @@ -693,11 +684,11 @@ static bool create_point_attribute(GeometryComponent &component, /* We just created the attribute, it should exist. */ BLI_assert(write_attribute); - GVArrayPtr source_varray = varray_from_initializer(initializer, data_type, splines); + GVArray source_varray = varray_from_initializer(initializer, data_type, splines); /* TODO: When we can call a variant of #set_all with a virtual array argument, * this theoretically unnecessary materialize step could be removed. */ - GVArray_GSpan source_varray_span{*source_varray}; - write_attribute.varray->set_all(source_varray_span.data()); + GVArray_GSpan source_varray_span{source_varray}; + write_attribute.varray.set_all(source_varray_span.data()); if (initializer.type == AttributeInit::Type::MoveArray) { MEM_freeN(static_cast<const AttributeInitMove &>(initializer).data); @@ -725,29 +716,29 @@ static bool remove_point_attribute(GeometryComponent &component, /** * Virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VArray_For_SplinePoints : public VArray<T> { +template<typename T> class VArray_For_SplinePoints : public VArrayImpl<T> { private: const Array<Span<T>> data_; Array<int> offsets_; public: VArray_For_SplinePoints(Array<Span<T>> data, Array<int> offsets) - : VArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize(data_.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized(data_.as_span(), offsets_, mask, r_span); } @@ -756,30 +747,30 @@ template<typename T> class VArray_For_SplinePoints : public VArray<T> { /** * Mutable virtual array for any control point data accessed with spans and an offset array. */ -template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArray<T> { +template<typename T> class VMutableArray_For_SplinePoints final : public VMutableArrayImpl<T> { private: Array<MutableSpan<T>> data_; Array<int> offsets_; public: VMutableArray_For_SplinePoints(Array<MutableSpan<T>> data, Array<int> offsets) - : VMutableArray<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) + : VMutableArrayImpl<T>(offsets.last()), data_(std::move(data)), offsets_(std::move(offsets)) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return data_[indices.spline_index][indices.point_index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { const PointIndices indices = lookup_point_indices(offsets_, index); data_[indices.spline_index][indices.point_index] = value; } - void set_all_impl(Span<T> src) final + void set_all(Span<T> src) final { for (const int spline_index : data_.index_range()) { const int offset = offsets_[spline_index]; @@ -788,30 +779,28 @@ template<typename T> class VMutableArray_For_SplinePoints final : public VMutabl } } - void materialize_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize({(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, MutableSpan<T> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<T> r_span) const final { point_attribute_materialize_to_uninitialized( {(Span<T> *)data_.data(), data_.size()}, offsets_, mask, r_span); } }; -template<typename T> GVArrayPtr point_data_gvarray(Array<Span<T>> spans, Array<int> offsets) +template<typename T> VArray<T> point_data_varray(Array<Span<T>> spans, Array<int> offsets) { - return std::make_unique<fn::GVArray_For_EmbeddedVArray<T, VArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VArray<T>::template For<VArray_For_SplinePoints<T>>(std::move(spans), std::move(offsets)); } template<typename T> -GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> offsets) +VMutableArray<T> point_data_varray(Array<MutableSpan<T>> spans, Array<int> offsets) { - return std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_SplinePoints<T>>>( - offsets.last(), std::move(spans), std::move(offsets)); + return VMutableArray<T>::template For<VMutableArray_For_SplinePoints<T>>(std::move(spans), + std::move(offsets)); } /** @@ -822,24 +811,24 @@ GVMutableArrayPtr point_data_gvarray(Array<MutableSpan<T>> spans, Array<int> off * \note There is no need to check the handle type to avoid changing auto handles, since * retrieving write access to the position data will mark them for recomputation anyway. */ -class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { +class VMutableArray_For_SplinePosition final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; public: VMutableArray_For_SplinePosition(MutableSpan<SplinePtr> splines, Array<int> offsets) - : VMutableArray<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { const PointIndices indices = lookup_point_indices(offsets_, index); return splines_[indices.spline_index]->positions()[indices.point_index]; } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -854,7 +843,7 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -887,21 +876,20 @@ class VMutableArray_For_SplinePosition final : public VMutableArray<float3> { return spans; } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize(spans.as_span(), offsets_, mask, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { Array<Span<float3>> spans = this->get_position_spans(); point_attribute_materialize_to_uninitialized(spans.as_span(), offsets_, mask, r_span); } }; -class VArray_For_BezierHandle final : public VArray<float3> { +class VArray_For_BezierHandle final : public VArrayImpl<float3> { private: Span<SplinePtr> splines_; Array<int> offsets_; @@ -909,7 +897,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { public: VArray_For_BezierHandle(Span<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VArray<float3>(offsets.last()), + : VArrayImpl<float3>(offsets.last()), splines_(std::move(splines)), offsets_(std::move(offsets)), is_right_(is_right) @@ -931,7 +919,7 @@ class VArray_For_BezierHandle final : public VArray<float3> { return float3(0); } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return get_internal(index, splines_, offsets_, is_right_); } @@ -978,19 +966,18 @@ class VArray_For_BezierHandle final : public VArray<float3> { point_attribute_materialize_to_uninitialized(spans.as_span(), offsets, mask, r_span); } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { materialize_to_uninitialized_internal(mask, splines_, offsets_, is_right_, r_span); } }; -class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { +class VMutableArray_For_BezierHandles final : public VMutableArrayImpl<float3> { private: MutableSpan<SplinePtr> splines_; Array<int> offsets_; @@ -1000,19 +987,19 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { VMutableArray_For_BezierHandles(MutableSpan<SplinePtr> splines, Array<int> offsets, const bool is_right) - : VMutableArray<float3>(offsets.last()), + : VMutableArrayImpl<float3>(offsets.last()), splines_(splines), offsets_(std::move(offsets)), is_right_(is_right) { } - float3 get_impl(const int64_t index) const final + float3 get(const int64_t index) const final { return VArray_For_BezierHandle::get_internal(index, splines_, offsets_, is_right_); } - void set_impl(const int64_t index, float3 value) final + void set(const int64_t index, float3 value) final { const PointIndices indices = lookup_point_indices(offsets_, index); Spline &spline = *splines_[indices.spline_index]; @@ -1028,7 +1015,7 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void set_all_impl(Span<float3> src) final + void set_all(Span<float3> src) final { for (const int spline_index : splines_.index_range()) { Spline &spline = *splines_[spline_index]; @@ -1051,13 +1038,12 @@ class VMutableArray_For_BezierHandles final : public VMutableArray<float3> { } } - void materialize_impl(const IndexMask mask, MutableSpan<float3> r_span) const final + void materialize(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_internal(mask, splines_, offsets_, is_right_, r_span); } - void materialize_to_uninitialized_impl(const IndexMask mask, - MutableSpan<float3> r_span) const final + void materialize_to_uninitialized(const IndexMask mask, MutableSpan<float3> r_span) const final { VArray_For_BezierHandle::materialize_to_uninitialized_internal( mask, splines_, offsets_, is_right_, r_span); @@ -1099,7 +1085,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1112,7 +1098,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu Span<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return std::make_unique<fn::GVArray_For_GSpan>(get_span_(*splines.first())); + return GVArray::ForSpan(get_span_(*splines.first())); } Array<int> offsets = curve->control_point_offsets(); @@ -1121,7 +1107,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_span_(*splines[i]); } - return point_data_gvarray(spans, offsets); + return point_data_varray(spans, offsets); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1146,8 +1132,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu MutableSpan<SplinePtr> splines = curve->splines(); if (splines.size() == 1) { - return {std::make_unique<fn::GVMutableArray_For_GMutableSpan>( - get_mutable_span_(*splines.first())), + return {GVMutableArray::ForSpan(get_mutable_span_(*splines.first())), domain_, std::move(tag_modified_fn)}; } @@ -1158,7 +1143,7 @@ template<typename T> class BuiltinPointAttributeProvider : public BuiltinAttribu spans[i] = get_mutable_span_(*splines[i]); } - return {point_data_gvarray(spans, offsets), domain_, tag_modified_fn}; + return {point_data_varray(spans, offsets), domain_, tag_modified_fn}; } bool try_delete(GeometryComponent &component) const final @@ -1250,10 +1235,8 @@ class PositionAttributeProvider final : public BuiltinPointAttributeProvider<flo }; Array<int> offsets = curve->control_point_offsets(); - return {std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, - VMutableArray_For_SplinePosition>>( - offsets.last(), curve->splines(), std::move(offsets)), + return {VMutableArray<float3>::For<VMutableArray_For_SplinePosition>(curve->splines(), + std::move(offsets)), domain_, tag_modified_fn}; } @@ -1275,7 +1258,7 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const override + GVArray try_get_for_read(const GeometryComponent &component) const override { const CurveEval *curve = get_curve_from_component_for_read(component); if (curve == nullptr) { @@ -1287,8 +1270,8 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { } Array<int> offsets = curve->control_point_offsets(); - return std::make_unique<fn::GVArray_For_EmbeddedVArray<float3, VArray_For_BezierHandle>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_); + return VArray<float3>::For<VArray_For_BezierHandle>( + curve->splines(), std::move(offsets), is_right_); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const override @@ -1305,12 +1288,10 @@ class BezierHandleAttributeProvider : public BuiltinAttributeProvider { auto tag_modified_fn = [curve]() { curve->mark_cache_invalid(); }; Array<int> offsets = curve->control_point_offsets(); - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float3, VMutableArray_For_BezierHandles>>( - offsets.last(), curve->splines(), std::move(offsets), is_right_), - domain_, - tag_modified_fn}; + return {VMutableArray<float3>::For<VMutableArray_For_BezierHandles>( + curve->splines(), std::move(offsets), is_right_), + domain_, + tag_modified_fn}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -1389,7 +1370,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVArray_For_GSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } ReadAttributeLookup attribute = {}; @@ -1401,7 +1382,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } @@ -1442,7 +1423,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { /* First check for the simpler situation when we can return a simpler span virtual array. */ if (spans.size() == 1) { - return {std::make_unique<GVMutableArray_For_GMutableSpan>(spans.first()), ATTR_DOMAIN_POINT}; + return {GVMutableArray::ForSpan(spans.first()), ATTR_DOMAIN_POINT}; } WriteAttributeLookup attribute = {}; @@ -1454,7 +1435,7 @@ class DynamicPointAttributeProvider final : public DynamicAttributesProvider { data[i] = spans[i].typed<T>(); BLI_assert(data[i].data() != nullptr); } - attribute = {point_data_gvarray(data, offsets), ATTR_DOMAIN_POINT}; + attribute = {point_data_varray(data, offsets), ATTR_DOMAIN_POINT}; }); return attribute; } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc index 5fe77000519..9a30c86c1e5 100644 --- a/source/blender/blenkernel/intern/geometry_component_instances.cc +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -363,12 +363,22 @@ blender::Span<int> InstancesComponent::almost_unique_ids() const int InstancesComponent::attribute_domain_size(const AttributeDomain domain) const { - if (domain != ATTR_DOMAIN_POINT) { + if (domain != ATTR_DOMAIN_INSTANCE) { return 0; } return this->instances_amount(); } +blender::bke::CustomDataAttributes &InstancesComponent::attributes() +{ + return this->attributes_; +} + +const blender::bke::CustomDataAttributes &InstancesComponent::attributes() const +{ + return this->attributes_; +} + namespace blender::bke { static float3 get_transform_position(const float4x4 &transform) @@ -385,29 +395,26 @@ class InstancePositionAttributeProvider final : public BuiltinAttributeProvider public: InstancePositionAttributeProvider() : BuiltinAttributeProvider( - "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) + "position", ATTR_DOMAIN_INSTANCE, CD_PROP_FLOAT3, NonCreatable, Writable, NonDeletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances_component = static_cast<const InstancesComponent &>( component); Span<float4x4> transforms = instances_component.instance_transforms(); - return std::make_unique<fn::GVArray_For_DerivedSpan<float4x4, float3, get_transform_position>>( - transforms); + return VArray<float3>::ForDerivedSpan<float4x4, get_transform_position>(transforms); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final { InstancesComponent &instances_component = static_cast<InstancesComponent &>(component); MutableSpan<float4x4> transforms = instances_component.instance_transforms(); - return { - std::make_unique<fn::GVMutableArray_For_DerivedSpan<float4x4, - float3, - get_transform_position, - set_transform_position>>(transforms), - domain_}; + return {VMutableArray<float3>::ForDerivedSpan<float4x4, + get_transform_position, + set_transform_position>(transforms), + domain_}; } bool try_delete(GeometryComponent &UNUSED(component)) const final @@ -431,17 +438,17 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { public: InstanceIDAttributeProvider() : BuiltinAttributeProvider( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32, Creatable, Writable, Deletable) + "id", ATTR_DOMAIN_INSTANCE, CD_PROP_INT32, Creatable, Writable, Deletable) { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const InstancesComponent &instances = static_cast<const InstancesComponent &>(component); if (instances.instance_ids().is_empty()) { return {}; } - return std::make_unique<fn::GVArray_For_Span<int>>(instances.instance_ids()); + return VArray<int>::ForSpan(instances.instance_ids()); } WriteAttributeLookup try_get_for_write(GeometryComponent &component) const final @@ -450,8 +457,7 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { if (instances.instance_ids().is_empty()) { return {}; } - return {std::make_unique<fn::GVMutableArray_For_MutableSpan<int>>(instances.instance_ids()), - domain_}; + return {VMutableArray<int>::ForSpan(instances.instance_ids()), domain_}; } bool try_delete(GeometryComponent &component) const final @@ -477,8 +483,8 @@ class InstanceIDAttributeProvider final : public BuiltinAttributeProvider { break; } case AttributeInit::Type::VArray: { - const GVArray *varray = static_cast<const AttributeInitVArray &>(initializer).varray; - varray->materialize_to_uninitialized(IndexRange(varray->size()), ids.data()); + const GVArray &varray = static_cast<const AttributeInitVArray &>(initializer).varray; + varray.materialize_to_uninitialized(varray.index_range(), ids.data()); break; } case AttributeInit::Type::MoveArray: { @@ -503,7 +509,21 @@ static ComponentAttributeProviders create_attribute_providers_for_instances() static InstancePositionAttributeProvider position; static InstanceIDAttributeProvider id; - return ComponentAttributeProviders({&position, &id}, {}); + static CustomDataAccessInfo instance_custom_data_access = { + [](GeometryComponent &component) -> CustomData * { + InstancesComponent &inst = static_cast<InstancesComponent &>(component); + return &inst.attributes().data; + }, + [](const GeometryComponent &component) -> const CustomData * { + const InstancesComponent &inst = static_cast<const InstancesComponent &>(component); + return &inst.attributes().data; + }, + nullptr}; + + static CustomDataAttributeProvider instance_custom_data(ATTR_DOMAIN_INSTANCE, + instance_custom_data_access); + + return ComponentAttributeProviders({&position, &id}, {&instance_custom_data}); } } // namespace blender::bke diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc index 0456316151c..a258a66cdf3 100644 --- a/source/blender/blenkernel/intern/geometry_component_mesh.cc +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -32,8 +32,6 @@ /* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); -using blender::fn::GVArray; - /* -------------------------------------------------------------------- */ /** \name Geometry Component Implementation * \{ */ @@ -203,17 +201,17 @@ void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { /* We compute all interpolated values at once, because for this interpolation, one has to * iterate over all loops anyway. */ Array<T> values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -239,14 +237,14 @@ static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); Array<T> values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); }); return new_varray; } @@ -295,15 +293,15 @@ void adapt_mesh_domain_corner_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -368,15 +366,15 @@ void adapt_mesh_domain_corner_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_corner_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_corner_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_corner_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -424,15 +422,15 @@ void adapt_mesh_domain_face_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_face_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -453,15 +451,15 @@ void adapt_mesh_domain_face_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -507,15 +505,15 @@ void adapt_mesh_domain_face_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_face_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_face_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_face_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -567,15 +565,15 @@ void adapt_mesh_domain_point_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_point_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -617,15 +615,15 @@ void adapt_mesh_domain_point_to_edge_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_point_to_edge(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_point_to_edge(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totedge); - adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_point_to_edge_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -678,15 +676,15 @@ void adapt_mesh_domain_edge_to_corner_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_corner(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_corner(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totloop); - adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_corner_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -728,15 +726,15 @@ void adapt_mesh_domain_edge_to_point_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_point(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_point(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totvert); - adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_point_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -788,15 +786,15 @@ void adapt_mesh_domain_edge_to_face_impl(const Mesh &mesh, } } -static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr varray) +static GVArray adapt_mesh_domain_edge_to_face(const Mesh &mesh, const GVArray &varray) { - GVArrayPtr new_varray; - attribute_math::convert_to_static_type(varray->type(), [&](auto dummy) { + GVArray new_varray; + attribute_math::convert_to_static_type(varray.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { Array<T> values(mesh.totpoly); - adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray->typed<T>(), values); - new_varray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + adapt_mesh_domain_edge_to_face_impl<T>(mesh, varray.typed<T>(), values); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); return new_varray; @@ -804,15 +802,15 @@ static GVArrayPtr adapt_mesh_domain_edge_to_face(const Mesh &mesh, GVArrayPtr va } // namespace blender::bke -blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( - blender::fn::GVArrayPtr varray, +blender::fn::GVArray MeshComponent::attribute_try_adapt_domain_impl( + const blender::fn::GVArray &varray, const AttributeDomain from_domain, const AttributeDomain to_domain) const { if (!varray) { return {}; } - if (varray->size() == 0) { + if (varray.size() == 0) { return {}; } if (from_domain == to_domain) { @@ -823,11 +821,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_CORNER: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_corner_to_edge(*mesh_, varray); default: break; } @@ -836,11 +834,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_POINT: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_face(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_point_to_edge(*mesh_, varray); default: break; } @@ -849,11 +847,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_FACE: { switch (to_domain) { case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_point(*mesh_, varray); case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_corner(*mesh_, varray); case ATTR_DOMAIN_EDGE: - return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_face_to_edge(*mesh_, varray); default: break; } @@ -862,11 +860,11 @@ blender::fn::GVArrayPtr MeshComponent::attribute_try_adapt_domain( case ATTR_DOMAIN_EDGE: { switch (to_domain) { case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_corner(*mesh_, varray); case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_point(*mesh_, varray); case ATTR_DOMAIN_FACE: - return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, std::move(varray)); + return blender::bke::adapt_mesh_domain_edge_to_face(*mesh_, varray); default: break; } @@ -896,9 +894,9 @@ static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &com namespace blender::bke { template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -static GVArrayPtr make_derived_read_attribute(const void *data, const int domain_size) +static GVArray make_derived_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( + return VArray<ElemT>::template ForDerivedSpan<StructT, GetFunc>( Span<StructT>((const StructT *)data, domain_size)); } @@ -906,23 +904,22 @@ template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, ElemT)> -static GVMutableArrayPtr make_derived_write_attribute(void *data, const int domain_size) +static GVMutableArray make_derived_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>( + return VMutableArray<ElemT>::template ForDerivedSpan<StructT, GetFunc, SetFunc>( MutableSpan<StructT>((StructT *)data, domain_size)); } template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } static float3 get_vertex_position(const MVert &vert) @@ -999,23 +996,23 @@ static void set_crease(MEdge &edge, float value) edge.crease = round_fl_to_uchar_clamp(value * 255.0f); } -class VMutableArray_For_VertexWeights final : public VMutableArray<float> { +class VMutableArray_For_VertexWeights final : public VMutableArrayImpl<float> { private: MDeformVert *dverts_; const int dvert_index_; public: VMutableArray_For_VertexWeights(MDeformVert *dverts, const int totvert, const int dvert_index) - : VMutableArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VMutableArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return get_internal(dverts_, dvert_index_, index); } - void set_impl(const int64_t index, const float value) override + void set(const int64_t index, const float value) override { MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); weight->weight = value; @@ -1036,18 +1033,18 @@ class VMutableArray_For_VertexWeights final : public VMutableArray<float> { } }; -class VArray_For_VertexWeights final : public VArray<float> { +class VArray_For_VertexWeights final : public VArrayImpl<float> { private: const MDeformVert *dverts_; const int dvert_index_; public: VArray_For_VertexWeights(const MDeformVert *dverts, const int totvert, const int dvert_index) - : VArray<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) + : VArrayImpl<float>(totvert), dverts_(dverts), dvert_index_(dvert_index) { } - float get_impl(const int64_t index) const override + float get(const int64_t index) const override { return VMutableArray_For_VertexWeights::get_internal(dverts_, dvert_index_, index); } @@ -1078,12 +1075,10 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { } if (mesh->dvert == nullptr) { static const float default_value = 0.0f; - return {std::make_unique<fn::GVArray_For_SingleValueRef>( - CPPType::get<float>(), mesh->totvert, &default_value), - ATTR_DOMAIN_POINT}; + return {VArray<float>::ForSingle(default_value, mesh->totvert), ATTR_DOMAIN_POINT}; } - return {std::make_unique<fn::GVArray_For_EmbeddedVArray<float, VArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), + return {VArray<float>::For<VArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), ATTR_DOMAIN_POINT}; } @@ -1114,11 +1109,9 @@ class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); } - return { - std::make_unique< - fn::GVMutableArray_For_EmbeddedVMutableArray<float, VMutableArray_For_VertexWeights>>( - mesh->totvert, mesh->dvert, mesh->totvert, vertex_group_index), - ATTR_DOMAIN_POINT}; + return {VMutableArray<float>::For<VMutableArray_For_VertexWeights>( + mesh->dvert, mesh->totvert, vertex_group_index), + ATTR_DOMAIN_POINT}; } bool try_delete(GeometryComponent &component, const AttributeIDRef &attribute_id) const final @@ -1187,7 +1180,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { { } - GVArrayPtr try_get_for_read(const GeometryComponent &component) const final + GVArray try_get_for_read(const GeometryComponent &component) const final { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); @@ -1200,8 +1193,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh->pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, mesh->totpoly)); + return VArray<float3>::ForSpan(Span<float3>((const float3 *)data, mesh->totpoly)); } Array<float3> normals(mesh->totpoly); @@ -1210,7 +1202,7 @@ class NormalAttributeProvider final : public BuiltinAttributeProvider { BKE_mesh_calc_poly_normal(poly, &mesh->mloop[poly->loopstart], mesh->mvert, normals[i]); } - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } WriteAttributeLookup try_get_for_write(GeometryComponent &UNUSED(component)) const final diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc index dfb65a9078d..c6a1c61a96d 100644 --- a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -141,16 +141,15 @@ int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) con namespace blender::bke { template<typename T> -static GVArrayPtr make_array_read_attribute(const void *data, const int domain_size) +static GVArray make_array_read_attribute(const void *data, const int domain_size) { - return std::make_unique<fn::GVArray_For_Span<T>>(Span<T>((const T *)data, domain_size)); + return VArray<T>::ForSpan(Span<T>((const T *)data, domain_size)); } template<typename T> -static GVMutableArrayPtr make_array_write_attribute(void *data, const int domain_size) +static GVMutableArray make_array_write_attribute(void *data, const int domain_size) { - return std::make_unique<fn::GVMutableArray_For_MutableSpan<T>>( - MutableSpan<T>((T *)data, domain_size)); + return VMutableArray<T>::ForSpan(MutableSpan<T>((T *)data, domain_size)); } /** diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index cd1bafe445a..c250c14f1d7 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -610,24 +610,32 @@ bool BKE_object_has_geometry_set_instances(const Object *ob) if (geometry_set == nullptr) { return false; } - if (geometry_set->has_instances()) { - return true; - } - const bool has_mesh = geometry_set->has_mesh(); - const bool has_pointcloud = geometry_set->has_pointcloud(); - const bool has_volume = geometry_set->has_volume(); - const bool has_curve = geometry_set->has_curve(); - if (ob->type == OB_MESH) { - return has_pointcloud || has_volume || has_curve; - } - if (ob->type == OB_POINTCLOUD) { - return has_mesh || has_volume || has_curve; - } - if (ob->type == OB_VOLUME) { - return has_mesh || has_pointcloud || has_curve; - } - if (ELEM(ob->type, OB_CURVE, OB_FONT)) { - return has_mesh || has_pointcloud || has_volume; + for (const GeometryComponent *component : geometry_set->get_components_for_read()) { + if (component->is_empty()) { + continue; + } + const GeometryComponentType type = component->type(); + bool is_instance = false; + switch (type) { + case GEO_COMPONENT_TYPE_MESH: + is_instance = ob->type != OB_MESH; + break; + case GEO_COMPONENT_TYPE_POINT_CLOUD: + is_instance = ob->type != OB_POINTCLOUD; + break; + case GEO_COMPONENT_TYPE_INSTANCES: + is_instance = true; + break; + case GEO_COMPONENT_TYPE_VOLUME: + is_instance = ob->type != OB_VOLUME; + break; + case GEO_COMPONENT_TYPE_CURVE: + is_instance = !ELEM(ob->type, OB_CURVE, OB_FONT); + break; + } + if (is_instance) { + return true; + } } return false; } diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 8a7840acd73..c73da7d9659 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -89,8 +89,7 @@ GeometrySet object_get_evaluated_geometry_set(const Object &object) static void geometry_set_collect_recursive_collection_instance( const Collection &collection, const float4x4 &transform, Vector<GeometryInstanceGroup> &r_sets) { - float4x4 offset_matrix; - unit_m4(offset_matrix.values); + float4x4 offset_matrix = float4x4::identity(); sub_v3_v3(offset_matrix.values[3], collection.instance_offset); const float4x4 instance_transform = transform * offset_matrix; geometry_set_collect_recursive_collection(collection, instance_transform, r_sets); @@ -183,10 +182,7 @@ static void geometry_set_collect_recursive(const GeometrySet &geometry_set, void geometry_set_gather_instances(const GeometrySet &geometry_set, Vector<GeometryInstanceGroup> &r_instance_groups) { - float4x4 unit_transform; - unit_m4(unit_transform.values); - - geometry_set_collect_recursive(geometry_set, unit_transform, r_instance_groups); + geometry_set_collect_recursive(geometry_set, float4x4::identity(), r_instance_groups); } void geometry_set_gather_instances_attribute_info(Span<GeometryInstanceGroup> set_groups, @@ -364,12 +360,12 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, result.attribute_try_create( entry.key, domain_output, data_type_output, AttributeInitDefault()); WriteAttributeLookup write_attribute = result.attribute_try_get_for_write(attribute_id); - if (!write_attribute || &write_attribute.varray->type() != cpp_type || + if (!write_attribute || &write_attribute.varray.type() != cpp_type || write_attribute.domain != domain_output) { continue; } - fn::GVMutableArray_GSpan dst_span{*write_attribute.varray}; + fn::GVMutableArray_GSpan dst_span{write_attribute.varray}; int offset = 0; for (const GeometryInstanceGroup &set_group : set_groups) { @@ -381,11 +377,11 @@ static void join_attributes(Span<GeometryInstanceGroup> set_groups, if (domain_size == 0) { continue; /* Domain size is 0, so no need to increment the offset. */ } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( attribute_id, domain_output, data_type_output); if (source_attribute) { - fn::GVArray_GSpan src_span{*source_attribute}; + fn::GVArray_GSpan src_span{source_attribute}; const void *src_buffer = src_span.data(); for (const int UNUSED(i) : set_group.transforms.index_range()) { void *dst_buffer = dst_span[offset]; diff --git a/source/blender/blenkernel/intern/gpencil_geom.cc b/source/blender/blenkernel/intern/gpencil_geom.cc index debdf44b0bb..fffc13c49a8 100644 --- a/source/blender/blenkernel/intern/gpencil_geom.cc +++ b/source/blender/blenkernel/intern/gpencil_geom.cc @@ -3122,8 +3122,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, bGPDstroke *gps, bGPDstroke *next_stroke, int tag_flags, - bool select, - int limit) + const bool select, + const bool flat_cap, + const int limit) { tGPDeleteIsland *islands = (tGPDeleteIsland *)MEM_callocN( sizeof(tGPDeleteIsland) * (gps->totpoints + 1) / 2, "gp_point_islands"); @@ -3171,6 +3172,9 @@ bGPDstroke *BKE_gpencil_stroke_delete_tagged_points(bGPdata *gpd, for (idx = 0; idx < num_islands; idx++) { tGPDeleteIsland *island = &islands[idx]; new_stroke = BKE_gpencil_stroke_duplicate(gps, false, true); + if (flat_cap) { + new_stroke->caps[1 - (idx % 2)] = GP_STROKE_CAP_FLAT; + } /* if cyclic and first stroke, save to join later */ if ((is_cyclic) && (gps_first == nullptr)) { diff --git a/source/blender/blenkernel/intern/icons.cc b/source/blender/blenkernel/intern/icons.cc index 9cf289935ab..c2250dd04f9 100644 --- a/source/blender/blenkernel/intern/icons.cc +++ b/source/blender/blenkernel/intern/icons.cc @@ -35,6 +35,7 @@ #include "DNA_gpencil_types.h" #include "DNA_light_types.h" #include "DNA_material_types.h" +#include "DNA_node_types.h" #include "DNA_object_types.h" #include "DNA_scene_types.h" #include "DNA_screen_types.h" @@ -375,6 +376,7 @@ PreviewImage **BKE_previewimg_id_get_p(const ID *id) ID_PRV_CASE(ID_SCE, Scene); ID_PRV_CASE(ID_SCR, bScreen); ID_PRV_CASE(ID_AC, bAction); + ID_PRV_CASE(ID_NT, bNodeTree); #undef ID_PRV_CASE default: break; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 0530d537daf..1ef5659855b 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -112,12 +112,26 @@ #include "DNA_view3d_types.h" static CLG_LogRef LOG = {"bke.image"}; -static ThreadMutex *image_mutex; static void image_init(Image *ima, short source, short type); static void image_free_packedfiles(Image *ima); static void copy_image_packedfiles(ListBase *lb_dst, const ListBase *lb_src); +/* Reset runtime image fields when datablock is being initialized. */ +static void image_runtime_reset(struct Image *image) +{ + memset(&image->runtime, 0, sizeof(image->runtime)); + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + +/* Reset runtime image fields when datablock is being copied. */ +static void image_runtime_reset_on_copy(struct Image *image) +{ + image->runtime.cache_mutex = MEM_mallocN(sizeof(ThreadMutex), "image runtime cache_mutex"); + BLI_mutex_init(image->runtime.cache_mutex); +} + static void image_init_data(ID *id) { Image *image = (Image *)id; @@ -167,6 +181,8 @@ static void image_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c else { image_dst->preview = NULL; } + + image_runtime_reset_on_copy(image_dst); } static void image_free_data(ID *id) @@ -194,6 +210,9 @@ static void image_free_data(ID *id) BLI_freelistN(&image->tiles); BLI_freelistN(&image->gpu_refresh_areas); + + BLI_mutex_end(image->runtime.cache_mutex); + MEM_freeN(image->runtime.cache_mutex); } static void image_foreach_cache(ID *id, @@ -325,6 +344,8 @@ static void image_blend_read_data(BlendDataReader *reader, ID *id) ima->lastused = 0; ima->gpuflag = 0; BLI_listbase_clear(&ima->gpu_refresh_areas); + + image_runtime_reset(ima); } static void image_blend_read_lib(BlendLibReader *UNUSED(reader), ID *id) @@ -452,16 +473,6 @@ static struct ImBuf *imagecache_get(Image *image, int index, bool *r_is_cached_e return NULL; } -void BKE_images_init(void) -{ - image_mutex = BLI_mutex_alloc(); -} - -void BKE_images_exit(void) -{ - BLI_mutex_free(image_mutex); -} - /* ***************** ALLOC & FREE, DATA MANAGING *************** */ static void image_free_cached_frames(Image *image) @@ -514,7 +525,7 @@ static void image_free_anims(Image *ima) void BKE_image_free_buffers_ex(Image *ima, bool do_lock) { if (do_lock) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); } image_free_cached_frames(ima); @@ -528,7 +539,7 @@ void BKE_image_free_buffers_ex(Image *ima, bool do_lock) BKE_image_free_gputextures(ima); if (do_lock) { - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -567,6 +578,8 @@ static void image_init(Image *ima, short source, short type) } } + image_runtime_reset(ima); + BKE_color_managed_colorspace_settings_init(&ima->colorspace_settings); ima->stereo3d_format = MEM_callocN(sizeof(Stereo3dFormat), "Image Stereo Format"); } @@ -640,7 +653,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) { /* sanity check */ if (dest && source && dest != source) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(source->runtime.cache_mutex); + BLI_mutex_lock(dest->runtime.cache_mutex); + if (source->cache != NULL) { struct MovieCacheIter *iter; iter = IMB_moviecacheIter_new(source->cache); @@ -652,7 +667,9 @@ void BKE_image_merge(Main *bmain, Image *dest, Image *source) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(dest->runtime.cache_mutex); + BLI_mutex_unlock(source->runtime.cache_mutex); BKE_id_free(bmain, source); } @@ -1243,7 +1260,8 @@ static uintptr_t image_mem_size(Image *image) return 0; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); + if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -1277,7 +1295,8 @@ static uintptr_t image_mem_size(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + + BLI_mutex_unlock(image->runtime.cache_mutex); return size; } @@ -1361,11 +1380,11 @@ static bool imagecache_check_free_anim(ImBuf *ibuf, void *UNUSED(userkey), void /* except_frame is weak, only works for seqs without offset... */ void BKE_image_free_anim_ibufs(Image *ima, int except_frame) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); if (ima->cache != NULL) { IMB_moviecache_cleanup(ima->cache, imagecache_check_free_anim, &except_frame); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } void BKE_image_all_free_anim_ibufs(Main *bmain, int cfra) @@ -3284,7 +3303,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * } if (do_reset) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); image_free_cached_frames(ima); BKE_image_free_views(ima); @@ -3292,7 +3311,7 @@ void BKE_image_ensure_viewer_views(const RenderData *rd, Image *ima, ImageUser * /* add new views */ image_viewer_create_views(rd, ima); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } BLI_thread_unlock(LOCK_DRAW_IMAGE); @@ -3556,7 +3575,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) return; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); switch (signal) { case IMA_SIGNAL_FREE: @@ -3676,7 +3695,7 @@ void BKE_image_signal(Main *bmain, Image *ima, ImageUser *iuser, int signal) break; } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); /* don't use notifiers because they are not 100% sure to succeeded * this also makes sure all scenes are accounted for. */ @@ -5130,11 +5149,11 @@ ImBuf *BKE_image_acquire_ibuf(Image *ima, ImageUser *iuser, void **r_lock) { ImBuf *ibuf; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_acquire_ibuf(ima, iuser, r_lock); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); return ibuf; } @@ -5153,9 +5172,9 @@ void BKE_image_release_ibuf(Image *ima, ImBuf *ibuf, void *lock) } if (ibuf) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); } } @@ -5169,7 +5188,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) return false; } - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(ima->runtime.cache_mutex); ibuf = image_get_cached_ibuf(ima, iuser, NULL, NULL, NULL); @@ -5177,7 +5196,7 @@ bool BKE_image_has_ibuf(Image *ima, ImageUser *iuser) ibuf = image_acquire_ibuf(ima, iuser, NULL); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(ima->runtime.cache_mutex); IMB_freeImBuf(ibuf); @@ -5197,6 +5216,7 @@ typedef struct ImagePoolItem { typedef struct ImagePool { ListBase image_buffers; BLI_mempool *memory_pool; + ThreadMutex mutex; } ImagePool; ImagePool *BKE_image_pool_new(void) @@ -5204,21 +5224,28 @@ ImagePool *BKE_image_pool_new(void) ImagePool *pool = MEM_callocN(sizeof(ImagePool), "Image Pool"); pool->memory_pool = BLI_mempool_create(sizeof(ImagePoolItem), 0, 128, BLI_MEMPOOL_NOP); + BLI_mutex_init(&pool->mutex); + return pool; } void BKE_image_pool_free(ImagePool *pool) { /* Use single lock to dereference all the image buffers. */ - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(&pool->mutex); for (ImagePoolItem *item = pool->image_buffers.first; item != NULL; item = item->next) { if (item->ibuf != NULL) { + BLI_mutex_lock(item->image->runtime.cache_mutex); IMB_freeImBuf(item->ibuf); + BLI_mutex_unlock(item->image->runtime.cache_mutex); } } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); BLI_mempool_destroy(pool->memory_pool); + + BLI_mutex_end(&pool->mutex); + MEM_freeN(pool); } @@ -5250,28 +5277,34 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool } if (pool == NULL) { - /* pool could be NULL, in this case use general acquire function */ + /* Pool could be NULL, in this case use general acquire function. */ return BKE_image_acquire_ibuf(ima, iuser, NULL); } image_get_entry_and_index(ima, iuser, &entry, &index); + /* Use double-checked locking, to avoid locking when the requested image buffer is already in the + * pool. */ + ibuf = image_pool_find_item(pool, ima, entry, index, &found); if (found) { return ibuf; } - BLI_mutex_lock(image_mutex); + /* Lock the pool, to allow thread-safe modification of the content of the pool. */ + BLI_mutex_lock(&pool->mutex); ibuf = image_pool_find_item(pool, ima, entry, index, &found); - /* will also create item even in cases image buffer failed to load, - * prevents trying to load the same buggy file multiple times - */ + /* Will also create item even in cases image buffer failed to load, + * prevents trying to load the same buggy file multiple times. */ if (!found) { ImagePoolItem *item; - ibuf = image_acquire_ibuf(ima, iuser, NULL); + /* Thread-safe acquisition of an image buffer from the image. + * The acquisition does not use image pools, so there is no risk of recursive or out-of-order + * mutex locking. */ + ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); item = BLI_mempool_alloc(pool->memory_pool); item->image = ima; @@ -5282,7 +5315,7 @@ ImBuf *BKE_image_pool_acquire_ibuf(Image *ima, ImageUser *iuser, ImagePool *pool BLI_addtail(&pool->image_buffers, item); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(&pool->mutex); return ibuf; } @@ -5671,7 +5704,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) bool is_dirty = false; bool is_writable = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5686,7 +5719,7 @@ bool BKE_image_is_dirty_writable(Image *image, bool *r_is_writable) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); if (r_is_writable) { *r_is_writable = is_writable; @@ -5715,7 +5748,7 @@ bool BKE_image_buffer_format_writable(ImBuf *ibuf) void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions *options) { - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5729,14 +5762,14 @@ void BKE_image_file_format_set(Image *image, int ftype, const ImbFormatOptions * } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); } bool BKE_image_has_loaded_ibuf(Image *image) { bool has_loaded_ibuf = false; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5746,7 +5779,7 @@ bool BKE_image_has_loaded_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return has_loaded_ibuf; } @@ -5759,7 +5792,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5774,7 +5807,7 @@ ImBuf *BKE_image_get_ibuf_with_name(Image *image, const char *name) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } @@ -5792,7 +5825,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) { ImBuf *ibuf = NULL; - BLI_mutex_lock(image_mutex); + BLI_mutex_lock(image->runtime.cache_mutex); if (image->cache != NULL) { struct MovieCacheIter *iter = IMB_moviecacheIter_new(image->cache); @@ -5805,7 +5838,7 @@ ImBuf *BKE_image_get_first_ibuf(Image *image) } IMB_moviecacheIter_free(iter); } - BLI_mutex_unlock(image_mutex); + BLI_mutex_unlock(image->runtime.cache_mutex); return ibuf; } diff --git a/source/blender/blenkernel/intern/image_gen.c b/source/blender/blenkernel/intern/image_gen.c index 943909cc90f..bef14b6ad70 100644 --- a/source/blender/blenkernel/intern/image_gen.c +++ b/source/blender/blenkernel/intern/image_gen.c @@ -369,7 +369,7 @@ static void checker_board_text( char text[3] = {'A', '1', '\0'}; const int mono = blf_mono_font_render; - BLF_size(mono, 54, 72); /* hard coded size! */ + BLF_size(mono, 54.0f, 72); /* hard coded size! */ /* OCIO_TODO: using NULL as display will assume using sRGB display * this is correct since currently generated images are assumed to be in sRGB space, diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 9ed7218027f..66a550ec6b0 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -1028,7 +1028,7 @@ static void lib_override_library_proxy_convert_do(Main *bmain, if (success) { CLOG_INFO(&LOG, 4, - "Proxy object '%s' successfuly converted to library overrides", + "Proxy object '%s' successfully converted to library overrides", ob_proxy->id.name); /* Remove the instance empty from this scene, the items now have an overridden collection * instead. */ diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index 4165452801c..74750a9b61a 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -76,48 +76,52 @@ typedef struct LibraryForeachIDData { BLI_LINKSTACK_DECLARE(ids_todo, ID *); } LibraryForeachIDData; -bool BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +/** Check whether current iteration over ID usages should be stopped or not. + * \return true if the iteration should be stopped, false otherwise. */ +bool BKE_lib_query_foreachid_iter_stop(LibraryForeachIDData *data) { - if (!(data->status & IDWALK_STOP)) { - const int flag = data->flag; - ID *old_id = *id_pp; - - /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic - * caller code. */ - cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); - - /* Update the callback flags with some extra information regarding overrides: all 'loopback', - * 'internal', 'embedded' etc. ID pointers are never overridable. */ - if (cb_flag & - (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; - } + return (data->status & IDWALK_STOP) != 0; +} - const int callback_return = data->callback( - &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, - .bmain = data->bmain, - .id_owner = data->owner_id, - .id_self = data->self_id, - .id_pointer = id_pp, - .cb_flag = cb_flag}); - if (flag & IDWALK_READONLY) { - BLI_assert(*(id_pp) == old_id); - } - if (old_id && (flag & IDWALK_RECURSE)) { - if (BLI_gset_add((data)->ids_handled, old_id)) { - if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { - BLI_LINKSTACK_PUSH(data->ids_todo, old_id); - } +void BKE_lib_query_foreachid_process(LibraryForeachIDData *data, ID **id_pp, int cb_flag) +{ + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; + } + + const int flag = data->flag; + ID *old_id = *id_pp; + + /* Update the callback flags with the ones defined (or forbidden) in `data` by the generic + * caller code. */ + cb_flag = ((cb_flag | data->cb_flag) & ~data->cb_flag_clear); + + /* Update the callback flags with some extra information regarding overrides: all 'loopback', + * 'internal', 'embedded' etc. ID pointers are never overridable. */ + if (cb_flag & (IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { + cb_flag |= IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE; + } + + const int callback_return = data->callback( + &(struct LibraryIDLinkCallbackData){.user_data = data->user_data, + .bmain = data->bmain, + .id_owner = data->owner_id, + .id_self = data->self_id, + .id_pointer = id_pp, + .cb_flag = cb_flag}); + if (flag & IDWALK_READONLY) { + BLI_assert(*(id_pp) == old_id); + } + if (old_id && (flag & IDWALK_RECURSE)) { + if (BLI_gset_add((data)->ids_handled, old_id)) { + if (!(callback_return & IDWALK_RET_STOP_RECURSION)) { + BLI_LINKSTACK_PUSH(data->ids_todo, old_id); } } - if (callback_return & IDWALK_RET_STOP_ITER) { - data->status |= IDWALK_STOP; - return false; - } - return true; } - - return false; + if (callback_return & IDWALK_RET_STOP_ITER) { + data->status |= IDWALK_STOP; + } } int BKE_lib_query_foreachid_process_flags_get(LibraryForeachIDData *data) @@ -139,7 +143,7 @@ int BKE_lib_query_foreachid_process_callback_flag_override(LibraryForeachIDData return cb_flag_backup; } -static void library_foreach_ID_link(Main *bmain, +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -158,19 +162,24 @@ void BKE_lib_query_idpropertiesForeachIDLink_callback(IDProperty *id_prop, void BKE_LIB_FOREACHID_PROCESS_ID(data, id_prop->data.pointer, cb_flag); } -bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) +/** Process embedded ID pointers (root nodetrees, master collections, ...). + * + * Those require specific care, since they are technically sub-data of their owner, yet in some + * cases they still behave as regular IDs. */ +void BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) { /* Needed e.g. for callbacks handling relationships. This call shall be absolutely read-only. */ ID *id = *id_pp; const int flag = data->flag; - if (!BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED)) { - return false; + BKE_lib_query_foreachid_process(data, id_pp, IDWALK_CB_EMBEDDED); + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; } BLI_assert(id == *id_pp); if (id == NULL) { - return true; + return; } if (flag & IDWALK_IGNORE_EMBEDDED_ID) { @@ -186,14 +195,24 @@ bool BKE_library_foreach_ID_embedded(LibraryForeachIDData *data, ID **id_pp) } } else { - library_foreach_ID_link( - data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data); + if (!library_foreach_ID_link( + data->bmain, data->owner_id, id, data->callback, data->user_data, data->flag, data)) { + data->status |= IDWALK_STOP; + return; + } } +} - return true; +static void library_foreach_ID_data_cleanup(LibraryForeachIDData *data) +{ + if (data->ids_handled != NULL) { + BLI_gset_free(data->ids_handled, NULL); + BLI_LINKSTACK_FREE(data->ids_todo); + } } -static void library_foreach_ID_link(Main *bmain, +/** \return false in case iteration over ID pointers must be stopped, true otherwise. */ +static bool library_foreach_ID_link(Main *bmain, ID *id_owner, ID *id, LibraryIDLinkCallback callback, @@ -210,6 +229,10 @@ static void library_foreach_ID_link(Main *bmain, flag |= IDWALK_READONLY; flag &= ~IDWALK_DO_INTERNAL_RUNTIME_POINTERS; + /* NOTE: This function itself should never be called recursively when IDWALK_RECURSE is set, + * see also comments in #BKE_library_foreach_ID_embedded. + * This is why we can always create this data here, and do not need to try and re-use it from + * `inherit_data`. */ data.ids_handled = BLI_gset_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); BLI_LINKSTACK_INIT(data.ids_todo); @@ -224,10 +247,26 @@ static void library_foreach_ID_link(Main *bmain, data.user_data = user_data; #define CALLBACK_INVOKE_ID(check_id, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_ID(&data, check_id, cb_flag) + { \ + CHECK_TYPE_ANY((check_id), ID *, void *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) #define CALLBACK_INVOKE(check_id_super, cb_flag) \ - BKE_LIB_FOREACHID_PROCESS_IDSUPER(&data, check_id_super, cb_flag) + { \ + CHECK_TYPE(&((check_id_super)->id), ID *); \ + BKE_lib_query_foreachid_process(&data, (ID **)&(check_id_super), (cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop(&data)) { \ + library_foreach_ID_data_cleanup(&data); \ + return false; \ + } \ + } \ + ((void)0) for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; @@ -269,6 +308,10 @@ static void library_foreach_ID_link(Main *bmain, to_id_entry = to_id_entry->next) { BKE_lib_query_foreachid_process( &data, to_id_entry->id_pointer.to, to_id_entry->usage_flag); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } continue; } @@ -292,26 +335,33 @@ static void library_foreach_ID_link(Main *bmain, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } AnimData *adt = BKE_animdata_from_id(id); if (adt) { BKE_animdata_foreach_id(adt, &data); + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; + } } const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(id); if (id_type->foreach_id != NULL) { id_type->foreach_id(id, &data); - if (data.status & IDWALK_STOP) { - break; + if (BKE_lib_query_foreachid_iter_stop(&data)) { + library_foreach_ID_data_cleanup(&data); + return false; } } } - if (data.ids_handled) { - BLI_gset_free(data.ids_handled, NULL); - BLI_LINKSTACK_FREE(data.ids_todo); - } + library_foreach_ID_data_cleanup(&data); + return true; #undef CALLBACK_INVOKE_ID #undef CALLBACK_INVOKE diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index 905ac5af512..014c923f04f 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -132,7 +132,8 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) const bool is_obj = (GS(id_owner->name) == ID_OB); const bool is_obj_proxy = (is_obj && (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); - const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner) && + (id_remap_data->flag & ID_REMAP_FORCE_OBDATA_IN_EDITMODE) == 0); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; @@ -669,57 +670,10 @@ void BKE_libblock_relink_ex( DEG_relations_tag_update(bmain); } +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag); static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_EMBEDDED) { - return IDWALK_RET_NOP; - } - - ID **id_pointer = cb_data->id_pointer; - ID *id = *id_pointer; - if (id) { - /* See: NEW_ID macro */ - if (id->newid) { - BKE_library_update_ID_link_user(id->newid, id, cb_flag); - id = id->newid; - *id_pointer = id; - } - if (id->tag & LIB_TAG_NEW) { - id->tag &= ~LIB_TAG_NEW; - BKE_libblock_relink_to_newid(id); - } - } - return IDWALK_RET_NOP; -} - -/** - * Similar to #libblock_relink_ex, - * but is remapping IDs to their newid value if non-NULL, in given \a id. - * - * Very specific usage, not sure we'll keep it on the long run, - * currently only used in Object/Collection duplication code... - * - * WARNING: This is a deprecated version of this function, should not be used by new code. See - * #BKE_libblock_relink_to_newid_new below. - */ -void BKE_libblock_relink_to_newid(ID *id) -{ - if (ID_IS_LINKED(id)) { - return; - } - - BKE_library_foreach_ID_link(NULL, id, id_relink_to_newid_looper, NULL, 0); -} - -/* ************************ - * FIXME: Port all usages of #BKE_libblock_relink_to_newid to this - * #BKE_libblock_relink_to_newid_new new code and remove old one. - ************************** */ -static void libblock_relink_to_newid_new(Main *bmain, ID *id); -static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) -{ - const int cb_flag = cb_data->cb_flag; if (cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { return IDWALK_RET_NOP; } @@ -729,31 +683,31 @@ static int id_relink_to_newid_looper_new(LibraryIDLinkCallbackData *cb_data) ID **id_pointer = cb_data->id_pointer; ID *id = *id_pointer; if (id) { + const int remap_flag = POINTER_AS_INT(cb_data->user_data); /* See: NEW_ID macro */ if (id->newid != NULL) { - BKE_libblock_relink_ex(bmain, - id_owner, - id, - id->newid, - ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_OVERRIDE_LIBRARY); + const int remap_flag_final = remap_flag | ID_REMAP_SKIP_INDIRECT_USAGE | + ID_REMAP_SKIP_OVERRIDE_LIBRARY; + BKE_libblock_relink_ex(bmain, id_owner, id, id->newid, (short)remap_flag_final); id = id->newid; } if (id->tag & LIB_TAG_NEW) { id->tag &= ~LIB_TAG_NEW; - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); } } return IDWALK_RET_NOP; } -static void libblock_relink_to_newid_new(Main *bmain, ID *id) +static void libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; } id->tag &= ~LIB_TAG_NEW; - BKE_library_foreach_ID_link(bmain, id, id_relink_to_newid_looper_new, NULL, 0); + BKE_library_foreach_ID_link( + bmain, id, id_relink_to_newid_looper, POINTER_FROM_INT(remap_flag), 0); } /** @@ -765,7 +719,7 @@ static void libblock_relink_to_newid_new(Main *bmain, ID *id) * Very specific usage, not sure we'll keep it on the long run, * currently only used in Object/Collection duplication code... */ -void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) +void BKE_libblock_relink_to_newid(Main *bmain, ID *id, const int remap_flag) { if (ID_IS_LINKED(id)) { return; @@ -774,7 +728,7 @@ void BKE_libblock_relink_to_newid_new(Main *bmain, ID *id) BLI_assert(bmain->relations == NULL); BKE_layer_collection_resync_forbid(); - libblock_relink_to_newid_new(bmain, id); + libblock_relink_to_newid(bmain, id, remap_flag); BKE_layer_collection_resync_allow(); BKE_main_collection_sync_remap(bmain); } diff --git a/source/blender/blenkernel/intern/light.c b/source/blender/blenkernel/intern/light.c index a6150028f46..05e8d4fe978 100644 --- a/source/blender/blenkernel/intern/light.c +++ b/source/blender/blenkernel/intern/light.c @@ -129,7 +129,8 @@ static void light_foreach_id(ID *id, LibraryForeachIDData *data) Light *lamp = (Light *)id; if (lamp->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&lamp->nodetree)); } } diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index a1c93920731..3c305d1fb3f 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -155,12 +155,14 @@ static void linestyle_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (linestyle->mtex[i]) { - BKE_texture_mtex_foreach_id(data, linestyle->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_texture_mtex_foreach_id(data, linestyle->mtex[i])); } } if (linestyle->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&linestyle->nodetree)); } LISTBASE_FOREACH (LineStyleModifier *, lsm, &linestyle->color_modifiers) { diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index d82559a27cb..1fac83c5665 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -166,9 +166,8 @@ static void material_foreach_id(ID *id, LibraryForeachIDData *data) { Material *material = (Material *)id; /* Nodetrees **are owned by IDs**, treat them as mere sub-data and not real ID! */ - if (!BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)) { - return; - } + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&material->nodetree)); if (material->texpaintslot != NULL) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, material->texpaintslot->ima, IDWALK_CB_NOP); } @@ -903,7 +902,7 @@ void BKE_object_materials_test(Main *bmain, Object *ob, ID *id) if ((ob->id.tag & LIB_TAG_MISSING) == 0 && (id->tag & LIB_TAG_MISSING) != 0) { /* Exception: In case the object is a valid data, but its obdata is an empty place-holder, * use object's material slots amount as reference. - * This avoids loosing materials in a local object when its linked obdata gets missing. + * This avoids losing materials in a local object when its linked obdata goes missing. * See T92780. */ BKE_id_material_resize(bmain, id, (short)ob->totcol, false); } diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.cc index f0ba83b396b..73e0c2cfa74 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.cc @@ -124,7 +124,7 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int CustomData_MeshMasks_update(&mask, &CD_MASK_DERIVEDMESH); } - mesh_dst->mat = MEM_dupallocN(mesh_src->mat); + mesh_dst->mat = (Material **)MEM_dupallocN(mesh_src->mat); BKE_defgroup_copy_list(&mesh_dst->vertex_group_names, &mesh_src->vertex_group_names); @@ -142,9 +142,9 @@ static void mesh_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const int BKE_mesh_update_customdata_pointers(mesh_dst, do_tessface); - mesh_dst->edit_mesh = NULL; + mesh_dst->edit_mesh = nullptr; - mesh_dst->mselect = MEM_dupallocN(mesh_dst->mselect); + mesh_dst->mselect = (MSelect *)MEM_dupallocN(mesh_dst->mselect); /* TODO: Do we want to add flag to prevent this? */ if (mesh_src->key && (flag & LIB_ID_COPY_SHAPEKEY)) { @@ -165,7 +165,7 @@ static void mesh_free_data(ID *id) BKE_editmesh_free_data(mesh->edit_mesh); } MEM_freeN(mesh->edit_mesh); - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; } BKE_mesh_runtime_free_data(mesh); @@ -188,14 +188,14 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address Mesh *mesh = (Mesh *)id; const bool is_undo = BLO_write_is_undo(writer); - CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *flayers = NULL, flayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; - CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *vlayers = nullptr, vlayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *elayers = nullptr, elayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *flayers = nullptr, flayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *llayers = nullptr, llayers_buff[CD_TEMP_CHUNK_SIZE]; + CustomDataLayer *players = nullptr, players_buff[CD_TEMP_CHUNK_SIZE]; /* cache only - don't write */ - mesh->mface = NULL; + mesh->mface = nullptr; mesh->totface = 0; memset(&mesh->fdata, 0, sizeof(mesh->fdata)); memset(&mesh->runtime, 0, sizeof(mesh->runtime)); @@ -203,22 +203,22 @@ static void mesh_blend_write(BlendWriter *writer, ID *id, const void *id_address /* Do not store actual geometry data in case this is a library override ID. */ if (ID_IS_OVERRIDE_LIBRARY(mesh) && !is_undo) { - mesh->mvert = NULL; + mesh->mvert = nullptr; mesh->totvert = 0; memset(&mesh->vdata, 0, sizeof(mesh->vdata)); vlayers = vlayers_buff; - mesh->medge = NULL; + mesh->medge = nullptr; mesh->totedge = 0; memset(&mesh->edata, 0, sizeof(mesh->edata)); elayers = elayers_buff; - mesh->mloop = NULL; + mesh->mloop = nullptr; mesh->totloop = 0; memset(&mesh->ldata, 0, sizeof(mesh->ldata)); llayers = llayers_buff; - mesh->mpoly = NULL; + mesh->mpoly = nullptr; mesh->totpoly = 0; memset(&mesh->pdata, 0, sizeof(mesh->pdata)); players = players_buff; @@ -307,13 +307,13 @@ static void mesh_blend_read_data(BlendDataReader *reader, ID *id) CustomData_blend_read(reader, &mesh->pdata, mesh->totpoly); mesh->texflag &= ~ME_AUTOSPACE_EVALUATED; - mesh->edit_mesh = NULL; + mesh->edit_mesh = nullptr; memset(&mesh->runtime, 0, sizeof(mesh->runtime)); BKE_mesh_runtime_init_data(mesh); /* happens with old files */ - if (mesh->mselect == NULL) { + if (mesh->mselect == nullptr) { mesh->totselect = 0; } @@ -355,31 +355,28 @@ static void mesh_read_expand(BlendExpander *expander, ID *id) } IDTypeInfo IDType_ID_ME = { - .id_code = ID_ME, - .id_filter = FILTER_ID_ME, - .main_listbase_index = INDEX_ID_ME, - .struct_size = sizeof(Mesh), - .name = "Mesh", - .name_plural = "meshes", - .translation_context = BLT_I18NCONTEXT_ID_MESH, - .flags = IDTYPE_FLAGS_APPEND_IS_REUSABLE, - - .init_data = mesh_init_data, - .copy_data = mesh_copy_data, - .free_data = mesh_free_data, - .make_local = NULL, - .foreach_id = mesh_foreach_id, - .foreach_cache = NULL, - .owner_get = NULL, - - .blend_write = mesh_blend_write, - .blend_read_data = mesh_blend_read_data, - .blend_read_lib = mesh_blend_read_lib, - .blend_read_expand = mesh_read_expand, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, + ID_ME, + FILTER_ID_ME, + INDEX_ID_ME, + sizeof(Mesh), + "Mesh", + "meshes", + BLT_I18NCONTEXT_ID_MESH, + IDTYPE_FLAGS_APPEND_IS_REUSABLE, + + mesh_init_data, + mesh_copy_data, + mesh_free_data, + nullptr, + mesh_foreach_id, + nullptr, + nullptr, + mesh_blend_write, + mesh_blend_read_data, + mesh_blend_read_lib, + mesh_read_expand, + nullptr, + nullptr, }; enum { @@ -471,8 +468,8 @@ static int customdata_compare( switch (l1->type) { case CD_MVERT: { - MVert *v1 = l1->data; - MVert *v2 = l2->data; + MVert *v1 = (MVert *)l1->data; + MVert *v2 = (MVert *)l2->data; int vtot = m1->totvert; for (j = 0; j < vtot; j++, v1++, v2++) { @@ -488,8 +485,8 @@ static int customdata_compare( /* We're order-agnostic for edges here. */ case CD_MEDGE: { - MEdge *e1 = l1->data; - MEdge *e2 = l2->data; + MEdge *e1 = (MEdge *)l1->data; + MEdge *e2 = (MEdge *)l2->data; int etot = m1->totedge; EdgeHash *eh = BLI_edgehash_new_ex(__func__, etot); @@ -502,12 +499,12 @@ static int customdata_compare( return MESHCMP_EDGEUNKNOWN; } } - BLI_edgehash_free(eh, NULL); + BLI_edgehash_free(eh, nullptr); break; } case CD_MPOLY: { - MPoly *p1 = l1->data; - MPoly *p2 = l2->data; + MPoly *p1 = (MPoly *)l1->data; + MPoly *p2 = (MPoly *)l2->data; int ptot = m1->totpoly; for (j = 0; j < ptot; j++, p1++, p2++) { @@ -530,8 +527,8 @@ static int customdata_compare( break; } case CD_MLOOP: { - MLoop *lp1 = l1->data; - MLoop *lp2 = l2->data; + MLoop *lp1 = (MLoop *)l1->data; + MLoop *lp2 = (MLoop *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -542,8 +539,8 @@ static int customdata_compare( break; } case CD_MLOOPUV: { - MLoopUV *lp1 = l1->data; - MLoopUV *lp2 = l2->data; + MLoopUV *lp1 = (MLoopUV *)l1->data; + MLoopUV *lp2 = (MLoopUV *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -554,8 +551,8 @@ static int customdata_compare( break; } case CD_MLOOPCOL: { - MLoopCol *lp1 = l1->data; - MLoopCol *lp2 = l2->data; + MLoopCol *lp1 = (MLoopCol *)l1->data; + MLoopCol *lp2 = (MLoopCol *)l2->data; int ltot = m1->totloop; for (j = 0; j < ltot; j++, lp1++, lp2++) { @@ -566,8 +563,8 @@ static int customdata_compare( break; } case CD_MDEFORMVERT: { - MDeformVert *dv1 = l1->data; - MDeformVert *dv2 = l2->data; + MDeformVert *dv1 = (MDeformVert *)l1->data; + MDeformVert *dv2 = (MDeformVert *)l2->data; int dvtot = m1->totvert; for (j = 0; j < dvtot; j++, dv1++, dv2++) { @@ -590,8 +587,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT: { - const float *l1_data = l1->data; - const float *l2_data = l2->data; + const float *l1_data = (float *)l1->data; + const float *l2_data = (float *)l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i], l2_data[i], thresh)) { @@ -601,8 +598,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT2: { - const float(*l1_data)[2] = l1->data; - const float(*l2_data)[2] = l2->data; + const float(*l1_data)[2] = (float(*)[2])l1->data; + const float(*l2_data)[2] = (float(*)[2])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -615,8 +612,8 @@ static int customdata_compare( break; } case CD_PROP_FLOAT3: { - const float(*l1_data)[3] = l1->data; - const float(*l2_data)[3] = l2->data; + const float(*l1_data)[3] = (float(*)[3])l1->data; + const float(*l2_data)[3] = (float(*)[3])l2->data; for (int i = 0; i < total_length; i++) { if (compare_threshold_relative(l1_data[i][0], l2_data[i][0], thresh)) { @@ -632,8 +629,8 @@ static int customdata_compare( break; } case CD_PROP_INT32: { - const int *l1_data = l1->data; - const int *l2_data = l2->data; + const int *l1_data = (int *)l1->data; + const int *l2_data = (int *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -643,8 +640,8 @@ static int customdata_compare( break; } case CD_PROP_BOOL: { - const bool *l1_data = l1->data; - const bool *l2_data = l2->data; + const bool *l1_data = (bool *)l1->data; + const bool *l2_data = (bool *)l2->data; for (int i = 0; i < total_length; i++) { if (l1_data[i] != l2_data[i]) { @@ -654,8 +651,8 @@ static int customdata_compare( break; } case CD_PROP_COLOR: { - const MPropCol *l1_data = l1->data; - const MPropCol *l2_data = l2->data; + const MPropCol *l1_data = (MPropCol *)l1->data; + const MPropCol *l2_data = (MPropCol *)l2->data; for (int i = 0; i < total_length; i++) { for (j = 0; j < 4; j++) { @@ -722,7 +719,7 @@ const char *BKE_mesh_cmp(Mesh *me1, Mesh *me2, float thresh) return cmpcode_to_str(c); } - return NULL; + return nullptr; } static void mesh_ensure_tessellation_customdata(Mesh *me) @@ -767,7 +764,7 @@ static void mesh_ensure_tessellation_customdata(Mesh *me) void BKE_mesh_ensure_skin_customdata(Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; MVertSkin *vs; if (bm) { @@ -779,7 +776,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) /* Mark an arbitrary vertex as root */ BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - vs = CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); + vs = (MVertSkin *)CustomData_bmesh_get(&bm->vdata, v->head.data, CD_MVERT_SKIN); vs->flag |= MVERT_SKIN_ROOT; break; } @@ -787,7 +784,8 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) } else { if (!CustomData_has_layer(&me->vdata, CD_MVERT_SKIN)) { - vs = CustomData_add_layer(&me->vdata, CD_MVERT_SKIN, CD_DEFAULT, NULL, me->totvert); + vs = (MVertSkin *)CustomData_add_layer( + &me->vdata, CD_MVERT_SKIN, CD_DEFAULT, nullptr, me->totvert); /* Mark an arbitrary vertex as root */ if (vs) { @@ -799,7 +797,7 @@ void BKE_mesh_ensure_skin_customdata(Mesh *me) bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (!CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -809,7 +807,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) } else { if (!CustomData_has_layer(&me->pdata, CD_FACEMAP)) { - CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, NULL, me->totpoly); + CustomData_add_layer(&me->pdata, CD_FACEMAP, CD_DEFAULT, nullptr, me->totpoly); changed = true; } } @@ -818,7 +816,7 @@ bool BKE_mesh_ensure_facemap_customdata(struct Mesh *me) bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) { - BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : NULL; + BMesh *bm = me->edit_mesh ? me->edit_mesh->bm : nullptr; bool changed = false; if (bm) { if (CustomData_has_layer(&bm->pdata, CD_FACEMAP)) { @@ -836,12 +834,12 @@ bool BKE_mesh_clear_facemap_customdata(struct Mesh *me) } /** - * This ensures grouped customdata (e.g. mtexpoly and mloopuv and mtface, or - * mloopcol and mcol) have the same relative active/render/clone/mask indices. + * This ensures grouped custom-data (e.g. #CD_MLOOPUV and #CD_MTFACE, or + * #CD_MLOOPCOL and #CD_MCOL) have the same relative active/render/clone/mask indices. * - * NOTE(campbell): that for undo mesh data we want to skip 'ensure_tess_cd' call since - * we don't want to store memory for tessface when its only used for older - * Versions of the mesh. + * NOTE(@campbellbarton): that for undo mesh data we want to skip 'ensure_tess_cd' call since + * we don't want to store memory for #MFace data when its only used for older + * versions of the mesh. */ static void mesh_update_linked_customdata(Mesh *me, const bool do_ensure_tess_cd) { @@ -856,20 +854,20 @@ void BKE_mesh_update_customdata_pointers(Mesh *me, const bool do_ensure_tess_cd) { mesh_update_linked_customdata(me, do_ensure_tess_cd); - me->mvert = CustomData_get_layer(&me->vdata, CD_MVERT); - me->dvert = CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); + me->mvert = (MVert *)CustomData_get_layer(&me->vdata, CD_MVERT); + me->dvert = (MDeformVert *)CustomData_get_layer(&me->vdata, CD_MDEFORMVERT); - me->medge = CustomData_get_layer(&me->edata, CD_MEDGE); + me->medge = (MEdge *)CustomData_get_layer(&me->edata, CD_MEDGE); - me->mface = CustomData_get_layer(&me->fdata, CD_MFACE); - me->mcol = CustomData_get_layer(&me->fdata, CD_MCOL); - me->mtface = CustomData_get_layer(&me->fdata, CD_MTFACE); + me->mface = (MFace *)CustomData_get_layer(&me->fdata, CD_MFACE); + me->mcol = (MCol *)CustomData_get_layer(&me->fdata, CD_MCOL); + me->mtface = (MTFace *)CustomData_get_layer(&me->fdata, CD_MTFACE); - me->mpoly = CustomData_get_layer(&me->pdata, CD_MPOLY); - me->mloop = CustomData_get_layer(&me->ldata, CD_MLOOP); + me->mpoly = (MPoly *)CustomData_get_layer(&me->pdata, CD_MPOLY); + me->mloop = (MLoop *)CustomData_get_layer(&me->ldata, CD_MLOOP); - me->mloopcol = CustomData_get_layer(&me->ldata, CD_MLOOPCOL); - me->mloopuv = CustomData_get_layer(&me->ldata, CD_MLOOPUV); + me->mloopcol = (MLoopCol *)CustomData_get_layer(&me->ldata, CD_MLOOPCOL); + me->mloopuv = (MLoopUV *)CustomData_get_layer(&me->ldata, CD_MLOOPUV); } bool BKE_mesh_has_custom_loop_normals(Mesh *me) @@ -883,7 +881,7 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) /** * Free (or release) any data used by this mesh (does not free the mesh itself). - * Only use for undo, in most cases `BKE_id_free(NULL, me)` should be used. + * Only use for undo, in most cases `BKE_id_free(nullptr, me)` should be used. */ void BKE_mesh_free_data_for_undo(Mesh *me) { @@ -939,15 +937,15 @@ static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) CustomData_reset(&mesh->fdata); } - mesh->mface = NULL; - mesh->mtface = NULL; - mesh->mcol = NULL; + mesh->mface = nullptr; + mesh->mtface = nullptr; + mesh->mcol = nullptr; mesh->totface = 0; } Mesh *BKE_mesh_add(Main *bmain, const char *name) { - Mesh *me = BKE_id_new(bmain, ID_ME, name); + Mesh *me = (Mesh *)BKE_id_new(bmain, ID_ME, name); return me; } @@ -956,28 +954,28 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) static void mesh_ensure_cdlayers_primary(Mesh *mesh, bool do_tessface) { if (!CustomData_get_layer(&mesh->vdata, CD_MVERT)) { - CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, NULL, mesh->totvert); + CustomData_add_layer(&mesh->vdata, CD_MVERT, CD_CALLOC, nullptr, mesh->totvert); } if (!CustomData_get_layer(&mesh->edata, CD_MEDGE)) { - CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, NULL, mesh->totedge); + CustomData_add_layer(&mesh->edata, CD_MEDGE, CD_CALLOC, nullptr, mesh->totedge); } if (!CustomData_get_layer(&mesh->ldata, CD_MLOOP)) { - CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, NULL, mesh->totloop); + CustomData_add_layer(&mesh->ldata, CD_MLOOP, CD_CALLOC, nullptr, mesh->totloop); } if (!CustomData_get_layer(&mesh->pdata, CD_MPOLY)) { - CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, NULL, mesh->totpoly); + CustomData_add_layer(&mesh->pdata, CD_MPOLY, CD_CALLOC, nullptr, mesh->totpoly); } if (do_tessface && !CustomData_get_layer(&mesh->fdata, CD_MFACE)) { - CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, NULL, mesh->totface); + CustomData_add_layer(&mesh->fdata, CD_MFACE, CD_CALLOC, nullptr, mesh->totface); } } Mesh *BKE_mesh_new_nomain( int verts_len, int edges_len, int tessface_len, int loops_len, int polys_len) { - Mesh *mesh = BKE_libblock_alloc( - NULL, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); + Mesh *mesh = (Mesh *)BKE_libblock_alloc( + nullptr, ID_ME, BKE_idtype_idcode_to_name(ID_ME), LIB_ID_CREATE_LOCALIZE); BKE_libblock_init_empty(&mesh->id); /* Don't use #CustomData_reset because we don't want to touch custom-data. */ @@ -1043,10 +1041,10 @@ void BKE_mesh_copy_parameters_for_eval(Mesh *me_dst, const Mesh *me_src) BKE_defgroup_copy_list(&me_dst->vertex_group_names, &me_src->vertex_group_names); /* Copy materials. */ - if (me_dst->mat != NULL) { + if (me_dst->mat != nullptr) { MEM_freeN(me_dst->mat); } - me_dst->mat = MEM_dupallocN(me_src->mat); + me_dst->mat = (Material **)MEM_dupallocN(me_src->mat); me_dst->totcol = me_src->totcol; } @@ -1061,9 +1059,9 @@ Mesh *BKE_mesh_new_nomain_from_template_ex(const Mesh *me_src, /* Only do tessface if we are creating tessfaces or copying from mesh with only tessfaces. */ const bool do_tessface = (tessface_len || ((me_src->totface != 0) && (me_src->totpoly == 0))); - Mesh *me_dst = BKE_id_new_nomain(ID_ME, NULL); + Mesh *me_dst = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - me_dst->mselect = MEM_dupallocN(me_src->mselect); + me_dst->mselect = (MSelect *)MEM_dupallocN(me_src->mselect); me_dst->totvert = verts_len; me_dst->totedge = edges_len; @@ -1107,7 +1105,7 @@ Mesh *BKE_mesh_new_nomain_from_template(const Mesh *me_src, void BKE_mesh_eval_delete(struct Mesh *mesh_eval) { /* Evaluated mesh may point to edit mesh, but never owns it. */ - mesh_eval->edit_mesh = NULL; + mesh_eval->edit_mesh = nullptr; mesh_free_data(&mesh_eval->id); BKE_libblock_free_data(&mesh_eval->id, false); MEM_freeN(mesh_eval); @@ -1121,7 +1119,7 @@ Mesh *BKE_mesh_copy_for_eval(const Mesh *source, bool reference) flags |= LIB_ID_COPY_CD_REFERENCE; } - Mesh *result = (Mesh *)BKE_id_copy_ex(NULL, &source->id, NULL, flags); + Mesh *result = (Mesh *)BKE_id_copy_ex(nullptr, &source->id, nullptr, flags); return result; } @@ -1142,14 +1140,12 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, const bool add_key_index, const struct BMeshCreateParams *params) { - return BKE_mesh_to_bmesh_ex(me, - params, - &(struct BMeshFromMeshParams){ - .calc_face_normal = false, - .add_key_index = add_key_index, - .use_shapekey = true, - .active_shapekey = ob->shapenr, - }); + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = false; + bmesh_from_mesh_params.add_key_index = add_key_index; + bmesh_from_mesh_params.use_shapekey = true; + bmesh_from_mesh_params.active_shapekey = ob->shapenr; + return BKE_mesh_to_bmesh_ex(me, params, &bmesh_from_mesh_params); } Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, @@ -1157,8 +1153,8 @@ Mesh *BKE_mesh_from_bmesh_nomain(BMesh *bm, const Mesh *me_settings) { BLI_assert(params->calc_object_remap == false); - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); - BM_mesh_bm_to_me(NULL, bm, mesh, params); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, params); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; } @@ -1167,7 +1163,7 @@ Mesh *BKE_mesh_from_bmesh_for_eval_nomain(BMesh *bm, const CustomData_MeshMasks *cd_mask_extra, const Mesh *me_settings) { - Mesh *mesh = BKE_id_new_nomain(ID_ME, NULL); + Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); BM_mesh_bm_to_me_for_eval(bm, mesh, cd_mask_extra); BKE_mesh_copy_parameters_for_eval(mesh, me_settings); return mesh; @@ -1177,8 +1173,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) { /* This is Object-level data access, * DO NOT touch to Mesh's bb, would be totally thread-unsafe. */ - if (ob->runtime.bb == NULL || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { - Mesh *me = ob->data; + if (ob->runtime.bb == nullptr || ob->runtime.bb->flag & BOUNDBOX_DIRTY) { + Mesh *me = (Mesh *)ob->data; float min[3], max[3]; INIT_MINMAX(min, max); @@ -1187,8 +1183,8 @@ BoundBox *BKE_mesh_boundbox_get(Object *ob) max[0] = max[1] = max[2] = 1.0f; } - if (ob->runtime.bb == NULL) { - ob->runtime.bb = MEM_mallocN(sizeof(*ob->runtime.bb), __func__); + if (ob->runtime.bb == nullptr) { + ob->runtime.bb = (BoundBox *)MEM_mallocN(sizeof(*ob->runtime.bb), __func__); } BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; @@ -1257,13 +1253,13 @@ void BKE_mesh_texspace_get_reference(Mesh *me, short **r_texflag, float **r_loc, { BKE_mesh_texspace_ensure(me); - if (r_texflag != NULL) { + if (r_texflag != nullptr) { *r_texflag = &me->texflag; } - if (r_loc != NULL) { + if (r_loc != nullptr) { *r_loc = me->loc; } - if (r_size != NULL) { + if (r_size != nullptr) { *r_size = me->size; } } @@ -1282,11 +1278,11 @@ void BKE_mesh_texspace_copy_from_object(Mesh *me, Object *ob) float (*BKE_mesh_orco_verts_get(Object *ob))[3] { - Mesh *me = ob->data; + Mesh *me = (Mesh *)ob->data; Mesh *tme = me->texcomesh ? me->texcomesh : me; /* Get appropriate vertex coordinates */ - float(*vcos)[3] = MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); + float(*vcos)[3] = (float(*)[3])MEM_calloc_arrayN(me->totvert, sizeof(*vcos), "orco mesh"); MVert *mvert = tme->mvert; int totvert = min_ii(tme->totvert, me->totvert); @@ -1393,28 +1389,28 @@ int BKE_mesh_mface_index_validate(MFace *mface, CustomData *fdata, int mfindex, Mesh *BKE_mesh_from_object(Object *ob) { - if (ob == NULL) { - return NULL; + if (ob == nullptr) { + return nullptr; } if (ob->type == OB_MESH) { - return ob->data; + return (Mesh *)ob->data; } - return NULL; + return nullptr; } void BKE_mesh_assign_object(Main *bmain, Object *ob, Mesh *me) { - Mesh *old = NULL; + Mesh *old = nullptr; - if (ob == NULL) { + if (ob == nullptr) { return; } multires_force_sculpt_rebuild(ob); if (ob->type == OB_MESH) { - old = ob->data; + old = (Mesh *)ob->data; if (old) { id_us_min(&old->id); } @@ -1605,8 +1601,9 @@ bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) { int i; - MVert *mvert = CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); - float(*lnors)[3] = CustomData_duplicate_referenced_layer(&me->ldata, CD_NORMAL, me->totloop); + MVert *mvert = (MVert *)CustomData_duplicate_referenced_layer(&me->vdata, CD_MVERT, me->totvert); + float(*lnors)[3] = (float(*)[3])CustomData_duplicate_referenced_layer( + &me->ldata, CD_NORMAL, me->totloop); /* If the referenced layer has been re-allocated need to update pointers stored in the mesh. */ BKE_mesh_update_customdata_pointers(me, false); @@ -1616,9 +1613,8 @@ void BKE_mesh_transform(Mesh *me, const float mat[4][4], bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { mul_m4_v3(mat, fp); } @@ -1651,9 +1647,8 @@ void BKE_mesh_translate(Mesh *me, const float offset[3], const bool do_keys) } if (do_keys && me->key) { - KeyBlock *kb; - for (kb = me->key->block.first; kb; kb = kb->next) { - float *fp = kb->data; + LISTBASE_FOREACH (KeyBlock *, kb, &me->key->block) { + float *fp = (float *)kb->data; for (i = kb->totelem; i--; fp += 3) { add_v3_v3(fp, offset); } @@ -1725,7 +1720,8 @@ void BKE_mesh_mselect_validate(Mesh *me) } mselect_src = me->mselect; - mselect_dst = MEM_malloc_arrayN((me->totselect), sizeof(MSelect), "Mesh selection history"); + mselect_dst = (MSelect *)MEM_malloc_arrayN( + (me->totselect), sizeof(MSelect), "Mesh selection history"); for (i_src = 0, i_dst = 0; i_src < me->totselect; i_src++) { int index = mselect_src[i_src].index; @@ -1762,10 +1758,10 @@ void BKE_mesh_mselect_validate(Mesh *me) if (i_dst == 0) { MEM_freeN(mselect_dst); - mselect_dst = NULL; + mselect_dst = nullptr; } else if (i_dst != me->totselect) { - mselect_dst = MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); + mselect_dst = (MSelect *)MEM_reallocN(mselect_dst, sizeof(MSelect) * i_dst); } me->totselect = i_dst; @@ -1809,7 +1805,7 @@ void BKE_mesh_mselect_active_set(Mesh *me, int index, int type) if (msel_index == -1) { /* add to the end */ - me->mselect = MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); + me->mselect = (MSelect *)MEM_reallocN(me->mselect, sizeof(MSelect) * (me->totselect + 1)); me->mselect[me->totselect].index = index; me->mselect[me->totselect].type = type; me->totselect++; @@ -1845,7 +1841,7 @@ void BKE_mesh_vert_coords_get(const Mesh *mesh, float (*vert_coords)[3]) float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] { - float(*vert_coords)[3] = MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); + float(*vert_coords)[3] = (float(*)[3])MEM_mallocN(sizeof(float[3]) * mesh->totvert, __func__); BKE_mesh_vert_coords_get(mesh, vert_coords); if (r_vert_len) { *r_vert_len = mesh->totvert; @@ -1856,7 +1852,8 @@ float (*BKE_mesh_vert_coords_alloc(const Mesh *mesh, int *r_vert_len))[3] void BKE_mesh_vert_coords_apply(Mesh *mesh, const float (*vert_coords)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3(mv->co, vert_coords[i]); @@ -1869,7 +1866,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, const float mat[4][4]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { mul_v3_m4v3(mv->co, mat, vert_coords[i]); @@ -1880,7 +1878,8 @@ void BKE_mesh_vert_coords_apply_with_mat4(Mesh *mesh, void BKE_mesh_vert_normals_apply(Mesh *mesh, const short (*vert_normals)[3]) { /* This will just return the pointer if it wasn't a referenced layer. */ - MVert *mv = CustomData_duplicate_referenced_layer(&mesh->vdata, CD_MVERT, mesh->totvert); + MVert *mv = (MVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MVERT, mesh->totvert); mesh->mvert = mv; for (int i = 0; i < mesh->totvert; i++, mv++) { copy_v3_v3_short(mv->no, vert_normals[i]); @@ -1899,35 +1898,37 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac { float(*r_loopnors)[3]; float(*polynors)[3]; - short(*clnors)[2] = NULL; + short(*clnors)[2] = nullptr; bool free_polynors = false; /* Note that we enforce computing clnors when the clnor space array is requested by caller here. - * However, we obviously only use the autosmooth angle threshold - * only in case autosmooth is enabled. */ - const bool use_split_normals = (r_lnors_spacearr != NULL) || ((mesh->flag & ME_AUTOSMOOTH) != 0); + * However, we obviously only use the auto-smooth angle threshold + * only in case auto-smooth is enabled. */ + const bool use_split_normals = (r_lnors_spacearr != nullptr) || + ((mesh->flag & ME_AUTOSMOOTH) != 0); const float split_angle = (mesh->flag & ME_AUTOSMOOTH) != 0 ? mesh->smoothresh : (float)M_PI; if (CustomData_has_layer(&mesh->ldata, CD_NORMAL)) { - r_loopnors = CustomData_get_layer(&mesh->ldata, CD_NORMAL); + r_loopnors = (float(*)[3])CustomData_get_layer(&mesh->ldata, CD_NORMAL); memset(r_loopnors, 0, sizeof(float[3]) * mesh->totloop); } else { - r_loopnors = CustomData_add_layer(&mesh->ldata, CD_NORMAL, CD_CALLOC, NULL, mesh->totloop); + r_loopnors = (float(*)[3])CustomData_add_layer( + &mesh->ldata, CD_NORMAL, CD_CALLOC, nullptr, mesh->totloop); CustomData_set_layer_flag(&mesh->ldata, CD_NORMAL, CD_FLAG_TEMPORARY); } - /* may be NULL */ - clnors = CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); + /* may be nullptr */ + clnors = (short(*)[2])CustomData_get_layer(&mesh->ldata, CD_CUSTOMLOOPNORMAL); if (CustomData_has_layer(&mesh->pdata, CD_NORMAL)) { /* This assume that layer is always up to date, not sure this is the case * (esp. in Edit mode?)... */ - polynors = CustomData_get_layer(&mesh->pdata, CD_NORMAL); + polynors = (float(*)[3])CustomData_get_layer(&mesh->pdata, CD_NORMAL); free_polynors = false; } else { - polynors = MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); + polynors = (float(*)[3])MEM_malloc_arrayN(mesh->totpoly, sizeof(float[3]), __func__); BKE_mesh_calc_normals_poly_and_vertex(mesh->mvert, mesh->totvert, mesh->mloop, @@ -1935,7 +1936,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac mesh->mpoly, mesh->totpoly, polynors, - NULL); + nullptr); free_polynors = true; } @@ -1953,7 +1954,7 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac split_angle, r_lnors_spacearr, clnors, - NULL); + nullptr); if (free_polynors) { MEM_freeN(polynors); @@ -1966,25 +1967,25 @@ void BKE_mesh_calc_normals_split_ex(Mesh *mesh, MLoopNorSpaceArray *r_lnors_spac void BKE_mesh_calc_normals_split(Mesh *mesh) { - BKE_mesh_calc_normals_split_ex(mesh, NULL); + BKE_mesh_calc_normals_split_ex(mesh, nullptr); } /* Split faces helper functions. */ -typedef struct SplitFaceNewVert { +struct SplitFaceNewVert { struct SplitFaceNewVert *next; int new_index; int orig_index; float *vnor; -} SplitFaceNewVert; +}; -typedef struct SplitFaceNewEdge { +struct SplitFaceNewEdge { struct SplitFaceNewEdge *next; int new_index; int orig_index; int v1; int v2; -} SplitFaceNewEdge; +}; /* Detect needed new vertices, and update accordingly loops' vertex indices. * WARNING! Leaves mesh in invalid state. */ @@ -1996,7 +1997,7 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, /* This is now mandatory, trying to do the job in simple way without that data is doomed to fail, * even when only dealing with smooth/flat faces one can find cases that no simple algorithm * can handle properly. */ - BLI_assert(lnors_spacearr != NULL); + BLI_assert(lnors_spacearr != nullptr); const int loops_len = mesh->totloop; int verts_len = mesh->totvert; @@ -2049,7 +2050,8 @@ static int split_faces_prepare_new_verts(const Mesh *mesh, } else { /* Add new vert to list. */ - SplitFaceNewVert *new_vert = BLI_memarena_alloc(memarena, sizeof(*new_vert)); + SplitFaceNewVert *new_vert = (SplitFaceNewVert *)BLI_memarena_alloc(memarena, + sizeof(*new_vert)); new_vert->orig_index = vert_idx; new_vert->new_index = new_vert_idx; new_vert->vnor = (*lnor_space)->vec_lnor; /* See note above. */ @@ -2096,7 +2098,8 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, *eval = POINTER_FROM_INT(new_edge_idx); ml_prev->e = new_edge_idx; - SplitFaceNewEdge *new_edge = BLI_memarena_alloc(memarena, sizeof(*new_edge)); + SplitFaceNewEdge *new_edge = (SplitFaceNewEdge *)BLI_memarena_alloc(memarena, + sizeof(*new_edge)); new_edge->orig_index = edge_idx; new_edge->new_index = new_edge_idx; new_edge->v1 = ml_prev->v; @@ -2122,7 +2125,7 @@ static int split_faces_prepare_new_edges(const Mesh *mesh, } MEM_freeN(edges_used); - BLI_edgehash_free(edges_hash, NULL); + BLI_edgehash_free(edges_hash, nullptr); return num_edges - mesh->totedge; } @@ -2181,14 +2184,14 @@ void BKE_mesh_split_faces(Mesh *mesh, bool free_loop_normals) } BKE_mesh_tessface_clear(mesh); - MLoopNorSpaceArray lnors_spacearr = {NULL}; + MLoopNorSpaceArray lnors_spacearr = {nullptr}; /* Compute loop normals and loop normal spaces (a.k.a. smooth fans of faces around vertices). */ BKE_mesh_calc_normals_split_ex(mesh, &lnors_spacearr); /* Stealing memarena from loop normals space array. */ MemArena *memarena = lnors_spacearr.mem; - SplitFaceNewVert *new_verts = NULL; - SplitFaceNewEdge *new_edges = NULL; + SplitFaceNewVert *new_verts = nullptr; + SplitFaceNewEdge *new_edges = nullptr; /* Ensure we own the layers, we need to do this before split_faces_prepare_new_verts as it will * directly assign new indices to existing edges and loops. */ @@ -2252,10 +2255,10 @@ void BKE_mesh_eval_geometry(Depsgraph *depsgraph, Mesh *mesh) /* We are here because something did change in the mesh. This means we can not trust the existing * evaluated mesh, and we don't know what parts of the mesh did change. So we simply delete the * evaluated mesh and let objects to re-create it with updated settings. */ - if (mesh->runtime.mesh_eval != NULL) { - mesh->runtime.mesh_eval->edit_mesh = NULL; - BKE_id_free(NULL, mesh->runtime.mesh_eval); - mesh->runtime.mesh_eval = NULL; + if (mesh->runtime.mesh_eval != nullptr) { + mesh->runtime.mesh_eval->edit_mesh = nullptr; + BKE_id_free(nullptr, mesh->runtime.mesh_eval); + mesh->runtime.mesh_eval = nullptr; } if (DEG_is_active(depsgraph)) { Mesh *mesh_orig = (Mesh *)DEG_get_original_id(&mesh->id); diff --git a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc index 9f5703a015d..3447185089d 100644 --- a/source/blender/blenkernel/intern/mesh_remesh_voxel.cc +++ b/source/blender/blenkernel/intern/mesh_remesh_voxel.cc @@ -410,7 +410,8 @@ struct Mesh *BKE_mesh_remesh_voxel_fix_poles(const Mesh *mesh) { const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh); - const BMeshCreateParams bmesh_create_params = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); BMeshFromMeshParams bmesh_from_mesh_params{}; diff --git a/source/blender/blenkernel/intern/mesh_runtime.c b/source/blender/blenkernel/intern/mesh_runtime.c index ce89c723a61..7b1d5140421 100644 --- a/source/blender/blenkernel/intern/mesh_runtime.c +++ b/source/blender/blenkernel/intern/mesh_runtime.c @@ -113,7 +113,7 @@ void BKE_mesh_runtime_reset_on_copy(Mesh *mesh, const int UNUSED(flag)) /** * \brief This function clears runtime cache of the given mesh. - * + * * Call this function to recalculate runtime data when used. */ void BKE_mesh_runtime_clear_cache(Mesh *mesh) diff --git a/source/blender/blenkernel/intern/mesh_sample.cc b/source/blender/blenkernel/intern/mesh_sample.cc index 2274d34f0f1..a046cc68bf2 100644 --- a/source/blender/blenkernel/intern/mesh_sample.cc +++ b/source/blender/blenkernel/intern/mesh_sample.cc @@ -269,7 +269,7 @@ void MeshAttributeInterpolator::sample_attribute(const ReadAttributeLookup &src_ eAttributeMapMode mode) { if (src_attribute && dst_attribute) { - this->sample_data(*src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); + this->sample_data(src_attribute.varray, src_attribute.domain, mode, dst_attribute.as_span()); } } diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index ef84afd8668..124db07298d 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -491,11 +491,11 @@ void BKE_nla_strip_foreach_id(NlaStrip *strip, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, strip->act, IDWALK_CB_USER); LISTBASE_FOREACH (FCurve *, fcu, &strip->fcurves) { - BKE_fcurve_foreach_id(fcu, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data)); } LISTBASE_FOREACH (NlaStrip *, substrip, &strip->strips) { - BKE_nla_strip_foreach_id(substrip, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_nla_strip_foreach_id(substrip, data)); } } diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index ab3132a5d58..e02ea3f7e37 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -66,6 +66,7 @@ #include "BKE_colortools.h" #include "BKE_cryptomatte.h" #include "BKE_global.h" +#include "BKE_icons.h" #include "BKE_idprop.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" @@ -129,10 +130,6 @@ static void node_socket_interface_free(bNodeTree *UNUSED(ntree), static void nodeMuteRerouteOutputLinks(struct bNodeTree *ntree, struct bNode *node, const bool mute); -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface); -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface); static void ntree_init_data(ID *id) { @@ -245,9 +242,16 @@ static void ntree_copy_data(Main *UNUSED(bmain), ID *id_dst, const ID *id_src, c ntree_dst->interface_type = nullptr; if (ntree_src->field_inferencing_interface) { - ntree_dst->field_inferencing_interface = node_field_inferencing_interface_copy( + ntree_dst->field_inferencing_interface = new FieldInferencingInterface( *ntree_src->field_inferencing_interface); } + + if (flag & LIB_ID_COPY_NO_PREVIEW) { + ntree_dst->preview = nullptr; + } + else { + BKE_previewimg_id_copy(&ntree_dst->id, &ntree_src->id); + } } static void ntree_free_data(ID *id) @@ -293,7 +297,7 @@ static void ntree_free_data(ID *id) MEM_freeN(sock); } - node_field_inferencing_interface_free(ntree->field_inferencing_interface); + delete ntree->field_inferencing_interface; /* free preview hash */ if (ntree->previews) { @@ -303,12 +307,16 @@ static void ntree_free_data(ID *id) if (ntree->id.tag & LIB_TAG_LOCALIZED) { BKE_libblock_free_data(&ntree->id, true); } + + BKE_previewimg_free(&ntree->preview); } static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket *sock) { - IDP_foreach_property( - sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property( + sock->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data)); switch ((eNodeSocketDatatype)sock->type) { case SOCK_OBJECT: { @@ -360,21 +368,25 @@ static void node_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { BKE_LIB_FOREACHID_PROCESS_ID(data, node->id, IDWALK_CB_USER); - IDP_foreach_property( - node->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(node->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &node->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->inputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { - library_foreach_node_socket(data, sock); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, library_foreach_node_socket(data, sock)); } } @@ -635,6 +647,8 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) LISTBASE_FOREACH (bNodeSocket *, sock, &ntree->outputs) { write_node_socket_interface(writer, sock); } + + BKE_previewimg_blend_write(writer, ntree->preview); } static void ntree_blend_write(BlendWriter *writer, ID *id, const void *id_address) @@ -665,6 +679,7 @@ static void direct_link_node_socket(BlendDataReader *reader, bNodeSocket *sock) BLO_read_data_address(reader, &sock->default_value); sock->total_inputs = 0; /* Clear runtime data set before drawing. */ sock->cache = nullptr; + sock->declaration = nullptr; } /* ntree itself has been read! */ @@ -828,6 +843,9 @@ void ntreeBlendReadData(BlendDataReader *reader, bNodeTree *ntree) ntree->update |= NTREE_UPDATE_FIELD_INFERENCING; } + BLO_read_data_address(reader, &ntree->preview); + BKE_previewimg_blend_read(reader, ntree->preview); + /* type verification is in lib-link */ } @@ -1051,8 +1069,7 @@ IDTypeInfo IDType_ID_NT = { static void node_add_sockets_from_type(bNodeTree *ntree, bNode *node, bNodeType *ntype) { if (ntype->declare != nullptr) { - nodeDeclarationEnsure(ntree, node); - node->declaration->build(*ntree, *node); + node_verify_sockets(ntree, node, true); return; } bNodeSocketTemplate *sockdef; @@ -1141,15 +1158,15 @@ static void ntree_set_typeinfo(bNodeTree *ntree, bNodeTreeType *typeinfo) { if (typeinfo) { ntree->typeinfo = typeinfo; - - /* deprecated integer type */ - ntree->type = typeinfo->type; } else { ntree->typeinfo = &NodeTreeTypeUndefined; ntree->init &= ~NTREE_TYPE_INIT; } + + /* Deprecated integer type. */ + ntree->type = ntree->typeinfo->type; } static void node_set_typeinfo(const struct bContext *C, @@ -1523,7 +1540,7 @@ static bNodeSocket *make_socket(bNodeTree *ntree, } /* make the identifier unique */ BLI_uniquename_cb( - unique_identifier_check, lb, "socket", '.', auto_identifier, sizeof(auto_identifier)); + unique_identifier_check, lb, "socket", '_', auto_identifier, sizeof(auto_identifier)); bNodeSocket *sock = (bNodeSocket *)MEM_callocN(sizeof(bNodeSocket), "sock"); sock->in_out = in_out; @@ -3975,8 +3992,10 @@ int nodeSocketIsHidden(const bNodeSocket *sock) return ((sock->flag & (SOCK_HIDDEN | SOCK_UNAVAIL)) != 0); } -void nodeSetSocketAvailability(bNodeSocket *sock, bool is_available) +void nodeSetSocketAvailability(bNodeTree *UNUSED(ntree), bNodeSocket *sock, bool is_available) { + /* #ntree is not needed right now, but it's generally necessary when changing the tree because we + * want to tag it as changed in the future. */ if (is_available) { sock->flag &= ~SOCK_UNAVAIL; } @@ -3999,17 +4018,38 @@ int nodeSocketLinkLimit(const bNodeSocket *sock) return sock->limit; } +static void update_socket_declarations(ListBase *sockets, + Span<blender::nodes::SocketDeclarationPtr> declarations) +{ + int index; + LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { + const SocketDeclaration &socket_decl = *declarations[index]; + socket->declaration = &socket_decl; + } +} + /** - * If the node implements a `declare` function, this function makes sure that `node->declaration` - * is up to date. + * Update `socket->declaration` for all sockets in the node. This assumes that the node declaration + * and sockets are up to date already. */ -void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) +void nodeSocketDeclarationsUpdate(bNode *node) +{ + BLI_assert(node->declaration != nullptr); + update_socket_declarations(&node->inputs, node->declaration->inputs()); + update_socket_declarations(&node->outputs, node->declaration->outputs()); +} + +/** + * Just update `node->declaration` if necessary. This can also be called on nodes that may not be + * up to date (e.g. because the need versioning or are dynamic). + */ +bool nodeDeclarationEnsureOnOutdatedNode(bNodeTree *UNUSED(ntree), bNode *node) { if (node->declaration != nullptr) { - return; + return false; } if (node->typeinfo->declare == nullptr) { - return; + return false; } if (node->typeinfo->declaration_is_dynamic) { node->declaration = new blender::nodes::NodeDeclaration(); @@ -4021,6 +4061,20 @@ void nodeDeclarationEnsure(bNodeTree *UNUSED(ntree), bNode *node) BLI_assert(node->typeinfo->fixed_declaration != nullptr); node->declaration = node->typeinfo->fixed_declaration; } + return true; +} + +/** + * If the node implements a `declare` function, this function makes sure that `node->declaration` + * is up to date. It is expected that the sockets of the node are up to date already. + */ +bool nodeDeclarationEnsure(bNodeTree *ntree, bNode *node) +{ + if (nodeDeclarationEnsureOnOutdatedNode(ntree, node)) { + nodeSocketDeclarationsUpdate(node); + return true; + } + return false; } /* ************** Node Clipboard *********** */ @@ -4492,18 +4546,6 @@ void ntreeUpdateAllNew(Main *main) FOREACH_NODETREE_END; } -static FieldInferencingInterface *node_field_inferencing_interface_copy( - const FieldInferencingInterface &field_inferencing_interface) -{ - return new FieldInferencingInterface(field_inferencing_interface); -} - -static void node_field_inferencing_interface_free( - const FieldInferencingInterface *field_inferencing_interface) -{ - delete field_inferencing_interface; -} - namespace blender::bke::node_field_inferencing { static bool is_field_socket_type(eNodeSocketDatatype type) @@ -5195,9 +5237,8 @@ bool nodeUpdateID(bNodeTree *ntree, ID *id) void nodeUpdateInternalLinks(bNodeTree *ntree, bNode *node) { BLI_freelistN(&node->internal_links); - - if (node->typeinfo && node->typeinfo->update_internal_links) { - node->typeinfo->update_internal_links(ntree, node); + if (!node->typeinfo->no_muting) { + node_internal_links_create(ntree, node); } } @@ -5462,12 +5503,6 @@ void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) ntype->gpu_fn = gpu_fn; } -void node_type_internal_links(bNodeType *ntype, - void (*update_internal_links)(bNodeTree *, bNode *)) -{ - ntype->update_internal_links = update_internal_links; -} - /* callbacks for undefined types */ static bool node_undefined_poll(bNodeType *UNUSED(ntype), @@ -5485,6 +5520,7 @@ static void register_undefined_types() * they are just used as placeholders in case the actual types are not registered. */ + NodeTreeTypeUndefined.type = NTREE_UNDEFINED; strcpy(NodeTreeTypeUndefined.idname, "NodeTreeUndefined"); strcpy(NodeTreeTypeUndefined.ui_name, N_("Undefined")); strcpy(NodeTreeTypeUndefined.ui_description, N_("Undefined Node Tree Type")); diff --git a/source/blender/blenkernel/intern/object.cc b/source/blender/blenkernel/intern/object.cc index 4b01ee29828..b2dd4b40bae 100644 --- a/source/blender/blenkernel/intern/object.cc +++ b/source/blender/blenkernel/intern/object.cc @@ -160,11 +160,10 @@ static CLG_LogRef LOG = {"bke.object"}; /** - * Vertex parent modifies original BMesh which is not safe for threading. + * NOTE(@sergey): Vertex parent modifies original #BMesh which is not safe for threading. * Ideally such a modification should be handled as a separate DAG update - * callback for mesh datablock, but for until it is actually supported use + * callback for mesh data-block, but for until it is actually supported use * simpler solution with a mutex lock. - * - sergey - */ #define VPARENT_THREADING_HACK @@ -390,7 +389,8 @@ static void library_foreach_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, @@ -399,7 +399,8 @@ static void library_foreach_gpencil_modifiersForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_shaderfxForeachIDLink(void *user_data, @@ -408,7 +409,8 @@ static void library_foreach_shaderfxForeachIDLink(void *user_data, int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), @@ -418,7 +420,8 @@ static void library_foreach_constraintObjectLooper(bConstraint *UNUSED(con), { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; const int cb_flag = is_reference ? IDWALK_CB_USER : IDWALK_CB_NOP; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(psys), @@ -427,7 +430,8 @@ static void library_foreach_particlesystemsObjectLooper(ParticleSystem *UNUSED(p int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } static void object_foreach_id(ID *id, LibraryForeachIDData *data) @@ -494,10 +498,18 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) const int cb_flag_orig = BKE_lib_query_foreachid_process_callback_flag_override( data, proxy_cb_flag, false); LISTBASE_FOREACH (bPoseChannel *, pchan, &object->pose->chanbase) { - IDP_foreach_property( - pchan->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(pchan->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); + BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, pchan->custom, IDWALK_CB_USER); - BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop( + &pchan->constraints, library_foreach_constraintObjectLooper, data)); } BKE_lib_query_foreachid_process_callback_flag_override(data, cb_flag_orig, true); } @@ -509,14 +521,21 @@ static void object_foreach_id(ID *id, LibraryForeachIDData *data) data, object->rigidbody_constraint->ob2, IDWALK_CB_NEVER_SELF); } - BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data); - BKE_gpencil_modifiers_foreach_ID_link( - object, library_foreach_gpencil_modifiersForeachIDLink, data); - BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data); - BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_modifiers_foreach_ID_link(object, library_foreach_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_gpencil_modifiers_foreach_ID_link( + object, library_foreach_gpencil_modifiersForeachIDLink, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_constraints_id_loop(&object->constraints, library_foreach_constraintObjectLooper, data)); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_shaderfx_foreach_ID_link(object, library_foreach_shaderfxForeachIDLink, data)); LISTBASE_FOREACH (ParticleSystem *, psys, &object->particlesystem) { - BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, data)); } if (object->soft) { @@ -1204,7 +1223,7 @@ static IDProperty *object_asset_dimensions_property(Object *ob) return nullptr; } - IDPropertyTemplate idprop = {0}; + IDPropertyTemplate idprop{}; idprop.array.len = ARRAY_SIZE(dimensions); idprop.array.type = IDP_FLOAT; @@ -1747,24 +1766,24 @@ static void object_update_from_subsurf_ccg(Object *object) /* NOTE: we need to reshape into an original mesh from main database, * allowing: * - * - Update copies of that mesh at any moment. - * - Save the file without doing extra reshape. - * - All the users of the mesh have updated displacement. + * - Update copies of that mesh at any moment. + * - Save the file without doing extra reshape. + * - All the users of the mesh have updated displacement. * * However, the tricky part here is that we only know about sculpted * state of a mesh on an object level, and object is being updated after - * mesh datablock is updated. This forces us to: + * mesh data-block is updated. This forces us to: * - * - Update mesh datablock from object evaluation, which is technically - * forbidden, but there is no other place for this yet. - * - Reshape to the original mesh from main database, and then copy updated - * layer to copy of that mesh (since copy of the mesh has decoupled - * custom data layers). + * - Update mesh data-block from object evaluation, which is technically + * forbidden, but there is no other place for this yet. + * - Reshape to the original mesh from main database, and then copy updated + * layer to copy of that mesh (since copy of the mesh has decoupled + * custom data layers). * * All this is defeating all the designs we need to follow to allow safe * threaded evaluation, but this is as good as we can make it within the * current sculpt/evaluated mesh design. This is also how we've survived - * with old DerivedMesh based solutions. So, while this is all wrong and + * with old #DerivedMesh based solutions. So, while this is all wrong and * needs reconsideration, doesn't seem to be a big stopper for real * production artists. */ @@ -1803,7 +1822,7 @@ void BKE_object_eval_assign_data(Object *object_eval, ID *data_eval, bool is_own object_eval->runtime.data_eval = data_eval; object_eval->runtime.is_data_eval_owned = is_owned; - /* Overwrite data of evaluated object, if the datablock types match. */ + /* Overwrite data of evaluated object, if the data-block types match. */ ID *data = (ID *)object_eval->data; if (GS(data->name) == GS(data_eval->name)) { /* NOTE: we are not supposed to invoke evaluation for original objects, @@ -1845,8 +1864,8 @@ void BKE_object_free_derived_caches(Object *ob) ob->runtime.mesh_deform_eval = nullptr; } - /* Restore initial pointer for copy-on-write datablocks, object->data - * might be pointing to an evaluated datablock data was just freed above. */ + /* Restore initial pointer for copy-on-write data-blocks, object->data + * might be pointing to an evaluated data-block data was just freed above. */ if (ob->runtime.data_orig != nullptr) { ob->data = ob->runtime.data_orig; } @@ -2345,13 +2364,13 @@ Object *BKE_object_add_from( } /** - * Add a new object, but assign the given datablock as the ob->data + * Add a new object, but assign the given data-block as the `ob->data` * for the newly created object. * - * \param data: The datablock to assign as ob->data for the new object. - * This is assumed to be of the correct type. - * \param do_id_user: If true, id_us_plus() will be called on data when - * assigning it to the object. + * \param data: The data-block to assign as `ob->data` for the new object. + * This is assumed to be of the correct type. + * \param do_id_user: If true, #id_us_plus() will be called on data when + * assigning it to the object. */ Object *BKE_object_add_for_data( Main *bmain, ViewLayer *view_layer, int type, const char *name, ID *data, bool do_id_user) @@ -2616,7 +2635,7 @@ Object **BKE_object_pose_array_get_ex(ViewLayer *view_layer, Object *ob_pose = BKE_object_pose_armature_get(ob_active); Object **objects = nullptr; if (ob_pose == ob_active) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2663,7 +2682,7 @@ Base **BKE_object_pose_base_array_get_ex(ViewLayer *view_layer, } if (base_active && (base_pose == base_active)) { - ObjectsInModeParams ob_params = {0}; + ObjectsInModeParams ob_params{}; ob_params.object_mode = OB_MODE_POSE; ob_params.no_dup_data = unique; @@ -2851,7 +2870,7 @@ Object *BKE_object_duplicate(Main *bmain, Object *ob, uint dupflag, uint duplica if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid((ID *)&obn->id); + BKE_libblock_relink_to_newid(bmain, &obn->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those flags. */ @@ -4285,7 +4304,7 @@ void BKE_object_foreach_display_point(Object *ob, } } else if (ob->type == OB_GPENCIL) { - GPencilStrokePointIterData iter_data = {nullptr}; + GPencilStrokePointIterData iter_data{}; iter_data.obmat = obmat; iter_data.point_func_cb = func_cb; iter_data.user_data = user_data; @@ -4323,28 +4342,18 @@ void BKE_scene_foreach_display_point(Depsgraph *depsgraph, } /** - * Struct members from DNA_object_types.h + * See struct members from #Object in DNA_object_types.h */ struct ObTfmBack { float loc[3], dloc[3]; - /** scale and delta scale. */ float scale[3], dscale[3]; - /** euler rotation. */ float rot[3], drot[3]; - /** quaternion rotation. */ float quat[4], dquat[4]; - /** axis angle rotation - axis part. */ float rotAxis[3], drotAxis[3]; - /** axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** final worldspace matrix with constraints & animsys applied. */ float obmat[4][4]; - /** inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; - /** inverse result of constraints. doesn't include effect of parent or object local transform. - */ float constinv[4][4]; - /** inverse matrix of 'obmat' for during render, temporally: ipokeys of transform. */ float imat[4][4]; }; @@ -5401,7 +5410,7 @@ void BKE_object_groups_clear(Main *bmain, Scene *scene, Object *ob) } /** - * Return a KDTree_3d from the deformed object (in worldspace) + * Return a KDTree_3d from the deformed object (in world-space). * * \note Only mesh objects currently support deforming, others are TODO. * @@ -5427,7 +5436,7 @@ KDTree_3d *BKE_object_as_kdtree(Object *ob, int *r_tot) MVert *mvert = me_eval->mvert; uint totvert = me_eval->totvert; - /* tree over-allocs in case where some verts have ORIGINDEX_NONE */ + /* Tree over-allocates in case where some verts have #ORIGINDEX_NONE. */ tot = 0; tree = BLI_kdtree_3d_new(totvert); diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index b13fd8a395f..b158633294e 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -180,7 +180,8 @@ static void particle_settings_foreach_id(ID *id, LibraryForeachIDData *data) for (int i = 0; i < MAX_MTEX; i++) { if (psett->mtex[i]) { - BKE_texture_mtex_foreach_id(data, psett->mtex[i]); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_texture_mtex_foreach_id(data, psett->mtex[i])); } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 3358f3e6dea..2318a05e635 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -2798,7 +2798,7 @@ float (*BKE_pbvh_vert_coords_alloc(PBVH *pbvh))[3] void BKE_pbvh_vert_coords_apply(PBVH *pbvh, const float (*vertCos)[3], const int totvert) { if (totvert != pbvh->totvert) { - BLI_assert_msg(0, "PBVH: Given deforming vcos number does not natch PBVH vertex number!"); + BLI_assert_msg(0, "PBVH: Given deforming vcos number does not match PBVH vertex number!"); return; } diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 0aeee11ed17..a0bd3abbc1a 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -471,7 +471,8 @@ static void scene_foreach_rigidbodyworldSceneLooper(struct RigidBodyWorld *UNUSE int cb_flag) { LibraryForeachIDData *data = (LibraryForeachIDData *)user_data; - BKE_lib_query_foreachid_process(data, id_pointer, cb_flag); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_lib_query_foreachid_process(data, id_pointer, cb_flag)); } /** @@ -522,7 +523,10 @@ static void scene_foreach_toolsettings_id_pointer_process( } } -#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS( \ +/* Special handling is needed here, as `scene_foreach_toolsettings` (and its dependency + * `scene_foreach_paint`) are also used by `scene_undo_preserve`, where `LibraryForeachIDData + * *data` is NULL. */ +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER( \ __data, __id, __do_undo_restore, __action, __reader, __id_old, __cb_flag) \ { \ if (__do_undo_restore) { \ @@ -530,24 +534,38 @@ static void scene_foreach_toolsettings_id_pointer_process( (ID **)&(__id), __action, __reader, (ID **)&(__id_old), __cb_flag); \ } \ else { \ + BLI_assert((__data) != NULL); \ BKE_LIB_FOREACHID_PROCESS_IDSUPER(__data, __id, __cb_flag); \ } \ } \ (void)0 +#define BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( \ + __data, __do_undo_restore, __func_call) \ + { \ + if (__do_undo_restore) { \ + __func_call; \ + } \ + else { \ + BLI_assert((__data) != NULL); \ + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(__data, __func_call); \ + } \ + } \ + (void)0 + static void scene_foreach_paint(LibraryForeachIDData *data, Paint *paint, const bool do_undo_restore, BlendLibReader *reader, Paint *paint_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->brush, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->brush, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); for (int i = 0; i < paint_old->tool_slots_len; i++) { /* This is a bit tricky. * - In case we do not do `undo_restore`, `paint` and `paint_old` pointers are the same, so @@ -559,21 +577,21 @@ static void scene_foreach_paint(LibraryForeachIDData *data, */ Brush *brush_tmp = NULL; Brush **brush_p = i < paint->tool_slots_len ? &paint->tool_slots[i].brush : &brush_tmp; - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - *brush_p, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->brush, - IDWALK_CB_USER); - } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - paint->palette, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - paint_old->palette, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + *brush_p, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->brush, + IDWALK_CB_USER); + } + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + paint->palette, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + paint_old->palette, + IDWALK_CB_USER); } static void scene_foreach_toolsettings(LibraryForeachIDData *data, @@ -582,110 +600,152 @@ static void scene_foreach_toolsettings(LibraryForeachIDData *data, BlendLibReader *reader, ToolSettings *toolsett_old) { - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.scene, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.scene, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.object, - IDWALK_CB_NOP); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->particle.shape_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->particle.shape_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.scene, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.scene, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.object, + IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->particle.shape_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->particle.shape_object, + IDWALK_CB_NOP); scene_foreach_paint( data, &toolsett->imapaint.paint, do_undo_restore, reader, &toolsett_old->imapaint.paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.stencil, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.stencil, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.clone, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.clone, - IDWALK_CB_USER); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->imapaint.canvas, - do_undo_restore, - SCENE_FOREACH_UNDO_RESTORE, - reader, - toolsett_old->imapaint.canvas, - IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.stencil, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.stencil, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.clone, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.clone, + IDWALK_CB_USER); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->imapaint.canvas, + do_undo_restore, + SCENE_FOREACH_UNDO_RESTORE, + reader, + toolsett_old->imapaint.canvas, + IDWALK_CB_USER); if (toolsett->vpaint) { - scene_foreach_paint( - data, &toolsett->vpaint->paint, do_undo_restore, reader, &toolsett_old->vpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->vpaint->paint, + do_undo_restore, + reader, + &toolsett_old->vpaint->paint)); } if (toolsett->wpaint) { - scene_foreach_paint( - data, &toolsett->wpaint->paint, do_undo_restore, reader, &toolsett_old->wpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->wpaint->paint, + do_undo_restore, + reader, + &toolsett_old->wpaint->paint)); } if (toolsett->sculpt) { - scene_foreach_paint( - data, &toolsett->sculpt->paint, do_undo_restore, reader, &toolsett_old->sculpt->paint); - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->sculpt->gravity_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->sculpt->gravity_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->sculpt->paint, + do_undo_restore, + reader, + &toolsett_old->sculpt->paint)); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->sculpt->gravity_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->sculpt->gravity_object, + IDWALK_CB_NOP); } if (toolsett->uvsculpt) { - scene_foreach_paint( - data, &toolsett->uvsculpt->paint, do_undo_restore, reader, &toolsett_old->uvsculpt->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->uvsculpt->paint, + do_undo_restore, + reader, + &toolsett_old->uvsculpt->paint)); } if (toolsett->gp_paint) { - scene_foreach_paint( - data, &toolsett->gp_paint->paint, do_undo_restore, reader, &toolsett_old->gp_paint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_paint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_paint->paint)); } if (toolsett->gp_vertexpaint) { - scene_foreach_paint(data, - &toolsett->gp_vertexpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_vertexpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_vertexpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_vertexpaint->paint)); } if (toolsett->gp_sculptpaint) { - scene_foreach_paint(data, - &toolsett->gp_sculptpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_sculptpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_sculptpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_sculptpaint->paint)); } if (toolsett->gp_weightpaint) { - scene_foreach_paint(data, - &toolsett->gp_weightpaint->paint, - do_undo_restore, - reader, - &toolsett_old->gp_weightpaint->paint); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL( + data, + do_undo_restore, + scene_foreach_paint(data, + &toolsett->gp_weightpaint->paint, + do_undo_restore, + reader, + &toolsett_old->gp_weightpaint->paint)); } - BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS(data, - toolsett->gp_sculpt.guide.reference_object, - do_undo_restore, - SCENE_FOREACH_UNDO_NO_RESTORE, - reader, - toolsett_old->gp_sculpt.guide.reference_object, - IDWALK_CB_NOP); + BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER(data, + toolsett->gp_sculpt.guide.reference_object, + do_undo_restore, + SCENE_FOREACH_UNDO_NO_RESTORE, + reader, + toolsett_old->gp_sculpt.guide.reference_object, + IDWALK_CB_NOP); } +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_IDSUPER +#undef BKE_LIB_FOREACHID_UNDO_PRESERVE_PROCESS_FUNCTION_CALL + static void scene_foreach_layer_collection(LibraryForeachIDData *data, ListBase *lb) { LISTBASE_FOREACH (LayerCollection *, lc, lb) { @@ -707,7 +767,8 @@ static bool seq_foreach_member_id_cb(Sequence *seq, void *user_data) #define FOREACHID_PROCESS_IDSUPER(_data, _id_super, _cb_flag) \ { \ CHECK_TYPE(&((_id_super)->id), ID *); \ - if (!BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag))) { \ + BKE_lib_query_foreachid_process((_data), (ID **)&(_id_super), (_cb_flag)); \ + if (BKE_lib_query_foreachid_iter_stop((_data))) { \ return false; \ } \ } \ @@ -746,15 +807,18 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scene->r.bake.cage_object, IDWALK_CB_NOP); if (scene->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->nodetree)); } if (scene->ed) { - SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, SEQ_for_each_callback(&scene->ed->seqbase, seq_foreach_member_id_cb, data)); } /* This pointer can be NULL during old files reading, better be safe than sorry. */ if (scene->master_collection != NULL) { - BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&scene->master_collection)); } LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { @@ -765,7 +829,8 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) data, base->object, IDWALK_CB_NOP | IDWALK_CB_OVERRIDE_LIBRARY_NOT_OVERRIDABLE); } - scene_foreach_layer_collection(data, &view_layer->layer_collections); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_layer_collection(data, &view_layer->layer_collections)); LISTBASE_FOREACH (FreestyleModuleConfig *, fmc, &view_layer->freestyle_config.modules) { if (fmc->script) { @@ -786,18 +851,25 @@ static void scene_foreach_id(ID *id, LibraryForeachIDData *data) LISTBASE_FOREACH (TimeMarker *, marker, &scene->markers) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, marker->camera, IDWALK_CB_NOP); - IDP_foreach_property( - marker->prop, IDP_TYPE_FILTER_ID, BKE_lib_query_idpropertiesForeachIDLink_callback, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + IDP_foreach_property(marker->prop, + IDP_TYPE_FILTER_ID, + BKE_lib_query_idpropertiesForeachIDLink_callback, + data)); } ToolSettings *toolsett = scene->toolsettings; if (toolsett) { - scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, scene_foreach_toolsettings(data, toolsett, false, NULL, toolsett)); } if (scene->rigidbody_world) { - BKE_rigidbody_world_id_loop( - scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, + BKE_rigidbody_world_id_loop( + scene->rigidbody_world, scene_foreach_rigidbodyworldSceneLooper, data)); } } @@ -1853,7 +1925,7 @@ Scene *BKE_scene_duplicate(Main *bmain, Scene *sce, eSceneCopyMethod type) if (!is_subprocess) { /* This code will follow into all ID links using an ID tagged with LIB_TAG_NEW. */ - BKE_libblock_relink_to_newid(&sce_copy->id); + BKE_libblock_relink_to_newid(bmain, &sce_copy->id, 0); #ifndef NDEBUG /* Call to `BKE_libblock_relink_to_newid` above is supposed to have cleared all those diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 233a4f344b5..6352e08ec4b 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -97,6 +97,10 @@ static void screen_foreach_id_dopesheet(LibraryForeachIDData *data, bDopeSheet * } } +/** + * Callback used by lib_query to walk over all ID usages (mimics `foreach_id` callback of + * `IDTypeInfo` structure). + */ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, area->full, IDWALK_CB_NOP); @@ -107,10 +111,8 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area switch (sl->spacetype) { case SPACE_VIEW3D: { View3D *v3d = (View3D *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->camera, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->ob_center, IDWALK_CB_NOP); - if (v3d->localvd) { BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, v3d->localvd->camera, IDWALK_CB_NOP); } @@ -118,13 +120,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_GRAPH: { SpaceGraph *sipo = (SpaceGraph *)sl; - - screen_foreach_id_dopesheet(data, sipo->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, sipo->ads)); break; } case SPACE_PROPERTIES: { SpaceProperties *sbuts = (SpaceProperties *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, sbuts->pinid, IDWALK_CB_NOP); break; } @@ -132,14 +133,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area break; case SPACE_ACTION: { SpaceAction *saction = (SpaceAction *)sl; - screen_foreach_id_dopesheet(data, &saction->ads); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, saction->action, IDWALK_CB_NOP); break; } case SPACE_IMAGE: { SpaceImage *sima = (SpaceImage *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->image, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->mask_info.mask, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sima->gpd, IDWALK_CB_USER); @@ -147,33 +146,28 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_SEQ: { SpaceSeq *sseq = (SpaceSeq *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sseq->gpd, IDWALK_CB_USER); break; } case SPACE_NLA: { SpaceNla *snla = (SpaceNla *)sl; - - screen_foreach_id_dopesheet(data, snla->ads); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + screen_foreach_id_dopesheet(data, snla->ads)); break; } case SPACE_TEXT: { SpaceText *st = (SpaceText *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, st->text, IDWALK_CB_NOP); break; } case SPACE_SCRIPT: { SpaceScript *scpt = (SpaceScript *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, scpt->script, IDWALK_CB_NOP); break; } case SPACE_OUTLINER: { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - BKE_LIB_FOREACHID_PROCESS_ID(data, space_outliner->search_tse.id, IDWALK_CB_NOP); - if (space_outliner->treestore != NULL) { TreeStoreElem *tselem; BLI_mempool_iter iter; @@ -187,13 +181,11 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_NODE: { SpaceNode *snode = (SpaceNode *)sl; - const bool is_private_nodetree = snode->id != NULL && ntreeFromID(snode->id) == snode->nodetree; BKE_LIB_FOREACHID_PROCESS_ID(data, snode->id, IDWALK_CB_NOP); BKE_LIB_FOREACHID_PROCESS_ID(data, snode->from, IDWALK_CB_NOP); - BKE_LIB_FOREACHID_PROCESS_IDSUPER( data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER_ONE); @@ -219,14 +211,12 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area } case SPACE_CLIP: { SpaceClip *sclip = (SpaceClip *)sl; - BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->clip, IDWALK_CB_USER_ONE); BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, sclip->mask_info.mask, IDWALK_CB_USER_ONE); break; } case SPACE_SPREADSHEET: { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { if (context->type == SPREADSHEET_CONTEXT_OBJECT) { BKE_LIB_FOREACHID_PROCESS_IDSUPER( @@ -243,12 +233,13 @@ void BKE_screen_foreach_id_screen_area(LibraryForeachIDData *data, ScrArea *area static void screen_foreach_id(ID *id, LibraryForeachIDData *data) { - if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { - bScreen *screen = (bScreen *)id; + if ((BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) == 0) { + return; + } + bScreen *screen = (bScreen *)id; - LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { - BKE_screen_foreach_id_screen_area(data, area); - } + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_screen_foreach_id_screen_area(data, area)); } } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 1d297b3ced9..98e7405bde6 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -103,7 +103,8 @@ static void simulation_foreach_id(ID *id, LibraryForeachIDData *data) Simulation *simulation = (Simulation *)id; if (simulation->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&simulation->nodetree)); } } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index b7eb9d31b23..a008edd038a 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2633,7 +2633,7 @@ static void interpolate_exciter(Object *ob, int timescale, int time) } } -/* ************ convertors ********** */ +/* ************ converters ********** */ /* for each object type we need; * - xxxx_to_softbody(Object *ob) : a full (new) copy, creates SB geometry diff --git a/source/blender/blenkernel/intern/spline_base.cc b/source/blender/blenkernel/intern/spline_base.cc index c2c9d178171..52bbd2bec57 100644 --- a/source/blender/blenkernel/intern/spline_base.cc +++ b/source/blender/blenkernel/intern/spline_base.cc @@ -30,14 +30,12 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::attribute_math::convert_to_static_type; using blender::bke::AttributeIDRef; using blender::fn::GMutableSpan; using blender::fn::GSpan; using blender::fn::GVArray; -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; Spline::Type Spline::type() const { @@ -416,7 +414,7 @@ Span<float3> Spline::evaluated_normals() const } /* Rotate the generated normals with the interpolated tilt data. */ - GVArray_Typed<float> tilts = this->interpolate_to_evaluated(this->tilts()); + VArray<float> tilts = this->interpolate_to_evaluated(this->tilts()); for (const int i : normals.index_range()) { normals[i] = rotate_direction_around_axis(normals[i], tangents[i], tilts[i]); } @@ -529,9 +527,9 @@ void Spline::bounds_min_max(float3 &min, float3 &max, const bool use_evaluated) } } -GVArrayPtr Spline::interpolate_to_evaluated(GSpan data) const +GVArray Spline::interpolate_to_evaluated(GSpan data) const { - return this->interpolate_to_evaluated(GVArray_For_GSpan(data)); + return this->interpolate_to_evaluated(GVArray::ForSpan(data)); } /** @@ -547,7 +545,7 @@ void Spline::sample_with_index_factors(const GVArray &src, blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); - const GVArray_Typed<T> src_typed = src.typed<T>(); + const VArray<T> src_typed = src.typed<T>(); MutableSpan<T> dst_typed = dst.typed<T>(); if (src.size() == 1) { dst_typed.fill(src_typed[0]); diff --git a/source/blender/blenkernel/intern/spline_bezier.cc b/source/blender/blenkernel/intern/spline_bezier.cc index 18d195f19da..0cadab998f5 100644 --- a/source/blender/blenkernel/intern/spline_bezier.cc +++ b/source/blender/blenkernel/intern/spline_bezier.cc @@ -25,9 +25,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArrayPtr; void BezierSpline::copy_settings(Spline &dst) const { @@ -708,26 +707,26 @@ static void interpolate_to_evaluated_impl(const BezierSpline &spline, } } -GVArrayPtr BezierSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray BezierSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } const int eval_size = this->evaluated_points_size(); if (eval_size == 1) { - return src.shallow_copy(); + return src; } - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(eval_size); interpolate_to_evaluated_impl<T>(*this, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); diff --git a/source/blender/blenkernel/intern/spline_nurbs.cc b/source/blender/blenkernel/intern/spline_nurbs.cc index 6d30d8ba916..7fa332a0330 100644 --- a/source/blender/blenkernel/intern/spline_nurbs.cc +++ b/source/blender/blenkernel/intern/spline_nurbs.cc @@ -26,10 +26,8 @@ using blender::float3; using blender::IndexRange; using blender::MutableSpan; using blender::Span; +using blender::VArray; using blender::fn::GVArray; -using blender::fn::GVArray_For_ArrayContainer; -using blender::fn::GVArray_Typed; -using blender::fn::GVArrayPtr; void NURBSpline::copy_settings(Spline &dst) const { @@ -410,23 +408,23 @@ void interpolate_to_evaluated_impl(Span<NURBSpline::BasisCache> weights, mixer.finalize(); } -GVArrayPtr NURBSpline::interpolate_to_evaluated(const GVArray &src) const +GVArray NURBSpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); if (src.is_single()) { - return src.shallow_copy(); + return src; } Span<BasisCache> basis_cache = this->calculate_basis_cache(); - GVArrayPtr new_varray; + GVArray new_varray; blender::attribute_math::convert_to_static_type(src.type(), [&](auto dummy) { using T = decltype(dummy); if constexpr (!std::is_void_v<blender::attribute_math::DefaultMixer<T>>) { Array<T> values(this->evaluated_points_size()); interpolate_to_evaluated_impl<T>(basis_cache, src.typed<T>(), values); - new_varray = std::make_unique<GVArray_For_ArrayContainer<Array<T>>>(std::move(values)); + new_varray = VArray<T>::ForContainer(std::move(values)); } }); @@ -448,8 +446,8 @@ Span<float3> NURBSpline::evaluated_positions() const evaluated_position_cache_.resize(eval_size); /* TODO: Avoid copying the evaluated data from the temporary array. */ - GVArray_Typed<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); - evaluated->materialize(evaluated_position_cache_); + VArray<float3> evaluated = Spline::interpolate_to_evaluated(positions_.as_span()); + evaluated.materialize(evaluated_position_cache_); position_cache_dirty_ = false; return evaluated_position_cache_; diff --git a/source/blender/blenkernel/intern/spline_poly.cc b/source/blender/blenkernel/intern/spline_poly.cc index 338b5d0ac9e..d495c977285 100644 --- a/source/blender/blenkernel/intern/spline_poly.cc +++ b/source/blender/blenkernel/intern/spline_poly.cc @@ -23,7 +23,6 @@ using blender::float3; using blender::MutableSpan; using blender::Span; using blender::fn::GVArray; -using blender::fn::GVArrayPtr; void PolySpline::copy_settings(Spline &UNUSED(dst)) const { @@ -122,9 +121,8 @@ Span<float3> PolySpline::evaluated_positions() const * the original data. Therefore the lifetime of the returned virtual array must not be longer than * the source data. */ -GVArrayPtr PolySpline::interpolate_to_evaluated(const GVArray &src) const +GVArray PolySpline::interpolate_to_evaluated(const GVArray &src) const { BLI_assert(src.size() == this->size()); - - return src.shallow_copy(); + return src; } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index 0c58c8e8a5a..6796b1ac397 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -2020,7 +2020,7 @@ static void set_ccgdm_all_geometry(CCGDerivedMesh *ccgdm, &dm->loopData, &ccgdm->dm.loopData, loopidx, w2, NULL, numVerts, loopindex2); loopindex2++; - /* Copy over poly data, e.g. mtexpoly. */ + /* Copy over poly data, e.g. #CD_FACEMAP. */ CustomData_copy_data(&dm->polyData, &ccgdm->dm.polyData, origIndex, faceNum, 1); /* Set original index data. */ diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 0cb2218e7e0..7ac9e20d1a7 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -1977,7 +1977,7 @@ static char tab_to_spaces[] = " "; static void txt_convert_tab_to_spaces(Text *text) { /* sb aims to pad adjust the tab-width needed so that the right number of spaces - * is added so that the indention of the line is the right width (i.e. aligned + * is added so that the indentation of the line is the right width (i.e. aligned * to multiples of TXT_TABSIZE) */ const char *sb = &tab_to_spaces[text->curc % TXT_TABSIZE]; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index c878abf0dff..a8c8eaa6a1c 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -142,7 +142,8 @@ static void texture_foreach_id(ID *id, LibraryForeachIDData *data) Tex *texture = (Tex *)id; if (texture->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&texture->nodetree)); } BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, texture->ima, IDWALK_CB_USER); } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index fe03c5b817a..2f0a282a298 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -131,7 +131,8 @@ static void world_foreach_id(ID *id, LibraryForeachIDData *data) if (world->nodetree) { /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ - BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL( + data, BKE_library_foreach_ID_embedded(data, (ID **)&world->nodetree)); } } diff --git a/source/blender/blenlib/BLI_any.hh b/source/blender/blenlib/BLI_any.hh new file mode 100644 index 00000000000..0fc5de5540f --- /dev/null +++ b/source/blender/blenlib/BLI_any.hh @@ -0,0 +1,319 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +/** \file + * \ingroup bli + * + * A #blender::Any is a type-safe container for single values of any copy constructible type. + * It is similar to #std::any but provides the following two additional features: + * - Adjustable inline buffer capacity and alignment. #std::any has a small inline buffer in most + * implementations as well, but its size is not guaranteed. + * - Can store additional user-defined type information without increasing the stack size of #Any. + */ + +#include <algorithm> +#include <utility> + +#include "BLI_memory_utils.hh" + +namespace blender { + +namespace detail { + +/** + * Contains function pointers that manage the memory in an #Any. + * Additional type specific #ExtraInfo can be embedded here as well. + */ +template<typename ExtraInfo> struct AnyTypeInfo { + void (*copy_construct)(void *dst, const void *src); + void (*move_construct)(void *dst, void *src); + void (*destruct)(void *src); + const void *(*get)(const void *src); + ExtraInfo extra_info; + + /** + * Used when #T is stored directly in the inline buffer of the #Any. + */ + template<typename T> static const AnyTypeInfo &get_for_inline() + { + static AnyTypeInfo funcs = {[](void *dst, const void *src) { new (dst) T(*(const T *)src); }, + [](void *dst, void *src) { new (dst) T(std::move(*(T *)src)); }, + [](void *src) { ((T *)src)->~T(); }, + [](const void *src) { return src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when #T can't be stored directly in the inline buffer and is stored in a #std::unique_ptr + * instead. In this scenario, the #std::unique_ptr is stored in the inline buffer. + */ + template<typename T> static const AnyTypeInfo &get_for_unique_ptr() + { + using Ptr = std::unique_ptr<T>; + static AnyTypeInfo funcs = { + [](void *dst, const void *src) { new (dst) Ptr(new T(**(const Ptr *)src)); }, + [](void *dst, void *src) { new (dst) Ptr(new T(std::move(**(Ptr *)src))); }, + [](void *src) { ((Ptr *)src)->~Ptr(); }, + [](const void *src) -> const void * { return &**(const Ptr *)src; }, + ExtraInfo::template get<T>()}; + return funcs; + } + + /** + * Used when the #Any does not contain any type currently. + */ + static const AnyTypeInfo &get_for_empty() + { + static AnyTypeInfo funcs = {[](void *UNUSED(dst), const void *UNUSED(src)) {}, + [](void *UNUSED(dst), void *UNUSED(src)) {}, + [](void *UNUSED(src)) {}, + [](const void *UNUSED(src)) -> const void * { return nullptr; }, + ExtraInfo{}}; + return funcs; + } +}; + +/** + * Dummy extra info that is used when no additional type information should be stored in the #Any. + */ +struct NoExtraInfo { + template<typename T> static NoExtraInfo get() + { + return {}; + } +}; + +} // namespace detail + +template< + /** + * Either void or a struct that contains data members for additional type information. + * The struct has to have a static `ExtraInfo get<T>()` method that initializes the struct + * based on a type. + */ + typename ExtraInfo = void, + /** + * Size of the inline buffer. This allows types that are small enough to be stored directly + * inside the #Any without an additional allocation. + */ + size_t InlineBufferCapacity = 8, + /** + * Required minimum alignment of the inline buffer. If this is smaller than the alignment + * requirement of a used type, a separate allocation is necessary. + */ + size_t Alignment = 8> +class Any { + private: + /* Makes it possible to use void in the template parameters. */ + using RealExtraInfo = + std::conditional_t<std::is_void_v<ExtraInfo>, detail::NoExtraInfo, ExtraInfo>; + using Info = detail::AnyTypeInfo<RealExtraInfo>; + + /** + * Inline buffer that either contains nothing, the stored value directly, or a #std::unique_ptr + * to the value. + */ + AlignedBuffer<std::max(InlineBufferCapacity, sizeof(std::unique_ptr<int>)), Alignment> buffer_{}; + + /** + * Information about the type that is currently stored. + */ + const Info *info_ = &Info::get_for_empty(); + + public: + /** Only copy constructible types can be stored in #Any. */ + template<typename T> static constexpr inline bool is_allowed_v = std::is_copy_constructible_v<T>; + + /** + * Checks if the type will be stored in the inline buffer or if it requires a separate + * allocation. + */ + template<typename T> + static constexpr inline bool is_inline_v = std::is_nothrow_move_constructible_v<T> && + sizeof(T) <= InlineBufferCapacity && + alignof(T) <= Alignment; + + /** + * Checks if #T is the same type as this #Any, because in this case the behavior of e.g. the + * assignment operator is different. + */ + template<typename T> + static constexpr inline bool is_same_any_v = std::is_same_v<std::decay_t<T>, Any>; + + private: + template<typename T> const Info &get_info() const + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + if constexpr (is_inline_v<DecayT>) { + return Info::template get_for_inline<DecayT>(); + } + else { + return Info::template get_for_unique_ptr<DecayT>(); + } + } + + public: + Any() = default; + + Any(const Any &other) : info_(other.info_) + { + info_->copy_construct(&buffer_, &other.buffer_); + } + + /** + * \note The #other #Any will not be empty afterwards if it was not before. Just its value is in + * a moved-from state. + */ + Any(Any &&other) noexcept : info_(other.info_) + { + info_->move_construct(&buffer_, &other.buffer_); + } + + /** + * Constructs a new #Any that contains the given type #T from #args. The #std::in_place_type_t is + * used to disambiguate this and the copy/move constructors. + */ + template<typename T, typename... Args> explicit Any(std::in_place_type_t<T>, Args &&...args) + { + using DecayT = std::decay_t<T>; + static_assert(is_allowed_v<DecayT>); + info_ = &this->template get_info<DecayT>(); + if constexpr (is_inline_v<DecayT>) { + /* Construct the value directly in the inline buffer. */ + new (&buffer_) DecayT(std::forward<Args>(args)...); + } + else { + /* Construct the value in a new allocation and store a #std::unique_ptr to it in the inline + * buffer. */ + new (&buffer_) std::unique_ptr<DecayT>(new DecayT(std::forward<Args>(args)...)); + } + } + + /** + * Constructs a new #Any that contains the given value. + */ + template<typename T, typename X = std::enable_if_t<!is_same_any_v<T>, void>> + Any(T &&value) : Any(std::in_place_type<T>, std::forward<T>(value)) + { + } + + ~Any() + { + info_->destruct(&buffer_); + } + + /** + * \note: Only needed because the template below does not count as copy assignment operator. + */ + Any &operator=(const Any &other) + { + if (this == &other) { + return *this; + } + this->~Any(); + new (this) Any(other); + return *this; + } + + /** Assign any value to the #Any. */ + template<typename T> Any &operator=(T &&other) + { + if constexpr (is_same_any_v<T>) { + if (this == &other) { + return *this; + } + } + this->~Any(); + new (this) Any(std::forward<T>(other)); + return *this; + } + + /** Destruct any existing value to make it empty. */ + void reset() + { + info_->destruct(&buffer_); + info_ = &Info::get_for_empty(); + } + + operator bool() const + { + return this->has_value(); + } + + bool has_value() const + { + return info_ != &Info::get_for_empty(); + } + + template<typename T, typename... Args> std::decay_t<T> &emplace(Args &&...args) + { + this->~Any(); + new (this) Any(std::in_place_type<T>, std::forward<Args>(args)...); + return this->get<T>(); + } + + /** Return true when the value that is currently stored is a #T. */ + template<typename T> bool is() const + { + return info_ == &this->template get_info<T>(); + } + + /** Get a pointer to the stored value. */ + void *get() + { + return const_cast<void *>(info_->get(&buffer_)); + } + + /** Get a pointer to the stored value. */ + const void *get() const + { + return info_->get(&buffer_); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> std::decay_t<T> &get() + { + BLI_assert(this->is<T>()); + return *static_cast<std::decay_t<T> *>(this->get()); + } + + /** + * Get a reference to the stored value. This invokes undefined behavior when #T does not have the + * correct type. + */ + template<typename T> const std::decay_t<T> &get() const + { + BLI_assert(this->is<T>()); + return *static_cast<const std::decay_t<T> *>(this->get()); + } + + /** + * Get extra information that has been stored for the contained type. + */ + const RealExtraInfo &extra_info() const + { + return info_->extra_info; + } +}; + +} // namespace blender diff --git a/source/blender/blenlib/BLI_serialize.hh b/source/blender/blenlib/BLI_serialize.hh index 7b8aa03b807..051731ab801 100644 --- a/source/blender/blenlib/BLI_serialize.hh +++ b/source/blender/blenlib/BLI_serialize.hh @@ -103,11 +103,11 @@ using IntValue = PrimitiveValue<int64_t, eValueType::Int>; using DoubleValue = PrimitiveValue<double, eValueType::Double>; using BooleanValue = PrimitiveValue<bool, eValueType::Boolean>; -template<typename Container, typename ContainerItem, eValueType V> class ContainerValue; +template<typename Container, eValueType V, typename ContainerItem = typename Container::value_type> +class ContainerValue; /* ArrayValue stores its items as shared pointer as it shares data with a lookup table that can * be created by calling `create_lookup`. */ -using ArrayValue = - ContainerValue<Vector<std::shared_ptr<Value>>, std::shared_ptr<Value>, eValueType::Array>; +using ArrayValue = ContainerValue<Vector<std::shared_ptr<Value>>, eValueType::Array>; /** * Class containing a (de)serializable value. @@ -138,7 +138,7 @@ class Value { public: virtual ~Value() = default; - const eValueType type() const + eValueType type() const { return type_; } @@ -234,11 +234,11 @@ template< /** The container type where the elements are stored in. */ typename Container, - /** Type of the data inside the container. */ - typename ContainerItem, - /** ValueType representing the value (object/array). */ - eValueType V> + eValueType V, + + /** Type of the data inside the container. */ + typename ContainerItem> class ContainerValue : public Value { public: using Items = Container; @@ -275,8 +275,7 @@ using ObjectElementType = std::pair<std::string, std::shared_ptr<Value>>; * Object is a key-value container where the key must be a std::string. * Internally it is stored in a blender::Vector to ensure the order of keys. */ -class ObjectValue - : public ContainerValue<Vector<ObjectElementType>, ObjectElementType, eValueType::Object> { +class ObjectValue : public ContainerValue<Vector<ObjectElementType>, eValueType::Object> { public: using LookupValue = std::shared_ptr<Value>; using Lookup = Map<std::string, LookupValue>; diff --git a/source/blender/blenlib/BLI_virtual_array.hh b/source/blender/blenlib/BLI_virtual_array.hh index 1c02bce8411..d9f83d3e1cb 100644 --- a/source/blender/blenlib/BLI_virtual_array.hh +++ b/source/blender/blenlib/BLI_virtual_array.hh @@ -37,148 +37,98 @@ * see of the increased compile time and binary size is worth it. */ +#include "BLI_any.hh" #include "BLI_array.hh" #include "BLI_index_mask.hh" #include "BLI_span.hh" namespace blender { -/* An immutable virtual array. */ -template<typename T> class VArray { +/* Forward declarations for generic virtual arrays. */ +namespace fn { +class GVArray; +class GVMutableArray; +}; // namespace fn + +/** + * Implements the specifics of how the elements of a virtual array are accessed. It contains a + * bunch of virtual methods that are wrapped by #VArray. + */ +template<typename T> class VArrayImpl { protected: + /** + * Number of elements in the virtual array. All virtual arrays have a size, but in some cases it + * may make sense to set it to the max value. + */ int64_t size_; public: - VArray(const int64_t size) : size_(size) + VArrayImpl(const int64_t size) : size_(size) { BLI_assert(size_ >= 0); } - virtual ~VArray() = default; - - T get(const int64_t index) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - return this->get_impl(index); - } + virtual ~VArrayImpl() = default; int64_t size() const { return size_; } - bool is_empty() const - { - return size_ == 0; - } - - IndexRange index_range() const - { - return IndexRange(size_); - } - - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } - - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - Span<T> get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return {}; - } - return this->get_internal_span_impl(); - } + /** + * Get the element at #index. This does not return a reference, because the value may be computed + * on the fly. + */ + virtual T get(const int64_t index) const = 0; - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } - - /* Returns the value that is returned for every index. This invokes undefined behavior if the - * virtual array would not return the same value for every index. */ - T get_internal_single() const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - return this->get(0); - } - return this->get_internal_single_impl(); - } - - /* Get the element at a specific index. Note that this operator cannot be used to assign values - * to an index, because the return value is not a reference. */ - T operator[](const int64_t index) const - { - return this->get(index); - } - - /* Copy the entire virtual array into a span. */ - void materialize(MutableSpan<T> r_span) const - { - this->materialize(IndexMask(size_), r_span); - } - - /* Copy some indices of the virtual array into a span. */ - void materialize(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_impl(mask, r_span); - } - - void materialize_to_uninitialized(MutableSpan<T> r_span) const - { - this->materialize_to_uninitialized(IndexMask(size_), r_span); - } - - void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const - { - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, r_span); - } - - protected: - virtual T get_impl(const int64_t index) const = 0; - - virtual bool is_span_impl() const + /** + * Return true when the virtual array is a plain array internally. + */ + virtual bool is_span() const { return false; } - virtual Span<T> get_internal_span_impl() const + /** + * Return the span of the virtual array. + * This invokes undefined behavior when #is_span returned false. + */ + virtual Span<T> get_internal_span() const { + /* Provide a default implementation, so that subclasses don't have to provide it. This method + * should never be called because #is_span returns false by default. */ BLI_assert_unreachable(); return {}; } - virtual bool is_single_impl() const + /** + * Return true when the virtual array has the same value at every index. + */ + virtual bool is_single() const { return false; } - virtual T get_internal_single_impl() const + /** + * Return the value that is used at every index. + * This invokes undefined behavior when #is_single returned false. + */ + virtual T get_internal_single() const { /* Provide a default implementation, so that subclasses don't have to provide it. This method - * should never be called because `is_single_impl` returns false by default. */ + * should never be called because #is_single returns false by default. */ BLI_assert_unreachable(); return T(); } - virtual void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Copy values from the virtual array into the provided span. The index of the value in the + * virtual is the same as the index in the span. + */ + virtual void materialize(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { dst[i] = src[i]; }); @@ -192,9 +142,13 @@ template<typename T> class VArray { } } - virtual void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const + /** + * Same as #materialize but #r_span is expected to be uninitialized. + */ + virtual void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const { T *dst = r_span.data(); + /* Optimize for a few different common cases. */ if (this->is_span()) { const T *src = this->get_internal_span().data(); mask.foreach_index([&](const int64_t i) { new (dst + i) T(src[i]); }); @@ -207,43 +161,48 @@ template<typename T> class VArray { mask.foreach_index([&](const int64_t i) { new (dst + i) T(this->get(i)); }); } } -}; -/* Similar to VArray, but the elements are mutable. */ -template<typename T> class VMutableArray : public VArray<T> { - public: - VMutableArray(const int64_t size) : VArray<T>(size) + /** + * If this virtual wraps another #GVArray, this method should assign the wrapped array to the + * provided reference. This allows losslessly converting between generic and typed virtual + * arrays in all cases. + * Return true when the virtual array was assigned and false when nothing was done. + */ + virtual bool try_assign_GVArray(fn::GVArray &UNUSED(varray)) const { + return false; } - void set(const int64_t index, T value) + /** + * Return true when this virtual array may own any of the memory it references. This can be used + * for optimization purposes when converting or copying the virtual array. + */ + virtual bool may_have_ownership() const { - BLI_assert(index >= 0); - BLI_assert(index < this->size_); - this->set_impl(index, std::move(value)); + /* Use true by default to be on the safe side. Subclasses that know for sure that they don't + * own anything can overwrite this with false. */ + return true; } +}; - /* Copy the values from the source span to all elements in the virtual array. */ - void set_all(Span<T> src) - { - BLI_assert(src.size() == this->size_); - this->set_all_impl(src); - } +/* Similar to #VArrayImpl, but adds methods that allow modifying the referenced elements. */ +template<typename T> class VMutableArrayImpl : public VArrayImpl<T> { + public: + using VArrayImpl<T>::VArrayImpl; - MutableSpan<T> get_internal_span() - { - BLI_assert(this->is_span()); - Span<T> span = static_cast<const VArray<T> *>(this)->get_internal_span(); - return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); - } + /** + * Assign the provided #value to the #index. + */ + virtual void set(const int64_t index, T value) = 0; - protected: - virtual void set_impl(const int64_t index, T value) = 0; - - virtual void set_all_impl(Span<T> src) + /** + * Copy all elements from the provided span into the virtual array. + */ + virtual void set_all(Span<T> src) { if (this->is_span()) { - const MutableSpan<T> span = this->get_internal_span(); + const Span<T> const_span = this->get_internal_span(); + const MutableSpan<T> span{(T *)const_span.data(), const_span.size()}; initialized_copy_n(src.data(), this->size_, span.data()); } else { @@ -253,95 +212,133 @@ template<typename T> class VMutableArray : public VArray<T> { } } } -}; -template<typename T> using VArrayPtr = std::unique_ptr<VArray<T>>; -template<typename T> using VMutableArrayPtr = std::unique_ptr<VMutableArray<T>>; + /** + * Similar to #VArrayImpl::try_assign_GVArray but for mutable virtual arrays. + */ + virtual bool try_assign_GVMutableArray(fn::GVMutableArray &UNUSED(varray)) const + { + return false; + } +}; /** * A virtual array implementation for a span. Methods in this class are final so that it can be * devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is used). */ -template<typename T> class VArray_For_Span : public VArray<T> { +template<typename T> class VArrayImpl_For_Span : public VArrayImpl<T> { protected: const T *data_ = nullptr; public: - VArray_For_Span(const Span<T> data) : VArray<T>(data.size()), data_(data.data()) + VArrayImpl_For_Span(const Span<T> data) : VArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VArray_For_Span(const int64_t size) : VArray<T>(size) + VArrayImpl_For_Span(const int64_t size) : VArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - bool is_span_impl() const final + bool is_span() const final { return true; } - Span<T> get_internal_span_impl() const final + Span<T> get_internal_span() const final { return Span<T>(data_, this->size_); } }; -template<typename T> class VMutableArray_For_MutableSpan : public VMutableArray<T> { +/** + * A version of #VArrayImpl_For_Span that can not be subclassed. This allows safely overwriting the + * #may_have_ownership method. + */ +template<typename T> class VArrayImpl_For_Span_final final : public VArrayImpl_For_Span<T> { + public: + using VArrayImpl_For_Span<T>::VArrayImpl_For_Span; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * Like #VArrayImpl_For_Span but for mutable data. + */ +template<typename T> class VMutableArrayImpl_For_MutableSpan : public VMutableArrayImpl<T> { protected: T *data_ = nullptr; public: - VMutableArray_For_MutableSpan(const MutableSpan<T> data) - : VMutableArray<T>(data.size()), data_(data.data()) + VMutableArrayImpl_For_MutableSpan(const MutableSpan<T> data) + : VMutableArrayImpl<T>(data.size()), data_(data.data()) { } protected: - VMutableArray_For_MutableSpan(const int64_t size) : VMutableArray<T>(size) + VMutableArrayImpl_For_MutableSpan(const int64_t size) : VMutableArrayImpl<T>(size) { } - T get_impl(const int64_t index) const final + T get(const int64_t index) const final { return data_[index]; } - void set_impl(const int64_t index, T value) final + void set(const int64_t index, T value) final { data_[index] = value; } - bool is_span_impl() const override + bool is_span() const override { return true; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(data_, this->size_); } }; /** - * A variant of `VArray_For_Span` that owns the underlying data. + * Like #VArrayImpl_For_Span_final but for mutable data. + */ +template<typename T> +class VMutableArrayImpl_For_MutableSpan_final final : public VMutableArrayImpl_For_MutableSpan<T> { + public: + using VMutableArrayImpl_For_MutableSpan<T>::VMutableArrayImpl_For_MutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * A variant of `VArrayImpl_For_Span` that owns the underlying data. * The `Container` type has to implement a `size()` and `data()` method. * The `data()` method has to return a pointer to the first element in the continuous array of * elements. */ template<typename Container, typename T = typename Container::value_type> -class VArray_For_ArrayContainer : public VArray_For_Span<T> { +class VArrayImpl_For_ArrayContainer : public VArrayImpl_For_Span<T> { private: Container container_; public: - VArray_For_ArrayContainer(Container container) - : VArray_For_Span<T>((int64_t)container.size()), container_(std::move(container)) + VArrayImpl_For_ArrayContainer(Container container) + : VArrayImpl_For_Span<T>((int64_t)container.size()), container_(std::move(container)) { this->data_ = container_.data(); } @@ -352,43 +349,671 @@ class VArray_For_ArrayContainer : public VArray_For_Span<T> { * so that it can be devirtualized by the compiler in some cases (e.g. when #devirtualize_varray is * used). */ -template<typename T> class VArray_For_Single final : public VArray<T> { +template<typename T> class VArrayImpl_For_Single final : public VArrayImpl<T> { private: T value_; public: - VArray_For_Single(T value, const int64_t size) : VArray<T>(size), value_(std::move(value)) + VArrayImpl_For_Single(T value, const int64_t size) + : VArrayImpl<T>(size), value_(std::move(value)) { } protected: - T get_impl(const int64_t UNUSED(index)) const override + T get(const int64_t UNUSED(index)) const override { return value_; } - bool is_span_impl() const override + bool is_span() const override { return this->size_ == 1; } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { return Span<T>(&value_, 1); } - bool is_single_impl() const override + bool is_single() const override { return true; } - T get_internal_single_impl() const override + T get_internal_single() const override { return value_; } }; /** + * This class makes it easy to create a virtual array for an existing function or lambda. The + * `GetFunc` should take a single `index` argument and return the value at that index. + */ +template<typename T, typename GetFunc> class VArrayImpl_For_Func final : public VArrayImpl<T> { + private: + GetFunc get_func_; + + public: + VArrayImpl_For_Func(const int64_t size, GetFunc get_func) + : VArrayImpl<T>(size), get_func_(std::move(get_func)) + { + } + + private: + T get(const int64_t index) const override + { + return get_func_(index); + } + + void materialize(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const override + { + T *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> +class VArrayImpl_For_DerivedSpan final : public VArrayImpl<ElemT> { + private: + const StructT *data_; + + public: + VArrayImpl_For_DerivedSpan(const Span<StructT> data) + : VArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +/** + * \note: This is `final` so that #may_have_ownership can be implemented reliably. + */ +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, ElemT)> +class VMutableArrayImpl_For_DerivedSpan final : public VMutableArrayImpl<ElemT> { + private: + StructT *data_; + + public: + VMutableArrayImpl_For_DerivedSpan(const MutableSpan<StructT> data) + : VMutableArrayImpl<ElemT>(data.size()), data_(data.data()) + { + } + + private: + ElemT get(const int64_t index) const override + { + return GetFunc(data_[index]); + } + + void set(const int64_t index, ElemT value) override + { + SetFunc(data_[index], std::move(value)); + } + + void materialize(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<ElemT> r_span) const override + { + ElemT *dst = r_span.data(); + mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); + } + + bool may_have_ownership() const override + { + return false; + } +}; + +namespace detail { + +/** + * Struct that can be passed as `ExtraInfo` into an #Any. + * This struct is only intended to be used by #VArrayCommon. + */ +template<typename T> struct VArrayAnyExtraInfo { + /** + * Gets the virtual array that is stored at the given pointer. + */ + const VArrayImpl<T> *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const VArrayImpl<T> * { return nullptr; }; + + template<typename StorageT> static VArrayAnyExtraInfo get() + { + /* These are the only allowed types in the #Any. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, StorageT> || + std::is_same_v<StorageT, const VArrayImpl<T> *> || + std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>); + + /* Depending on how the virtual array implementation is stored in the #Any, a different + * #get_varray function is required. */ + if constexpr (std::is_base_of_v<VArrayImpl<T>, StorageT>) { + return {[](const void *buffer) { + return static_cast<const VArrayImpl<T> *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const VArrayImpl<T> *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const VArrayImpl<T>>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } + } +}; + +} // namespace detail + +/** + * Utility class to reduce code duplication for methods available on #VArray and #VMutableArray. + * Deriving #VMutableArray from #VArray would have some issues: + * - Static methods on #VArray would also be available on #VMutableArray. + * - It would allow assigning a #VArray to a #VMutableArray under some circumstances which is not + * allowed and could result in hard to find bugs. + */ +template<typename T> class VArrayCommon { + protected: + /** + * Store the virtual array implementation in an #Any. This makes it easy to avoid a memory + * allocation if the implementation is small enough and is copyable. This is the case for the + * most common virtual arrays. + * Other virtual array implementations are typically stored as #std::shared_ptr. That works even + * when the implementation itself is not copyable and makes copying #VArrayCommon cheaper. + */ + using Storage = Any<detail::VArrayAnyExtraInfo<T>, 24, 8>; + + /** + * Pointer to the currently contained virtual array implementation. This is allowed to be null. + */ + const VArrayImpl<T> *impl_ = nullptr; + /** + * Does the memory management for the virtual array implementation. It contains one of the + * following: + * - Inlined subclass of #VArrayImpl. + * - Non-owning pointer to a #VArrayImpl. + * - Shared pointer to a #VArrayImpl. + */ + Storage storage_; + + protected: + VArrayCommon() = default; + + /** Copy constructor. */ + VArrayCommon(const VArrayCommon &other) : storage_(other.storage_) + { + impl_ = this->impl_from_storage(); + } + + /** Move constructor. */ + VArrayCommon(VArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) + { + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** + * Wrap an existing #VArrayImpl and don't take ownership of it. This should rarely be used in + * practice. + */ + VArrayCommon(const VArrayImpl<T> *impl) : impl_(impl) + { + storage_ = impl_; + } + + /** + * Wrap an existing #VArrayImpl that is contained in a #std::shared_ptr. This takes ownership. + */ + VArrayCommon(std::shared_ptr<const VArrayImpl<T>> impl) : impl_(impl.get()) + { + if (impl) { + storage_ = std::move(impl); + } + } + + /** + * Replace the contained #VArrayImpl. + */ + template<typename ImplT, typename... Args> void emplace(Args &&...args) + { + /* Make sure we are actually constructing a #VArrayImpl. */ + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + /* Only inline the implementatiton when it is copyable and when it fits into the inline + * buffer of the storage. */ + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + /* If it can't be inlined, create a new #std::shared_ptr instead and store that in the + * storage. */ + std::shared_ptr<const VArrayImpl<T>> ptr = std::make_shared<ImplT>( + std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } + } + + /** Utility to implement a copy assignment operator in a subclass. */ + void copy_from(const VArrayCommon &other) + { + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); + } + + /** Utility to implement a move assignment operator in a subclass. */ + void move_from(VArrayCommon &&other) noexcept + { + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; + } + + /** Get a pointer to the virtual array implementation that is currently stored in #storage_, or + * null. */ + const VArrayImpl<T> *impl_from_storage() const + { + return storage_.extra_info().get_varray(storage_.get()); + } + + public: + /** Return false when there is no virtual array implementation currently. */ + operator bool() const + { + return impl_ != nullptr; + } + + /** + * Get the element at a specific index. + * \note: This can't return a reference because the value may be computed on the fly. This also + * implies that one can not use this method for assignments. + */ + T operator[](const int64_t index) const + { + BLI_assert(*this); + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + return impl_->get(index); + } + + /** + * Same as the #operator[] but is sometimes easier to use when one has a pointer to a virtual + * array. + */ + T get(const int64_t index) const + { + return (*this)[index]; + } + + /** + * Return the size of the virtual array. It's allowed to call this method even when there is no + * virtual array. In this case 0 is returned. + */ + int64_t size() const + { + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); + } + + /** True when the size is zero or when there is no virtual array. */ + bool is_empty() const + { + return this->size() == 0; + } + + IndexRange index_range() const + { + return IndexRange(this->size()); + } + + /** Return true when the virtual array is stored as a span internally. */ + bool is_span() const + { + BLI_assert(*this); + if (this->is_empty()) { + return true; + } + return impl_->is_span(); + } + + /** + * Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. + */ + Span<T> get_internal_span() const + { + BLI_assert(this->is_span()); + if (this->is_empty()) { + return {}; + } + return impl_->get_internal_span(); + } + + /** Return true when the virtual array returns the same value for every index. */ + bool is_single() const + { + BLI_assert(*this); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); + } + + /** + * Return the value that is returned for every index. This invokes undefined behavior if the + * virtual array would not return the same value for every index. + */ + T get_internal_single() const + { + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + return impl_->get(0); + } + return impl_->get_internal_single(); + } + + /** Copy the entire virtual array into a span. */ + void materialize(MutableSpan<T> r_span) const + { + this->materialize(IndexMask(this->size()), r_span); + } + + /** Copy some indices of the virtual array into a span. */ + void materialize(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize(mask, r_span); + } + + void materialize_to_uninitialized(MutableSpan<T> r_span) const + { + this->materialize_to_uninitialized(IndexMask(this->size()), r_span); + } + + void materialize_to_uninitialized(IndexMask mask, MutableSpan<T> r_span) const + { + BLI_assert(mask.min_array_size() <= this->size()); + impl_->materialize_to_uninitialized(mask, r_span); + } + + /** See #GVArrayImpl::try_assign_GVArray. */ + bool try_assign_GVArray(fn::GVArray &varray) const + { + return impl_->try_assign_GVArray(varray); + } + + /** See #GVArrayImpl::may_have_ownership. */ + bool may_have_ownership() const + { + return impl_->may_have_ownership(); + } +}; + +template<typename T> class VMutableArray; + +/** + * A #VArray wraps a virtual array implementation and provides easy access to its elements. It can + * be copied and moved. While it is relatively small, it should still be passed by reference if + * possible (other than e.g. #Span). + */ +template<typename T> class VArray : public VArrayCommon<T> { + friend VMutableArray<T>; + + public: + VArray() = default; + VArray(const VArray &other) = default; + VArray(VArray &&other) noexcept = default; + + VArray(const VArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VArray(std::shared_ptr<const VArrayImpl<T>> impl) : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VArrayImpl. + */ + template<typename ImplT, typename... Args> static VArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VArrayImpl<T>, ImplT>); + VArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array that has the same value at every index. + */ + static VArray ForSingle(T value, const int64_t size) + { + return VArray::For<VArrayImpl_For_Single<T>>(std::move(value), size); + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the + * underlying memory. + */ + static VArray ForSpan(Span<T> values) + { + return VArray::For<VArrayImpl_For_Span_final<T>>(values); + } + + /** + * Construct a new virtual that will invoke the provided function whenever an element is + * accessed. + */ + template<typename GetFunc> static VArray ForFunc(const int64_t size, GetFunc get_func) + { + return VArray::For<VArrayImpl_For_Func<T, decltype(get_func)>>(size, std::move(get_func)); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &)> + static VArray ForDerivedSpan(Span<StructT> values) + { + return VArray::For<VArrayImpl_For_DerivedSpan<StructT, T, GetFunc>>(values); + } + + /** + * Construct a new virtual array for an existing container. Every container that lays out the + * elements in a plain array works. This takes ownership of the passed in container. If that is + * not desired, use #ForSpan instead. + */ + template<typename ContainerT> static VArray ForContainer(ContainerT container) + { + return VArray::For<VArrayImpl_For_ArrayContainer<ContainerT>>(std::move(container)); + } + + VArray &operator=(const VArray &other) + { + this->copy_from(other); + return *this; + } + + VArray &operator=(VArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } +}; + +/** + * Similar to #VArray but references a virtual array that can be modified. + */ +template<typename T> class VMutableArray : public VArrayCommon<T> { + public: + VMutableArray() = default; + VMutableArray(const VMutableArray &other) = default; + VMutableArray(VMutableArray &&other) noexcept = default; + + VMutableArray(const VMutableArrayImpl<T> *impl) : VArrayCommon<T>(impl) + { + } + + VMutableArray(std::shared_ptr<const VMutableArrayImpl<T>> impl) + : VArrayCommon<T>(std::move(impl)) + { + } + + /** + * Construct a new virtual array for a custom #VMutableArrayImpl. + */ + template<typename ImplT, typename... Args> static VMutableArray For(Args &&...args) + { + static_assert(std::is_base_of_v<VMutableArrayImpl<T>, ImplT>); + VMutableArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; + } + + /** + * Construct a new virtual array for an existing span. This does not take ownership of the span. + */ + static VMutableArray ForSpan(MutableSpan<T> values) + { + return VMutableArray::For<VMutableArrayImpl_For_MutableSpan_final<T>>(values); + } + + /** + * Construct a new virtual array for an existing span with a mapping function. This does not take + * ownership of the span. + */ + template<typename StructT, T (*GetFunc)(const StructT &), void (*SetFunc)(StructT &, T)> + static VMutableArray ForDerivedSpan(MutableSpan<StructT> values) + { + return VMutableArray::For<VMutableArrayImpl_For_DerivedSpan<StructT, T, GetFunc, SetFunc>>( + values); + } + + /** Convert to a #VArray by copying. */ + operator VArray<T>() const & + { + VArray<T> varray; + varray.copy_from(*this); + return varray; + } + + /** Convert to a #VArray by moving. */ + operator VArray<T>() &&noexcept + { + VArray<T> varray; + varray.move_from(std::move(*this)); + return varray; + } + + VMutableArray &operator=(const VMutableArray &other) + { + this->copy_from(other); + return *this; + } + + VMutableArray &operator=(VMutableArray &&other) noexcept + { + this->move_from(std::move(other)); + return *this; + } + + /** + * Get access to the internal span. This invokes undefined behavior if the #is_span returned + * false. + */ + MutableSpan<T> get_internal_span() const + { + BLI_assert(this->is_span()); + const Span<T> span = this->impl_->get_internal_span(); + return MutableSpan<T>(const_cast<T *>(span.data()), span.size()); + } + + /** + * Set the value at the given index. + */ + void set(const int64_t index, T value) + { + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set(index, std::move(value)); + } + + /** + * Copy the values from the source span to all elements in the virtual array. + */ + void set_all(Span<T> src) + { + BLI_assert(src.size() == this->size()); + this->get_impl()->set_all(src); + } + + /** See #GVMutableArrayImpl::try_assign_GVMutableArray. */ + bool try_assign_GVMutableArray(fn::GVMutableArray &varray) const + { + return this->get_impl()->try_assign_GVMutableArray(varray); + } + + private: + /** Utility to get the pointer to the wrapped #VMutableArrayImpl. */ + VMutableArrayImpl<T> *get_impl() const + { + /* This cast is valid by the invariant that a #VMutableArray->impl_ is always a + * #VMutableArrayImpl. */ + return (VMutableArrayImpl<T> *)this->impl_; + } +}; + +/** * In many cases a virtual array is a span internally. In those cases, access to individual could * be much more efficient than calling a virtual method. When the underlying virtual array is not a * span, this class allocates a new array and copies the values over. @@ -401,11 +1026,11 @@ template<typename T> class VArray_For_Single final : public VArray<T> { */ template<typename T> class VArray_Span final : public Span<T> { private: - const VArray<T> &varray_; + VArray<T> varray_; Array<T> owned_data_; public: - VArray_Span(const VArray<T> &varray) : Span<T>(), varray_(varray) + VArray_Span(VArray<T> varray) : Span<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -421,7 +1046,7 @@ template<typename T> class VArray_Span final : public Span<T> { }; /** - * Same as VArray_Span, but for a mutable span. + * Same as #VArray_Span, but for a mutable span. * The important thing to note is that when changing this span, the results might not be * immediately reflected in the underlying virtual array (only when the virtual array is a span * internally). The #save method can be used to write all changes to the underlying virtual array, @@ -429,7 +1054,7 @@ template<typename T> class VArray_Span final : public Span<T> { */ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { private: - VMutableArray<T> &varray_; + VMutableArray<T> varray_; Array<T> owned_data_; bool save_has_been_called_ = false; bool show_not_saved_warning_ = true; @@ -437,8 +1062,8 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { public: /* Create a span for any virtual array. This is cheap when the virtual array is a span itself. If * not, a new array has to be allocated as a wrapper for the underlying virtual array. */ - VMutableArray_Span(VMutableArray<T> &varray, const bool copy_values_to_span = true) - : MutableSpan<T>(), varray_(varray) + VMutableArray_Span(VMutableArray<T> varray, const bool copy_values_to_span = true) + : MutableSpan<T>(), varray_(std::move(varray)) { this->size_ = varray_.size(); if (varray_.is_span()) { @@ -483,106 +1108,6 @@ template<typename T> class VMutableArray_Span final : public MutableSpan<T> { }; /** - * This class makes it easy to create a virtual array for an existing function or lambda. The - * `GetFunc` should take a single `index` argument and return the value at that index. - */ -template<typename T, typename GetFunc> class VArray_For_Func final : public VArray<T> { - private: - GetFunc get_func_; - - public: - VArray_For_Func(const int64_t size, GetFunc get_func) - : VArray<T>(size), get_func_(std::move(get_func)) - { - } - - private: - T get_impl(const int64_t index) const override - { - return get_func_(index); - } - - void materialize_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = get_func_(i); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<T> r_span) const override - { - T *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) T(get_func_(i)); }); - } -}; - -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class VArray_For_DerivedSpan : public VArray<ElemT> { - private: - const StructT *data_; - - public: - VArray_For_DerivedSpan(const Span<StructT> data) : VArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class VMutableArray_For_DerivedSpan : public VMutableArray<ElemT> { - private: - StructT *data_; - - public: - VMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : VMutableArray<ElemT>(data.size()), data_(data.data()) - { - } - - private: - ElemT get_impl(const int64_t index) const override - { - return GetFunc(data_[index]); - } - - void set_impl(const int64_t index, ElemT value) override - { - SetFunc(data_[index], std::move(value)); - } - - void materialize_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { dst[i] = GetFunc(data_[i]); }); - } - - void materialize_to_uninitialized_impl(IndexMask mask, MutableSpan<ElemT> r_span) const override - { - ElemT *dst = r_span.data(); - mask.foreach_index([&](const int64_t i) { new (dst + i) ElemT(GetFunc(data_[i])); }); - } -}; - -/** * Generate multiple versions of the given function optimized for different virtual arrays. * One has to be careful with nesting multiple devirtualizations, because that results in an * exponential number of function instantiations (increasing compile time and binary size). @@ -596,15 +1121,14 @@ inline void devirtualize_varray(const VArray<T> &varray, const Func &func, bool /* Support disabling the devirtualization to simplify benchmarking. */ if (enable) { if (varray.is_single()) { - /* `VArray_For_Single` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Single<T> varray_single{varray.get_internal_single(), varray.size()}; - func(varray_single); + /* `VArrayImpl_For_Single` can be used for devirtualization, because it is declared `final`. + */ + func(VArray<T>::ForSingle(varray.get_internal_single(), varray.size())); return; } if (varray.is_span()) { - /* `VArray_For_Span` can be used for devirtualization, because it is declared `final`. */ - const VArray_For_Span<T> varray_span{varray.get_internal_span()}; - func(varray_span); + /* `VArrayImpl_For_Span` can be used for devirtualization, because it is declared `final`. */ + func(VArray<T>::ForSpan(varray.get_internal_span())); return; } } @@ -629,27 +1153,23 @@ inline void devirtualize_varray2(const VArray<T1> &varray1, const bool is_single1 = varray1.is_single(); const bool is_single2 = varray2.is_single(); if (is_span1 && is_span2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_span, varray2_span); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_span1 && is_single2) { - const VArray_For_Span<T1> varray1_span{varray1.get_internal_span()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_span, varray2_single); + func(VArray<T1>::ForSpan(varray1.get_internal_span()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } if (is_single1 && is_span2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Span<T2> varray2_span{varray2.get_internal_span()}; - func(varray1_single, varray2_span); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSpan(varray2.get_internal_span())); return; } if (is_single1 && is_single2) { - const VArray_For_Single<T1> varray1_single{varray1.get_internal_single(), varray1.size()}; - const VArray_For_Single<T2> varray2_single{varray2.get_internal_single(), varray2.size()}; - func(varray1_single, varray2_single); + func(VArray<T1>::ForSingle(varray1.get_internal_single(), varray1.size()), + VArray<T2>::ForSingle(varray2.get_internal_single(), varray2.size())); return; } } diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 7db984aef5c..29493c799b3 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -165,6 +165,7 @@ set(SRC BLI_alloca.h BLI_allocator.hh + BLI_any.hh BLI_args.h BLI_array.h BLI_array.hh @@ -411,6 +412,7 @@ blender_add_lib(bf_blenlib "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC + tests/BLI_any_test.cc tests/BLI_array_store_test.cc tests/BLI_array_test.cc tests/BLI_array_utils_test.cc diff --git a/source/blender/blenlib/intern/BLI_mempool.c b/source/blender/blenlib/intern/BLI_mempool.c index f968799326a..bd6a124c7cb 100644 --- a/source/blender/blenlib/intern/BLI_mempool.c +++ b/source/blender/blenlib/intern/BLI_mempool.c @@ -126,7 +126,7 @@ struct BLI_mempool { uint flag; /* keeps aligned to 16 bits */ - /** Free element list. Interleaved into chunk datas. */ + /** Free element list. Interleaved into chunk data. */ BLI_freenode *free; /** Use to know how many chunks to keep for #BLI_mempool_clear. */ uint maxchunks; diff --git a/source/blender/blenlib/intern/string.c b/source/blender/blenlib/intern/string.c index e8be674b6c1..62c8625378d 100644 --- a/source/blender/blenlib/intern/string.c +++ b/source/blender/blenlib/intern/string.c @@ -1346,9 +1346,8 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base } /** - * Format a attribute domain to a up to 6 places (plus '\0' terminator) string using long number - * names abbreviations. This function is designed to produce a compact representation of large - * numbers. + * Format a count to up to 6 places (plus '\0' terminator) string using long number + * names abbreviations. Used to produce a compact representation of large numbers. * * 1 -> 1 * 15 -> 15 @@ -1362,8 +1361,7 @@ void BLI_str_format_byte_unit(char dst[15], long long int bytes, const bool base * 1000000000 -> 1B * ... * - * Dimension of 7 is the maximum length of the resulting string - * A combination with 7 places would be -15.5K\0 + * Length of 7 is the maximum of the resulting string, for example, `-15.5K\0`. */ void BLI_str_format_attribute_domain_size(char dst[7], int number_to_format) { diff --git a/source/blender/blenlib/tests/BLI_any_test.cc b/source/blender/blenlib/tests/BLI_any_test.cc new file mode 100644 index 00000000000..226088cf3c7 --- /dev/null +++ b/source/blender/blenlib/tests/BLI_any_test.cc @@ -0,0 +1,108 @@ +/* Apache License, Version 2.0 */ + +#include "BLI_any.hh" +#include "BLI_map.hh" + +#include "testing/testing.h" + +namespace blender::tests { + +TEST(any, DefaultConstructor) +{ + Any a; + EXPECT_FALSE(a.has_value()); +} + +TEST(any, AssignInt) +{ + Any<> a = 5; + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE(a.is<int>()); + EXPECT_FALSE(a.is<float>()); + const int &value = a.get<int>(); + EXPECT_EQ(value, 5); + a = 10; + EXPECT_EQ(value, 10); + + Any b = a; + EXPECT_TRUE(b.has_value()); + EXPECT_EQ(b.get<int>(), 10); + + Any c = std::move(a); + EXPECT_TRUE(c); + EXPECT_EQ(c.get<int>(), 10); + + EXPECT_EQ(a.get<int>(), 10); /* NOLINT: bugprone-use-after-move */ + + a.reset(); + EXPECT_FALSE(a); +} + +TEST(any, AssignMap) +{ + Any<> a = Map<int, int>(); + EXPECT_TRUE(a.has_value()); + EXPECT_TRUE((a.is<Map<int, int>>())); + EXPECT_FALSE((a.is<Map<int, float>>())); + Map<int, int> &map = a.get<Map<int, int>>(); + map.add(4, 2); + EXPECT_EQ((a.get<Map<int, int>>().lookup(4)), 2); + + Any b = a; + EXPECT_TRUE(b); + EXPECT_EQ((b.get<Map<int, int>>().lookup(4)), 2); + + Any c = std::move(a); + c = c; + EXPECT_TRUE(b); + EXPECT_EQ((c.get<Map<int, int>>().lookup(4)), 2); + + EXPECT_TRUE((a.get<Map<int, int>>().is_empty())); /* NOLINT: bugprone-use-after-move */ +} + +TEST(any, AssignAny) +{ + Any<> a = 5; + Any<> b = std::string("hello"); + Any c; + + Any z; + EXPECT_FALSE(z.has_value()); + + z = a; + EXPECT_TRUE(z.has_value()); + EXPECT_EQ(z.get<int>(), 5); + + z = b; + EXPECT_EQ(z.get<std::string>(), "hello"); + + z = c; + EXPECT_FALSE(z.has_value()); + + z = Any(std::in_place_type<Any<>>, a); + EXPECT_FALSE(z.is<int>()); + EXPECT_TRUE(z.is<Any<>>()); + EXPECT_EQ(z.get<Any<>>().get<int>(), 5); +} + +struct ExtraSizeInfo { + size_t size; + + template<typename T> static ExtraSizeInfo get() + { + return {sizeof(T)}; + } +}; + +TEST(any, ExtraInfo) +{ + using MyAny = Any<ExtraSizeInfo>; + + MyAny a = 5; + EXPECT_EQ(a.extra_info().size, sizeof(int)); + + a = std::string("hello"); + EXPECT_EQ(a.extra_info().size, sizeof(std::string)); +} + +} // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_virtual_array_test.cc b/source/blender/blenlib/tests/BLI_virtual_array_test.cc index a6d2ca10315..62b7b383831 100644 --- a/source/blender/blenlib/tests/BLI_virtual_array_test.cc +++ b/source/blender/blenlib/tests/BLI_virtual_array_test.cc @@ -12,7 +12,7 @@ namespace blender::tests { TEST(virtual_array, Span) { std::array<int, 5> data = {3, 4, 5, 6, 7}; - VArray_For_Span<int> varray{data}; + VArray<int> varray = VArray<int>::ForSpan(data); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray.get(0), 3); EXPECT_EQ(varray.get(4), 7); @@ -23,7 +23,7 @@ TEST(virtual_array, Span) TEST(virtual_array, Single) { - VArray_For_Single<int> varray{10, 4}; + VArray<int> varray = VArray<int>::ForSingle(10, 4); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray.get(0), 10); EXPECT_EQ(varray.get(3), 10); @@ -35,7 +35,7 @@ TEST(virtual_array, Array) { Array<int> array = {1, 2, 3, 5, 8}; { - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(array); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -43,7 +43,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{std::move(array)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 5); EXPECT_EQ(varray[0], 1); EXPECT_EQ(varray[2], 3); @@ -51,7 +51,7 @@ TEST(virtual_array, Array) EXPECT_TRUE(varray.is_span()); } { - VArray_For_ArrayContainer varray{array}; /* NOLINT: bugprone-use-after-move */ + VArray<int> varray = VArray<int>::ForContainer(array); /* NOLINT: bugprone-use-after-move */ EXPECT_TRUE(varray.is_empty()); } } @@ -59,7 +59,7 @@ TEST(virtual_array, Array) TEST(virtual_array, Vector) { Vector<int> vector = {9, 8, 7, 6}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 9); EXPECT_EQ(varray[3], 6); @@ -68,7 +68,7 @@ TEST(virtual_array, Vector) TEST(virtual_array, StdVector) { std::vector<int> vector = {5, 6, 7, 8}; - VArray_For_ArrayContainer varray{std::move(vector)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); EXPECT_EQ(varray[1], 6); @@ -77,7 +77,7 @@ TEST(virtual_array, StdVector) TEST(virtual_array, StdArray) { std::array<int, 4> array = {2, 3, 4, 5}; - VArray_For_ArrayContainer varray{array}; + VArray<int> varray = VArray<int>::ForContainer(std::move(array)); EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 2); EXPECT_EQ(varray[1], 3); @@ -86,7 +86,7 @@ TEST(virtual_array, StdArray) TEST(virtual_array, VectorSet) { VectorSet<int> vector_set = {5, 3, 7, 3, 3, 5, 1}; - VArray_For_ArrayContainer varray{std::move(vector_set)}; + VArray<int> varray = VArray<int>::ForContainer(std::move(vector_set)); EXPECT_TRUE(vector_set.is_empty()); /* NOLINT: bugprone-use-after-move. */ EXPECT_EQ(varray.size(), 4); EXPECT_EQ(varray[0], 5); @@ -98,7 +98,7 @@ TEST(virtual_array, VectorSet) TEST(virtual_array, Func) { auto func = [](int64_t index) { return (int)(index * index); }; - VArray_For_Func<int, decltype(func)> varray{10, func}; + VArray<int> varray = VArray<int>::ForFunc(10, func); EXPECT_EQ(varray.size(), 10); EXPECT_EQ(varray[0], 0); EXPECT_EQ(varray[3], 9); @@ -108,7 +108,7 @@ TEST(virtual_array, Func) TEST(virtual_array, AsSpan) { auto func = [](int64_t index) { return (int)(10 * index); }; - VArray_For_Func<int, decltype(func)> func_varray{10, func}; + VArray<int> func_varray = VArray<int>::ForFunc(10, func); VArray_Span span_varray{func_varray}; EXPECT_EQ(span_varray.size(), 10); Span<int> span = span_varray; @@ -134,13 +134,14 @@ TEST(virtual_array, DerivedSpan) vector.append({3, 4, 5}); vector.append({1, 1, 1}); { - VArray_For_DerivedSpan<std::array<int, 3>, int, get_x> varray{vector}; + VArray<int> varray = VArray<int>::ForDerivedSpan<std::array<int, 3>, get_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); } { - VMutableArray_For_DerivedSpan<std::array<int, 3>, int, get_x, set_x> varray{vector}; + VMutableArray<int> varray = + VMutableArray<int>::ForDerivedSpan<std::array<int, 3>, get_x, set_x>(vector); EXPECT_EQ(varray.size(), 2); EXPECT_EQ(varray[0], 3); EXPECT_EQ(varray[1], 1); @@ -151,4 +152,32 @@ TEST(virtual_array, DerivedSpan) } } +TEST(virtual_array, MutableToImmutable) +{ + std::array<int, 4> array = {4, 2, 6, 4}; + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + VArray<int> varray = mutable_varray; + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 4); + } + { + VMutableArray<int> mutable_varray = VMutableArray<int>::ForSpan(array); + EXPECT_EQ(mutable_varray.size(), 4); + VArray<int> varray = std::move(mutable_varray); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + EXPECT_EQ(mutable_varray.size(), 0); /* NOLINT: bugprone-use-after-move */ + } + { + VArray<int> varray = VMutableArray<int>::ForSpan(array); + EXPECT_TRUE(varray.is_span()); + EXPECT_EQ(varray.size(), 4); + EXPECT_EQ(varray[1], 2); + } +} + } // namespace blender::tests diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index 22182edd070..e3a8fd2bf3f 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -241,7 +241,7 @@ typedef enum eBLOLibLinkFlags { * #BLO_library_link_begin, #BLO_library_link_named_part & #BLO_library_link_end. * Wrap these in parameters since it's important both functions receive matching values. */ -struct LibraryLink_Params { +typedef struct LibraryLink_Params { /** The current main database, e.g. #G_MAIN or `CTX_data_main(C)`. */ struct Main *bmain; /** Options for linking, used for instantiating. */ @@ -257,7 +257,7 @@ struct LibraryLink_Params { /** The active 3D viewport (only used to define local-view). */ const struct View3D *v3d; } context; -}; +} LibraryLink_Params; void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 3306eb9e454..c0fdfa86907 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -347,6 +347,7 @@ LinkNode *BLO_blendhandle_get_previews(BlendHandle *bh, int ofblocktype, int *r_ case ID_GR: /* fall through */ case ID_SCE: /* fall through */ case ID_AC: /* fall through */ + case ID_NT: /* fall through */ new_prv = MEM_callocN(sizeof(PreviewImage), "newpreview"); BLI_linklist_prepend(&previews, new_prv); tot++; diff --git a/source/blender/blenloader/intern/versioning_300.c b/source/blender/blenloader/intern/versioning_300.c index 940a10a9e91..822ef2cda8d 100644 --- a/source/blender/blenloader/intern/versioning_300.c +++ b/source/blender/blenloader/intern/versioning_300.c @@ -1279,6 +1279,18 @@ static void version_geometry_nodes_set_position_node_offset(bNodeTree *ntree) } } +static void version_node_tree_socket_id_delim(bNodeTree *ntree) +{ + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { + version_node_socket_id_delim(socket); + } + LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { + version_node_socket_id_delim(socket); + } + } +} + static bool version_fix_seq_meta_range(Sequence *seq, void *user_data) { Scene *scene = (Scene *)user_data; @@ -2308,35 +2320,11 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } if (!MAIN_VERSION_ATLEAST(bmain, 300, 42)) { - /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, - * constraints and NLA tracks). */ - ID *id_iter; - FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { - version_liboverride_rnacollections_insertion_animdata(id_iter); - if (GS(id_iter->name) == ID_OB) { - version_liboverride_rnacollections_insertion_object((Object *)id_iter); - } - } - } - FOREACH_MAIN_ID_END; - /* Use consistent socket identifiers for the math node. * The code to make unique identifiers from the names was inconsistent. */ FOREACH_NODETREE_BEGIN (bmain, ntree, id) { - if (ELEM(ntree->type, NTREE_SHADER, NTREE_GEOMETRY)) { - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->type == SH_NODE_MATH) { - bNodeSocket *value1 = ((bNodeSocket *)node->inputs.first)->next; - bNodeSocket *value2 = value1->next; - strcpy(value1->identifier, "Value_001"); - if (value2 != NULL) { - /* This can be null when file is quite old so that the socket did not exist - * (before 0406eb110332a8). */ - strcpy(value2->identifier, "Value_002"); - } - } - } + if (ntree->type != NTREE_CUSTOM) { + version_node_tree_socket_id_delim(ntree); } } FOREACH_NODETREE_END; @@ -2357,6 +2345,25 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Change minimum zoom to 0.05f in the node editor. */ + LISTBASE_FOREACH (bScreen *, screen, &bmain->screens) { + LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { + LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { + if (sl->spacetype == SPACE_NODE) { + ListBase *regionbase = (sl == area->spacedata.first) ? &area->regionbase : + &sl->regionbase; + LISTBASE_FOREACH (ARegion *, region, regionbase) { + if (region->regiontype == RGN_TYPE_WINDOW) { + if (region->v2d.minzoom > 0.05f) { + region->v2d.minzoom = 0.05f; + } + } + } + } + } + } + } + LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { Editing *ed = SEQ_editing_get(scene); /* Make sure range of meta strips is correct. @@ -2369,6 +2376,24 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + /* Special case to handle older in-dev 3.1 files, before change from 3.0 branch gets merged in + * master. */ + if (!MAIN_VERSION_ATLEAST(bmain, 300, 42) || + (bmain->versionfile == 301 && !MAIN_VERSION_ATLEAST(bmain, 301, 3))) { + /* Update LibOverride operations regarding insertions in RNA collections (i.e. modifiers, + * constraints and NLA tracks). */ + ID *id_iter; + FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { + if (ID_IS_OVERRIDE_LIBRARY_REAL(id_iter)) { + version_liboverride_rnacollections_insertion_animdata(id_iter); + if (GS(id_iter->name) == ID_OB) { + version_liboverride_rnacollections_insertion_object((Object *)id_iter); + } + } + } + FOREACH_MAIN_ID_END; + } + /** * Versioning code until next subversion bump goes here. * @@ -2379,5 +2404,6 @@ void blo_do_versions_300(FileData *fd, Library *UNUSED(lib), Main *bmain) * \note Keep this message at the bottom of the function. */ { + /* Keep this block, even when empty. */ } } diff --git a/source/blender/blenloader/intern/versioning_common.cc b/source/blender/blenloader/intern/versioning_common.cc index c7ff496fa20..af765be619f 100644 --- a/source/blender/blenloader/intern/versioning_common.cc +++ b/source/blender/blenloader/intern/versioning_common.cc @@ -27,6 +27,7 @@ #include "BLI_listbase.h" #include "BLI_string.h" +#include "BLI_string_ref.hh" #include "BKE_animsys.h" #include "BKE_lib_id.h" @@ -37,6 +38,8 @@ #include "versioning_common.h" +using blender::StringRef; + ARegion *do_versions_add_region_if_not_found(ListBase *regionbase, int region_type, const char *name, @@ -101,6 +104,30 @@ static void change_node_socket_name(ListBase *sockets, const char *old_name, con } } +/** + * Convert `SocketName.001` unique name format to `SocketName_001`. Previously both were used. + */ +void version_node_socket_id_delim(bNodeSocket *socket) +{ + StringRef name = socket->name; + StringRef id = socket->identifier; + + if (!id.startswith(name)) { + /* We only need to affect the case where the identifier starts with the name. */ + return; + } + + StringRef id_number = id.drop_known_prefix(name); + if (id_number.is_empty()) { + /* The name was already unique, and didn't need numbers at the end for the id. */ + return; + } + + if (id_number.startswith(".")) { + socket->identifier[name.size()] = '_'; + } +} + void version_node_socket_name(bNodeTree *ntree, const int node_type, const char *old_name, @@ -127,9 +154,9 @@ void version_node_input_socket_name(bNodeTree *ntree, } void version_node_output_socket_name(bNodeTree *ntree, - const int node_type, - const char *old_name, - const char *new_name) + const int node_type, + const char *old_name, + const char *new_name) { LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->type == node_type) { diff --git a/source/blender/blenloader/intern/versioning_common.h b/source/blender/blenloader/intern/versioning_common.h index ed1cafdca33..7f179800ddd 100644 --- a/source/blender/blenloader/intern/versioning_common.h +++ b/source/blender/blenloader/intern/versioning_common.h @@ -62,6 +62,8 @@ void version_node_socket_index_animdata( void version_node_id(struct bNodeTree *ntree, const int node_type, const char *new_name); +void version_node_socket_id_delim(bNodeSocket *socket); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 809adc493f4..0e5e0b76f43 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -321,14 +321,22 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) btheme->space_node.grid_levels = 7; } - if (!USER_VERSION_ATLEAST(300, 40)) { + if (!USER_VERSION_ATLEAST(300, 41)) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } - if (!USER_VERSION_ATLEAST(300, 41)) { + /* Again reset the theme, but only if stored with an early 3.1 alpha version. Some changes were + * done in the release branch and then merged into the 3.1 branch (master). So the previous reset + * wouldn't work for people who saved their preferences with a 3.1 build meanwhile. But we still + * don't want to reset theme changes stored in the eventual 3.0 release once opened in a 3.1 + * build. */ + if (userdef->versionfile > 300 && !USER_VERSION_ATLEAST(301, 1)) { memcpy(btheme, &U_theme_default, sizeof(*btheme)); } + if (!USER_VERSION_ATLEAST(301, 2)) { + FROM_DEFAULT_V4_UCHAR(space_sequencer.mask); + } /** * Versioning code until next subversion bump goes here. * @@ -704,8 +712,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 38)) { - - /* (keep this block even if it becomes empty). */ copy_v4_fl4(userdef->light_param[0].vec, -0.580952, 0.228571, 0.781185, 0.0); copy_v4_fl4(userdef->light_param[0].col, 0.900000, 0.900000, 0.900000, 1.000000); copy_v4_fl4(userdef->light_param[0].spec, 0.318547, 0.318547, 0.318547, 1.000000); @@ -738,8 +744,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 41)) { - /* (keep this block even if it becomes empty). */ - if (userdef->pie_tap_timeout == 0) { userdef->pie_tap_timeout = 20; } @@ -796,7 +800,6 @@ void blo_do_versions_userdef(UserDef *userdef) } if (!USER_VERSION_ATLEAST(280, 62)) { - /* (keep this block even if it becomes empty). */ if (userdef->vbotimeout == 0) { userdef->vbocollectrate = 60; userdef->vbotimeout = 120; diff --git a/source/blender/blenloader/tests/blendfile_loading_base_test.cc b/source/blender/blenloader/tests/blendfile_loading_base_test.cc index 21156868655..a4a5ced070d 100644 --- a/source/blender/blenloader/tests/blendfile_loading_base_test.cc +++ b/source/blender/blenloader/tests/blendfile_loading_base_test.cc @@ -67,7 +67,6 @@ void BlendfileLoadingBaseTest::SetUpTestCase() BKE_idtype_init(); BKE_appdir_init(); IMB_init(); - BKE_images_init(); BKE_modifier_init(); DEG_register_node_types(); RNA_init(); diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index da4567d947b..f366aede2ab 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -85,7 +85,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) } if (ok) { - /* NOTE: in the case of multiple loops, this over-allocs (which is fine). */ + /* NOTE: in the case of multiple loops, this over-allocates (which is fine). */ BMVert **f_verts = MEM_mallocN(sizeof(*verts) * totv, __func__); BMIter eiter; diff --git a/source/blender/bmesh/tests/bmesh_core_test.cc b/source/blender/bmesh/tests/bmesh_core_test.cc index 202d16b09e3..3d6fabcbc2f 100644 --- a/source/blender/bmesh/tests/bmesh_core_test.cc +++ b/source/blender/bmesh/tests/bmesh_core_test.cc @@ -10,9 +10,9 @@ TEST(bmesh_core, BMVertCreate) BMVert *bv1, *bv2, *bv3; const float co1[3] = {1.0f, 2.0f, 0.0f}; - BMeshCreateParams bm_params; - bm_params.use_toolflags = true; - bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params); + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; + bm = BM_mesh_create(&bm_mesh_allocsize_default, &bmesh_create_params); EXPECT_EQ(bm->totvert, 0); /* make a custom layer so we can see if it is copied properly */ BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLOAT); diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cc b/source/blender/compositor/operations/COM_CompositorOperation.cc index 354997ebd2e..696dbb1807c 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cc +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc @@ -155,7 +155,7 @@ void CompositorOperation::execute_region(rcti *rect, unsigned int /*tile_number* if (rd->mode & R_BORDER && rd->mode & R_CROP) { /** * When using cropped render result, need to re-position area of interest, - * so it'll natch bounds of render border within frame. By default, canvas + * so it'll match bounds of render border within frame. By default, canvas * will be centered between full frame and cropped frame, so we use such * scheme to map cropped coordinates to full-frame coordinates * diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 0baf994d978..b8ca22d33d3 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -112,8 +112,9 @@ set(SRC intern/draw_view_data.cc intern/smaa_textures.c engines/basic/basic_engine.c - engines/image/image_engine.c - engines/image/image_shader.c + engines/basic/basic_shader.c + engines/image/image_engine.cc + engines/image/image_shader.cc engines/eevee/eevee_bloom.c engines/eevee/eevee_cryptomatte.c engines/eevee/eevee_data.c @@ -214,13 +215,14 @@ set(SRC intern/mesh_extractors/extract_mesh.h intern/smaa_textures.h engines/basic/basic_engine.h + engines/basic/basic_private.h engines/eevee/eevee_engine.h engines/eevee/eevee_lightcache.h engines/eevee/eevee_lut.h engines/eevee/eevee_private.h engines/external/external_engine.h engines/image/image_engine.h - engines/image/image_private.h + engines/image/image_private.hh engines/workbench/workbench_engine.h engines/workbench/workbench_private.h engines/select/select_engine.h diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index f4fdb9d0912..8a825a7c81f 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -36,17 +36,10 @@ #include "GPU_shader.h" #include "basic_engine.h" -/* Shaders */ +#include "basic_private.h" #define BASIC_ENGINE "BLENDER_BASIC" -extern char datatoc_depth_frag_glsl[]; -extern char datatoc_depth_vert_glsl[]; -extern char datatoc_conservative_depth_geom_glsl[]; - -extern char datatoc_common_view_lib_glsl[]; -extern char datatoc_common_pointcloud_lib_glsl[]; - /* *********** LISTS *********** */ /* GPUViewport.storage @@ -69,20 +62,8 @@ typedef struct BASIC_Data { BASIC_StorageList *stl; } BASIC_Data; -typedef struct BASIC_Shaders { - /* Depth Pre Pass */ - struct GPUShader *depth; - struct GPUShader *pointcloud_depth; - struct GPUShader *depth_conservative; - struct GPUShader *pointcloud_depth_conservative; -} BASIC_Shaders; - /* *********** STATIC *********** */ -static struct { - BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]; -} e_data = {{{NULL}}}; /* Engine data */ - typedef struct BASIC_PrivateData { DRWShadingGroup *depth_shgrp[2]; DRWShadingGroup *depth_shgrp_cull[2]; @@ -91,74 +72,6 @@ typedef struct BASIC_PrivateData { bool use_material_slot_selection; } BASIC_PrivateData; /* Transient data */ -/* Functions */ - -static void basic_engine_init(void *UNUSED(vedata)) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - - /* Depth prepass */ - if (!sh_data->depth) { - const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[draw_ctx->sh_cfg]; - - sh_data->depth = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, NULL}, - }); - - sh_data->pointcloud_depth = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_common_pointcloud_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, - "#define POINTCLOUD\n", - "#define INSTANCED_ATTR\n", - "#define UNIFORM_RESOURCE_ID\n", - NULL}, - }); - - sh_data->depth_conservative = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .geom = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_conservative_depth_geom_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, - }); - - sh_data->pointcloud_depth_conservative = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_common_pointcloud_lib_glsl, - datatoc_depth_vert_glsl, - NULL}, - .geom = (const char *[]){sh_cfg->lib, - datatoc_common_view_lib_glsl, - datatoc_conservative_depth_geom_glsl, - NULL}, - .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, - .defs = (const char *[]){sh_cfg->def, - "#define CONSERVATIVE_RASTER\n", - "#define POINTCLOUD\n", - "#define INSTANCED_ATTR\n", - "#define UNIFORM_RESOURCE_ID\n", - NULL}, - }); - } -} - static void basic_cache_init(void *vedata) { BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl; @@ -166,7 +79,6 @@ static void basic_cache_init(void *vedata) DRWShadingGroup *grp; const DRWContextState *draw_ctx = DRW_context_state_get(); - BASIC_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; if (!stl->g_data) { /* Alloc transient pointers */ @@ -181,24 +93,29 @@ static void basic_cache_init(void *vedata) DRWState infront_state = (DRW_state_is_select() && (i == 1)) ? DRW_STATE_IN_FRONT_SELECT : 0; DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - GPUShader *sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth; + GPUShader *sh = DRW_state_is_select() ? + BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg); DRW_PASS_CREATE(psl->depth_pass[i], state | clip_state | infront_state); stl->g_data->depth_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass[i]); DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1); - sh = DRW_state_is_select() ? sh_data->pointcloud_depth_conservative : sh_data->pointcloud_depth; + sh = DRW_state_is_select() ? + BASIC_shaders_pointcloud_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_pointcloud_depth_sh_get(draw_ctx->sh_cfg); DRW_PASS_CREATE(psl->depth_pass_pointcloud[i], state | clip_state | infront_state); - stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_pointcloud[i]); + stl->g_data->depth_pointcloud_shgrp[i] = grp = DRW_shgroup_create( + sh, psl->depth_pass_pointcloud[i]); DRW_shgroup_uniform_vec2(grp, "sizeViewport", DRW_viewport_size_get(), 1); DRW_shgroup_uniform_vec2(grp, "sizeViewportInv", DRW_viewport_invert_size_get(), 1); - stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create(sh_data->depth, - psl->depth_pass[i]); + stl->g_data->depth_hair_shgrp[i] = grp = DRW_shgroup_create( + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg), psl->depth_pass[i]); - - sh = DRW_state_is_select() ? sh_data->depth_conservative : sh_data->depth; + sh = DRW_state_is_select() ? BASIC_shaders_depth_conservative_sh_get(draw_ctx->sh_cfg) : + BASIC_shaders_depth_sh_get(draw_ctx->sh_cfg); state |= DRW_STATE_CULL_BACK; DRW_PASS_CREATE(psl->depth_pass_cull[i], state | clip_state | infront_state); stl->g_data->depth_shgrp_cull[i] = grp = DRW_shgroup_create(sh, psl->depth_pass_cull[i]); @@ -336,13 +253,7 @@ static void basic_draw_scene(void *vedata) static void basic_engine_free(void) { - for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { - BASIC_Shaders *sh_data = &e_data.sh_data[i]; - DRW_SHADER_FREE_SAFE(sh_data->depth); - DRW_SHADER_FREE_SAFE(sh_data->depth_conservative); - DRW_SHADER_FREE_SAFE(sh_data->pointcloud_depth); - DRW_SHADER_FREE_SAFE(sh_data->pointcloud_depth_conservative); - } + BASIC_shaders_free(); } static const DrawEngineDataSize basic_data_size = DRW_VIEWPORT_DATA_SIZE(BASIC_Data); @@ -352,7 +263,7 @@ DrawEngineType draw_engine_basic_type = { NULL, N_("Basic"), &basic_data_size, - &basic_engine_init, + NULL, &basic_engine_free, &basic_cache_init, &basic_cache_populate, diff --git a/source/blender/draw/engines/image/image_private.h b/source/blender/draw/engines/basic/basic_private.h index 76a94e68da1..e5f494bf0e7 100644 --- a/source/blender/draw/engines/image/image_private.h +++ b/source/blender/draw/engines/basic/basic_private.h @@ -24,45 +24,11 @@ extern "C" { #endif -/* Forward declarations */ -struct GPUTexture; -struct ImBuf; -struct Image; - -/* *********** LISTS *********** */ - -/* GPUViewport.storage - * Is freed every time the viewport engine changes. */ -typedef struct IMAGE_PassList { - DRWPass *image_pass; -} IMAGE_PassList; - -typedef struct IMAGE_PrivateData { - void *lock; - struct ImBuf *ibuf; - struct Image *image; - struct DRWView *view; - - struct GPUTexture *texture; - bool owns_texture; -} IMAGE_PrivateData; - -typedef struct IMAGE_StorageList { - IMAGE_PrivateData *pd; -} IMAGE_StorageList; - -typedef struct IMAGE_Data { - void *engine_type; - DRWViewportEmptyList *fbl; - DRWViewportEmptyList *txl; - IMAGE_PassList *psl; - IMAGE_StorageList *stl; -} IMAGE_Data; - -/* image_shader.c */ -GPUShader *IMAGE_shader_image_get(bool is_tiled_image); -void IMAGE_shader_library_ensure(void); -void IMAGE_shader_free(void); +GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config); +GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config); +void BASIC_shaders_free(void); #ifdef __cplusplus } diff --git a/source/blender/draw/engines/basic/basic_shader.c b/source/blender/draw/engines/basic/basic_shader.c new file mode 100644 index 00000000000..4b92406d5c0 --- /dev/null +++ b/source/blender/draw/engines/basic/basic_shader.c @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2019, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "GPU_shader.h" + +#include "basic_private.h" + +extern char datatoc_depth_frag_glsl[]; +extern char datatoc_depth_vert_glsl[]; +extern char datatoc_conservative_depth_geom_glsl[]; + +extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_pointcloud_lib_glsl[]; + +/* Shaders */ + +typedef struct BASIC_Shaders { + /* Depth Pre Pass */ + struct GPUShader *depth; + struct GPUShader *pointcloud_depth; + struct GPUShader *depth_conservative; + struct GPUShader *pointcloud_depth_conservative; +} BASIC_Shaders; + +static struct { + BASIC_Shaders sh_data[GPU_SHADER_CFG_LEN]; +} e_data = {{{NULL}}}; /* Engine data */ + +static GPUShader *BASIC_shader_create_depth_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, NULL}, + }); +} + +static GPUShader *BASIC_shader_create_pointcloud_depth_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_common_pointcloud_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define POINTCLOUD\n", + "#define INSTANCED_ATTR\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); +} + +static GPUShader *BASIC_shader_create_depth_conservative_sh(const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_conservative_depth_geom_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, "#define CONSERVATIVE_RASTER\n", NULL}, + }); +} + +static GPUShader *BASIC_shader_create_pointcloud_depth_conservative_sh( + const GPUShaderConfigData *sh_cfg) +{ + return GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_common_pointcloud_lib_glsl, + datatoc_depth_vert_glsl, + NULL}, + .geom = (const char *[]){sh_cfg->lib, + datatoc_common_view_lib_glsl, + datatoc_conservative_depth_geom_glsl, + NULL}, + .frag = (const char *[]){datatoc_depth_frag_glsl, NULL}, + .defs = (const char *[]){sh_cfg->def, + "#define CONSERVATIVE_RASTER\n", + "#define POINTCLOUD\n", + "#define INSTANCED_ATTR\n", + "#define UNIFORM_RESOURCE_ID\n", + NULL}, + }); +} + +GPUShader *BASIC_shaders_depth_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->depth == NULL) { + sh_data->depth = BASIC_shader_create_depth_sh(sh_cfg); + } + return sh_data->depth; +} + +GPUShader *BASIC_shaders_pointcloud_depth_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->pointcloud_depth == NULL) { + sh_data->pointcloud_depth = BASIC_shader_create_pointcloud_depth_sh(sh_cfg); + } + return sh_data->pointcloud_depth; +} + +GPUShader *BASIC_shaders_depth_conservative_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->depth_conservative == NULL) { + sh_data->depth_conservative = BASIC_shader_create_depth_conservative_sh(sh_cfg); + } + return sh_data->depth_conservative; +} + +GPUShader *BASIC_shaders_pointcloud_depth_conservative_sh_get(eGPUShaderConfig config) +{ + BASIC_Shaders *sh_data = &e_data.sh_data[config]; + const GPUShaderConfigData *sh_cfg = &GPU_shader_cfg_data[config]; + if (sh_data->pointcloud_depth_conservative == NULL) { + sh_data->pointcloud_depth_conservative = BASIC_shader_create_pointcloud_depth_conservative_sh( + sh_cfg); + } + return sh_data->pointcloud_depth_conservative; +} + +void BASIC_shaders_free(void) +{ + for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { + GPUShader **sh_data_as_array = (GPUShader **)&e_data.sh_data[i]; + for (int j = 0; j < (sizeof(BASIC_Shaders) / sizeof(GPUShader *)); j++) { + DRW_SHADER_FREE_SAFE(sh_data_as_array[j]); + } + } +} diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 93641443cac..41d6db7f726 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -56,7 +56,7 @@ vec2 get_ao_noise(void) { vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; /* Decorrelate noise from AA. */ - /* TODO(fclem) we should use a more general approach for more random number dimentions. */ + /* TODO(fclem) we should use a more general approach for more random number dimensions. */ noise = fract(noise * 6.1803402007); return noise; } @@ -399,7 +399,7 @@ float specular_occlusion( /* Use the right occlusion. */ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) { - /* Default to fully openned cone. */ + /* Default to fully opened cone. */ OcclusionData data = NO_OCCLUSION_DATA; #ifdef ENABLE_DEFERED_AO diff --git a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl index e5cbc487e93..311887cf2f5 100644 --- a/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/closure_eval_lib.glsl @@ -172,7 +172,7 @@ /* -------------------------------------------------------------------- */ /** \name Common cl_eval data * - * Eval data not dependant on input parameters. All might not be used but unused ones + * Eval data not dependent on input parameters. All might not be used but unused ones * will be optimized out. * \{ */ @@ -240,7 +240,7 @@ ClosureEvalCommon closure_Common_eval_init(ClosureInputCommon cl_in) /* -------------------------------------------------------------------- */ /** \name Loop data * - * Loop datas are conveniently packed into struct to make it future proof. + * Loop data is conveniently packed into struct to make it future proof. * \{ */ struct ClosureLightData { diff --git a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl index c3325ec4286..77a1560f3a7 100644 --- a/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_utiltex_lib.glsl @@ -79,7 +79,7 @@ vec2 btdf_lut(float cos_theta, float roughness, float ior) /* Baked IOR for GGX BRDF. */ const float specular = 1.0; const float eta_brdf = (2.0 / (1.0 - sqrt(0.08 * specular))) - 1.0; - /* Avoid harsh transition comming from ior == 1. */ + /* Avoid harsh transition coming from ior == 1. */ float f90 = fast_sqrt(saturate(f0 / (f0_from_ior(eta_brdf) * 0.25))); float fresnel = F_brdf_single_scatter(vec3(f0), vec3(f90), split_sum).r; /* Setting the BTDF to one is not really important since it is only used for multiscatter diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl index 39a7e8fb931..c09365cdcb4 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_gather_frag.glsl @@ -2,7 +2,7 @@ /** * Gather pass: Convolve foreground and background parts in separate passes. * - * Using the min&max CoC tile buffer, we select the best apropriate method to blur the scene color. + * Using the min&max CoC tile buffer, we select the best appropriate method to blur the scene color. * A fast gather path is taken if there is not many CoC variation inside the tile. * * We sample using an octaweb sampling pattern. We randomize the kernel center and each ring diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl index 1b5b305dfc1..d21254003f9 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_reduce_frag.glsl @@ -140,7 +140,7 @@ void main() do_scatter *= dof_scatter_screen_border_rejection(outCoc, uv, halfres); /* Only scatter if neighborhood is different enough. */ do_scatter *= dof_scatter_neighborhood_rejection(outColor.rgb); - /* For debuging. */ + /* For debugging. */ do_scatter *= float(!no_scatter_pass); outScatterColor = mix(vec3(0.0), outColor.rgb, do_scatter); diff --git a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl index 7689e730bf3..7568d70bd14 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_reflection_resolve_frag.glsl @@ -134,7 +134,7 @@ void raytrace_resolve(ClosureInputGlossy cl_in, vec3 V, P, N; if (planar_index != -1) { PlanarData pd = planars_data[planar_index]; - /* Evaluate everything in refected space. */ + /* Evaluate everything in reflected space. */ P = line_plane_intersect(cl_common.P, cl_common.V, pd.pl_plane_eq); V = reflect(cl_common.V, pd.pl_normal); N = reflect(cl_in.N, pd.pl_normal); diff --git a/source/blender/draw/engines/eevee/shaders/random_lib.glsl b/source/blender/draw/engines/eevee/shaders/random_lib.glsl index 3a4ae257bbe..c2388f61346 100644 --- a/source/blender/draw/engines/eevee/shaders/random_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/random_lib.glsl @@ -1,6 +1,6 @@ /** - * Random numbers and low discrepency sequences utilities. + * Random numbers and low discrepancy sequences utilities. */ #pragma BLENDER_REQUIRE(common_math_lib.glsl) diff --git a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl index 0efa7b80b0b..7d016d57c46 100644 --- a/source/blender/draw/engines/eevee/shaders/surface_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/surface_lib.glsl @@ -8,7 +8,7 @@ #if defined(STEP_RESOLVE) || defined(STEP_RAYTRACE) /* SSR will set these global variables itself. - * Also make false positive compiler warnings disapear by setting values. */ + * Also make false positive compiler warnings disappear by setting values. */ vec3 worldPosition = vec3(0); vec3 viewPosition = vec3(0); vec3 worldNormal = vec3(0); diff --git a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl index c48c3bffaef..777e48fde34 100644 --- a/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/volumetric_lib.glsl @@ -74,7 +74,7 @@ vec3 light_volume(LightData ld, vec4 l_vector) float d = l_vector.w; float d_sqr = sqr(d); float r_sqr = ld.l_volume_radius; - /* Using reformulation that has better numerical percision. */ + /* Using reformulation that has better numerical precision. */ power = 2.0 / (d_sqr + r_sqr + d * sqrt(d_sqr + r_sqr)); if (ld.l_type == AREA_RECT || ld.l_type == AREA_ELLIPSE) { diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.h b/source/blender/draw/engines/gpencil/gpencil_engine.h index 674aca29662..328e60cf60b 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.h +++ b/source/blender/draw/engines/gpencil/gpencil_engine.h @@ -106,7 +106,7 @@ typedef struct gpLight { BLI_STATIC_ASSERT_ALIGN(gpMaterial, 16) BLI_STATIC_ASSERT_ALIGN(gpLight, 16) -/* *********** Draw Datas *********** */ +/* *********** Draw Data *********** */ typedef struct GPENCIL_MaterialPool { /* Linklist. */ struct GPENCIL_MaterialPool *next; diff --git a/source/blender/draw/engines/image/image_drawing_mode.hh b/source/blender/draw/engines/image/image_drawing_mode.hh new file mode 100644 index 00000000000..d81b0971982 --- /dev/null +++ b/source/blender/draw/engines/image/image_drawing_mode.hh @@ -0,0 +1,153 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class DefaultDrawingMode : public AbstractDrawingMode { + private: + DRWPass *create_image_pass() const + { + /* Write depth is needed for background overlay rendering. Near depth is used for + * transparency checker and Far depth is used for indicating the image size. */ + DRWState state = static_cast<DRWState>(DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_ALWAYS | DRW_STATE_BLEND_ALPHA_PREMUL); + return DRW_pass_create("Image", state); + } + + void add_to_shgroup(AbstractSpaceAccessor *space, + DRWShadingGroup *grp, + const Image *image, + const ImBuf *image_buffer) const + { + float image_mat[4][4]; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const ARegion *region = draw_ctx->region; + space->get_image_mat(image_buffer, region, image_mat); + + GPUBatch *geom = DRW_cache_quad_get(); + + const bool is_tiled_texture = image && image->source == IMA_SRC_TILED; + if (is_tiled_texture) { + const float translate_x = image_mat[3][0]; + const float translate_y = image_mat[3][1]; + LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { + const int tile_x = ((tile->tile_number - 1001) % 10); + const int tile_y = ((tile->tile_number - 1001) / 10); + image_mat[3][0] = (float)tile_x + translate_x; + image_mat[3][1] = (float)tile_y + translate_y; + DRW_shgroup_call_obmat(grp, geom, image_mat); + } + } + else { + DRW_shgroup_call_obmat(grp, geom, image_mat); + } + } + + public: + void cache_init(IMAGE_Data *vedata) const override + { + IMAGE_PassList *psl = vedata->psl; + + psl->image_pass = create_image_pass(); + } + + void cache_image(AbstractSpaceAccessor *space, + IMAGE_Data *vedata, + Image *image, + ImageUser *iuser, + ImBuf *image_buffer) const override + { + IMAGE_PassList *psl = vedata->psl; + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + GPUTexture *tex_tile_data = nullptr; + space->get_gpu_textures( + image, iuser, image_buffer, &pd->texture, &pd->owns_texture, &tex_tile_data); + if (pd->texture == nullptr) { + return; + } + const bool is_tiled_texture = tex_tile_data != nullptr; + + ShaderParameters sh_params; + sh_params.use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image, + image_buffer); + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + if (scene->camera && scene->camera->type == OB_CAMERA) { + Camera *camera = static_cast<Camera *>(scene->camera->data); + copy_v2_fl2(sh_params.far_near, camera->clip_end, camera->clip_start); + } + space->get_shader_parameters(sh_params, image_buffer, is_tiled_texture); + + GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture); + DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass); + if (is_tiled_texture) { + DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, GPU_SAMPLER_DEFAULT); + DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data); + } + else { + DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, GPU_SAMPLER_DEFAULT); + } + DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", sh_params.far_near); + DRW_shgroup_uniform_vec4_copy(shgrp, "color", ShaderParameters::color); + DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", sh_params.shuffle); + DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", sh_params.flags); + DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", sh_params.use_premul_alpha); + + add_to_shgroup(space, shgrp, image, image_buffer); + } + + void draw_finish(IMAGE_Data *vedata) const override + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + if (pd->texture && pd->owns_texture) { + GPU_texture_free(pd->texture); + pd->owns_texture = false; + } + pd->texture = nullptr; + } + + void draw_scene(IMAGE_Data *vedata) const override + { + IMAGE_PassList *psl = vedata->psl; + IMAGE_PrivateData *pd = vedata->stl->pd; + + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + GPU_framebuffer_bind(dfbl->default_fb); + static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0); + + DRW_view_set_active(pd->view); + DRW_draw_pass(psl->image_pass); + DRW_view_set_active(nullptr); + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_engine.c b/source/blender/draw/engines/image/image_engine.c deleted file mode 100644 index 8b4acfbd5e3..00000000000 --- a/source/blender/draw/engines/image/image_engine.c +++ /dev/null @@ -1,459 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Copyright 2020, Blender Foundation. - */ - -/** \file - * \ingroup draw_editors - * - * Draw engine to draw the Image/UV editor - */ - -#include "DRW_render.h" - -#include "BKE_image.h" -#include "BKE_main.h" -#include "BKE_object.h" - -#include "DNA_camera_types.h" -#include "DNA_screen_types.h" - -#include "IMB_imbuf.h" -#include "IMB_imbuf_types.h" - -#include "ED_image.h" - -#include "GPU_batch.h" - -#include "image_engine.h" -#include "image_private.h" - -#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0) -#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1) -#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2) -#define IMAGE_DRAW_FLAG_DEPTH (1 << 3) -#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) -#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5) - -static void image_cache_image_add(DRWShadingGroup *grp, Image *image, ImBuf *ibuf) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - const ARegion *region = draw_ctx->region; - const char space_type = draw_ctx->space_data->spacetype; - - float zoom_x = 1.0f; - float zoom_y = 1.0f; - float translate_x = 0.0f; - float translate_y = 0.0f; - - /* User can freely move the backdrop in the space of the node editor */ - if (space_type == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)draw_ctx->space_data; - const float ibuf_width = ibuf->x; - const float ibuf_height = ibuf->y; - const float x = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof; - const float y = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof; - - zoom_x = ibuf_width * snode->zoom; - zoom_y = ibuf_height * snode->zoom; - translate_x = x; - translate_y = y; - } - - const bool is_tiled_texture = image && image->source == IMA_SRC_TILED; - float obmat[4][4]; - unit_m4(obmat); - - GPUBatch *geom = DRW_cache_quad_get(); - - obmat[0][0] = zoom_x; - obmat[1][1] = zoom_y; - obmat[3][1] = translate_y; - obmat[3][0] = translate_x; - - if (is_tiled_texture) { - LISTBASE_FOREACH (ImageTile *, tile, &image->tiles) { - const int tile_x = ((tile->tile_number - 1001) % 10); - const int tile_y = ((tile->tile_number - 1001) / 10); - obmat[3][1] = (float)tile_y + translate_y; - obmat[3][0] = (float)tile_x + translate_x; - DRW_shgroup_call_obmat(grp, geom, obmat); - } - } - else { - DRW_shgroup_call_obmat(grp, geom, obmat); - } -} - -static void space_image_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - if (image->rr != NULL) { - /* Update multi-index and pass for the current eye. */ - BKE_image_multilayer_index(image->rr, &sima->iuser); - } - else { - BKE_image_multiview_index(image, &sima->iuser); - } - - if (ibuf == NULL) { - return; - } - - if (ibuf->rect == NULL && ibuf->rect_float == NULL) { - /* This code-path is only supposed to happen when drawing a lazily-allocatable render result. - * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return NULL as - * an image buffer when it has no pixels. */ - - BLI_assert(image->type == IMA_TYPE_R_RESULT); - - float zero[4] = {0, 0, 0, 0}; - *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero); - *r_owns_texture = true; - return; - } - - const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); - if (sima_flag & SI_SHOW_ZBUF && (ibuf->zbuf || ibuf->zbuf_float || (ibuf->channels == 1))) { - if (ibuf->zbuf) { - BLI_assert_msg(0, "Integer based depth buffers not supported"); - } - else if (ibuf->zbuf_float) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->zbuf_float); - *r_owns_texture = true; - } - else if (ibuf->rect_float && ibuf->channels == 1) { - *r_gpu_texture = GPU_texture_create_2d( - __func__, ibuf->x, ibuf->y, 0, GPU_R16F, ibuf->rect_float); - *r_owns_texture = true; - } - } - else if (image->source == IMA_SRC_TILED) { - *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, ibuf); - *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, NULL); - *r_owns_texture = false; - } - else { - *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); - *r_owns_texture = false; - } -} - -static void space_node_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); - *r_owns_texture = false; - *r_tex_tile_data = NULL; -} - -static void image_gpu_texture_get(Image *image, - ImageUser *iuser, - ImBuf *ibuf, - GPUTexture **r_gpu_texture, - bool *r_owns_texture, - GPUTexture **r_tex_tile_data) -{ - if (!image) { - return; - } - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - - if (space_type == SPACE_IMAGE) { - space_image_gpu_texture_get( - image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data); - } - else if (space_type == SPACE_NODE) { - space_node_gpu_texture_get(image, iuser, ibuf, r_gpu_texture, r_owns_texture, r_tex_tile_data); - } -} - -static void image_cache_image(IMAGE_Data *vedata, Image *image, ImageUser *iuser, ImBuf *ibuf) -{ - IMAGE_PassList *psl = vedata->psl; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - const Scene *scene = draw_ctx->scene; - - GPUTexture *tex_tile_data = NULL; - image_gpu_texture_get(image, iuser, ibuf, &pd->texture, &pd->owns_texture, &tex_tile_data); - - if (pd->texture) { - static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - static float shuffle[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - static float far_near[2] = {100.0f, 0.0f}; - - if (scene->camera && scene->camera->type == OB_CAMERA) { - far_near[1] = ((Camera *)scene->camera->data)->clip_start; - far_near[0] = ((Camera *)scene->camera->data)->clip_end; - } - - const bool use_premul_alpha = BKE_image_has_gpu_texture_premultiplied_alpha(image, ibuf); - const bool is_tiled_texture = tex_tile_data != NULL; - - int draw_flags = 0; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(ibuf); - const bool do_repeat = (!is_tiled_texture) && ((sima->flag & SI_DRAW_TILE) != 0); - SET_FLAG_FROM_TEST(draw_flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT); - SET_FLAG_FROM_TEST(draw_flags, is_tiled_texture, IMAGE_DRAW_FLAG_USE_WORLD_POS); - if ((sima_flag & SI_USE_ALPHA) != 0) { - /* Show RGBA */ - draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - else if ((sima_flag & SI_SHOW_ALPHA) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f); - } - else if ((sima_flag & SI_SHOW_ZBUF) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); - } - else if ((sima_flag & SI_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); - } - else /* RGB */ { - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - } - } - if (space_type == SPACE_NODE) { - SpaceNode *snode = (SpaceNode *)draw_ctx->space_data; - if ((snode->flag & SNODE_USE_ALPHA) != 0) { - /* Show RGBA */ - draw_flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - copy_v4_fl4(shuffle, 0.0f, 0.0f, 0.0f, 1.0f); - } - else if ((snode->flag & SNODE_SHOW_R) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 1.0f, 0.0f, 0.0f, 0.0f); - } - else if ((snode->flag & SNODE_SHOW_G) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 1.0f, 0.0f, 0.0f); - } - else if ((snode->flag & SNODE_SHOW_B) != 0) { - draw_flags |= IMAGE_DRAW_FLAG_SHUFFLING; - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - copy_v4_fl4(shuffle, 0.0f, 0.0f, 1.0f, 0.0f); - } - else /* RGB */ { - if (IMB_alpha_affects_rgb(ibuf)) { - draw_flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; - } - } - } - - GPUShader *shader = IMAGE_shader_image_get(is_tiled_texture); - DRWShadingGroup *shgrp = DRW_shgroup_create(shader, psl->image_pass); - if (is_tiled_texture) { - DRW_shgroup_uniform_texture_ex(shgrp, "imageTileArray", pd->texture, 0); - DRW_shgroup_uniform_texture(shgrp, "imageTileData", tex_tile_data); - } - else { - DRW_shgroup_uniform_texture_ex(shgrp, "imageTexture", pd->texture, 0); - } - DRW_shgroup_uniform_vec2_copy(shgrp, "farNearDistances", far_near); - DRW_shgroup_uniform_vec4_copy(shgrp, "color", color); - DRW_shgroup_uniform_vec4_copy(shgrp, "shuffle", shuffle); - DRW_shgroup_uniform_int_copy(shgrp, "drawFlags", draw_flags); - DRW_shgroup_uniform_bool_copy(shgrp, "imgPremultiplied", use_premul_alpha); - image_cache_image_add(shgrp, image, ibuf); - } -} - -/* -------------------------------------------------------------------- */ -/** \name Engine Callbacks - * \{ */ - -static void IMAGE_engine_init(void *ved) -{ - IMAGE_shader_library_ensure(); - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - if (!stl->pd) { - stl->pd = MEM_callocN(sizeof(IMAGE_PrivateData), __func__); - } - IMAGE_PrivateData *pd = stl->pd; - - pd->ibuf = NULL; - pd->lock = NULL; - pd->texture = NULL; -} - -static void IMAGE_cache_init(void *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - IMAGE_PassList *psl = vedata->psl; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - { - /* Write depth is needed for background overlay rendering. Near depth is used for - * transparency checker and Far depth is used for indicating the image size. */ - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | - DRW_STATE_BLEND_ALPHA_PREMUL; - psl->image_pass = DRW_pass_create("Image", state); - } - - const SpaceLink *space_link = draw_ctx->space_data; - const char space_type = space_link->spacetype; - pd->view = NULL; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - Image *image = ED_space_image(sima); - ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &pd->lock, 0); - image_cache_image(vedata, image, &sima->iuser, ibuf); - pd->image = image; - pd->ibuf = ibuf; - } - else if (space_type == SPACE_NODE) { - ARegion *region = draw_ctx->region; - Main *bmain = CTX_data_main(draw_ctx->evil_C); - Image *image = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(image, NULL, &pd->lock); - { - /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */ - float winmat[4][4], viewmat[4][4]; - orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0); - unit_m4(winmat); - pd->view = DRW_view_create(viewmat, winmat, NULL, NULL, NULL); - } - image_cache_image(vedata, image, NULL, ibuf); - pd->image = image; - pd->ibuf = ibuf; - } -} - -static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob)) -{ - /* Function intentional left empty. `cache_populate` is required to be implemented. */ -} - -static void image_draw_finish(IMAGE_Data *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_StorageList *stl = vedata->stl; - IMAGE_PrivateData *pd = stl->pd; - const DRWContextState *draw_ctx = DRW_context_state_get(); - const char space_type = draw_ctx->space_data->spacetype; - if (space_type == SPACE_IMAGE) { - SpaceImage *sima = (SpaceImage *)draw_ctx->space_data; - ED_space_image_release_buffer(sima, pd->ibuf, pd->lock); - } - else if (space_type == SPACE_NODE) { - BKE_image_release_ibuf(pd->image, pd->ibuf, pd->lock); - } - pd->image = NULL; - pd->ibuf = NULL; - - if (pd->texture && pd->owns_texture) { - GPU_texture_free(pd->texture); - pd->owns_texture = false; - } - pd->texture = NULL; -} - -static void IMAGE_draw_scene(void *ved) -{ - IMAGE_Data *vedata = (IMAGE_Data *)ved; - IMAGE_PassList *psl = vedata->psl; - IMAGE_PrivateData *pd = vedata->stl->pd; - - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - GPU_framebuffer_bind(dfbl->default_fb); - static float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - GPU_framebuffer_clear_color_depth(dfbl->default_fb, clear_col, 1.0); - - DRW_view_set_active(pd->view); - DRW_draw_pass(psl->image_pass); - DRW_view_set_active(NULL); - image_draw_finish(vedata); -} - -static void IMAGE_engine_free(void) -{ - IMAGE_shader_free(); -} - -/** \} */ - -static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data); - -DrawEngineType draw_engine_image_type = { - NULL, /* next */ - NULL, /* prev */ - N_("UV/Image"), /* idname */ - &IMAGE_data_size, /* vedata_size */ - &IMAGE_engine_init, /* engine_init */ - &IMAGE_engine_free, /* engine_free */ - &IMAGE_cache_init, /* cache_init */ - &IMAGE_cache_populate, /* cache_populate */ - NULL, /* cache_finish */ - &IMAGE_draw_scene, /* draw_scene */ - NULL, /* view_update */ - NULL, /* id_update */ - NULL, /* render_to_image */ - NULL, /* store_metadata */ -}; diff --git a/source/blender/draw/engines/image/image_engine.cc b/source/blender/draw/engines/image/image_engine.cc new file mode 100644 index 00000000000..491fbec978b --- /dev/null +++ b/source/blender/draw/engines/image/image_engine.cc @@ -0,0 +1,197 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Draw engine to draw the Image/UV editor + */ + +#include "DRW_render.h" + +#include <memory> +#include <optional> + +#include "BKE_image.h" +#include "BKE_main.h" +#include "BKE_object.h" + +#include "DNA_camera_types.h" +#include "DNA_screen_types.h" + +#include "IMB_imbuf.h" +#include "IMB_imbuf_types.h" + +#include "ED_image.h" + +#include "GPU_batch.h" + +#include "image_drawing_mode.hh" +#include "image_engine.h" +#include "image_private.hh" +#include "image_space_image.hh" +#include "image_space_node.hh" + +namespace blender::draw::image_engine { + +static std::unique_ptr<AbstractSpaceAccessor> space_accessor_from_context( + const DRWContextState *draw_ctx) +{ + const char space_type = draw_ctx->space_data->spacetype; + if (space_type == SPACE_IMAGE) { + return std::make_unique<SpaceImageAccessor>((SpaceImage *)draw_ctx->space_data); + } + if (space_type == SPACE_NODE) { + return std::make_unique<SpaceNodeAccessor>((SpaceNode *)draw_ctx->space_data); + } + BLI_assert_unreachable(); + return nullptr; +} + +class ImageEngine { + private: + const DRWContextState *draw_ctx; + IMAGE_Data *vedata; + std::unique_ptr<AbstractSpaceAccessor> space; + DefaultDrawingMode drawing_mode; + + public: + ImageEngine(const DRWContextState *draw_ctx, IMAGE_Data *vedata) + : draw_ctx(draw_ctx), vedata(vedata), space(space_accessor_from_context(draw_ctx)) + { + } + + virtual ~ImageEngine() = default; + + void cache_init() + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + + drawing_mode.cache_init(vedata); + pd->view = nullptr; + if (space->has_view_override()) { + const ARegion *region = draw_ctx->region; + pd->view = space->create_view_override(region); + } + } + + void cache_populate() + { + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + Main *bmain = CTX_data_main(draw_ctx->evil_C); + pd->image = space->get_image(bmain); + if (pd->image == nullptr) { + /* Early exit, nothing to draw. */ + return; + } + pd->ibuf = space->acquire_image_buffer(pd->image, &pd->lock); + ImageUser *iuser = space->get_image_user(); + drawing_mode.cache_image(space.get(), vedata, pd->image, iuser, pd->ibuf); + } + + void draw_finish() + { + drawing_mode.draw_finish(vedata); + + IMAGE_StorageList *stl = vedata->stl; + IMAGE_PrivateData *pd = stl->pd; + space->release_buffer(pd->image, pd->ibuf, pd->lock); + pd->image = nullptr; + pd->ibuf = nullptr; + } + + void draw_scene() + { + drawing_mode.draw_scene(vedata); + } +}; + +/* -------------------------------------------------------------------- */ +/** \name Engine Callbacks + * \{ */ + +static void IMAGE_engine_init(void *ved) +{ + IMAGE_shader_library_ensure(); + IMAGE_Data *vedata = (IMAGE_Data *)ved; + IMAGE_StorageList *stl = vedata->stl; + if (!stl->pd) { + stl->pd = static_cast<IMAGE_PrivateData *>(MEM_callocN(sizeof(IMAGE_PrivateData), __func__)); + } + IMAGE_PrivateData *pd = stl->pd; + + pd->ibuf = nullptr; + pd->lock = nullptr; + pd->texture = nullptr; +} + +static void IMAGE_cache_init(void *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata)); + image_engine.cache_init(); + image_engine.cache_populate(); +} + +static void IMAGE_cache_populate(void *UNUSED(vedata), Object *UNUSED(ob)) +{ + /* Function intentional left empty. `cache_populate` is required to be implemented. */ +} + +static void IMAGE_draw_scene(void *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ImageEngine image_engine(draw_ctx, static_cast<IMAGE_Data *>(vedata)); + image_engine.draw_scene(); + image_engine.draw_finish(); +} + +static void IMAGE_engine_free() +{ + IMAGE_shader_free(); +} + +/** \} */ + +static const DrawEngineDataSize IMAGE_data_size = DRW_VIEWPORT_DATA_SIZE(IMAGE_Data); + +} // namespace blender::draw::image_engine + +extern "C" { + +using namespace blender::draw::image_engine; + +DrawEngineType draw_engine_image_type = { + nullptr, /* next */ + nullptr, /* prev */ + N_("UV/Image"), /* idname */ + &IMAGE_data_size, /* vedata_size */ + &IMAGE_engine_init, /* engine_init */ + &IMAGE_engine_free, /* engine_free */ + &IMAGE_cache_init, /* cache_init */ + &IMAGE_cache_populate, /* cache_populate */ + nullptr, /* cache_finish */ + &IMAGE_draw_scene, /* draw_scene */ + nullptr, /* view_update */ + nullptr, /* id_update */ + nullptr, /* render_to_image */ + nullptr, /* store_metadata */ +}; +} diff --git a/source/blender/draw/engines/image/image_engine.h b/source/blender/draw/engines/image/image_engine.h index 0098d863ef9..f7e2f53d41b 100644 --- a/source/blender/draw/engines/image/image_engine.h +++ b/source/blender/draw/engines/image/image_engine.h @@ -17,9 +17,17 @@ */ /** \file - * \ingroup draw_editors + * \ingroup draw_engine */ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + extern DrawEngineType draw_engine_image_type; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/draw/engines/image/image_private.hh b/source/blender/draw/engines/image/image_private.hh new file mode 100644 index 00000000000..a62cd882e40 --- /dev/null +++ b/source/blender/draw/engines/image/image_private.hh @@ -0,0 +1,196 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include <optional> + +/* Forward declarations */ +extern "C" { +struct GPUTexture; +struct ImBuf; +struct Image; +} + +/* *********** LISTS *********** */ + +namespace blender::draw::image_engine { + +/* GPUViewport.storage + * Is freed every time the viewport engine changes. */ +struct IMAGE_PassList { + DRWPass *image_pass; +}; + +struct IMAGE_PrivateData { + void *lock; + struct ImBuf *ibuf; + struct Image *image; + struct DRWView *view; + + struct GPUTexture *texture; + bool owns_texture; +}; + +struct IMAGE_StorageList { + IMAGE_PrivateData *pd; +}; + +struct IMAGE_Data { + void *engine_type; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; + IMAGE_PassList *psl; + IMAGE_StorageList *stl; +}; + +/* Shader parameters. */ +#define IMAGE_DRAW_FLAG_SHOW_ALPHA (1 << 0) +#define IMAGE_DRAW_FLAG_APPLY_ALPHA (1 << 1) +#define IMAGE_DRAW_FLAG_SHUFFLING (1 << 2) +#define IMAGE_DRAW_FLAG_DEPTH (1 << 3) +#define IMAGE_DRAW_FLAG_DO_REPEAT (1 << 4) +#define IMAGE_DRAW_FLAG_USE_WORLD_POS (1 << 5) + +struct ShaderParameters { + constexpr static float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + + int flags = 0; + float shuffle[4]; + float far_near[2]; + bool use_premul_alpha = false; + + ShaderParameters() + { + copy_v4_fl(shuffle, 1.0f); + copy_v2_fl2(far_near, 100.0f, 0.0f); + } +}; + +/** + * Space accessor. + * + * Image engine is used to draw the images inside multiple spaces \see SpaceLink. + * The AbstractSpaceAccessor is an interface to communicate with a space. + */ +class AbstractSpaceAccessor { + public: + virtual ~AbstractSpaceAccessor() = default; + + /** + * Return the active image of the space. + * + * The returned image will be drawn in the space. + * + * The return value is optional. + */ + virtual Image *get_image(Main *bmain) = 0; + + /** + * Return the #ImageUser of the space. + * + * The return value is optional. + */ + virtual ImageUser *get_image_user() = 0; + + /** + * Acquire the image buffer of the image. + * + * \param image: Image to get the buffer from. Image is the same as returned from the #get_image + * member. + * \param lock: pointer to a lock object. + * \return Image buffer of the given image. + */ + virtual ImBuf *acquire_image_buffer(Image *image, void **lock) = 0; + + /** + * Release a previous locked image from #acquire_image_buffer. + */ + virtual void release_buffer(Image *image, ImBuf *image_buffer, void *lock) = 0; + + /** + * Update the r_shader_parameters with space specific settings. + * + * Only update the #ShaderParameters.flags and #ShaderParameters.shuffle. Other parameters + * are updated inside the image engine. + */ + virtual void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *image_buffer, + bool is_tiled) = 0; + + /** + * Retrieve the gpu textures to draw. + */ + virtual void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *image_buffer, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) = 0; + + /** + * Does this space override the view. + * When so this member should return true and the create_view_override must return the view to + * use during drawing. + */ + virtual bool has_view_override() const = 0; + + /** + * Override the view for drawing. + * Should match #has_view_override. + */ + virtual DRWView *create_view_override(const ARegion *UNUSED(region)) = 0; + + /** + * Initialize the matrix that will be used to draw the image. The matrix will be send as object + * matrix to the drawing pipeline. + */ + virtual void get_image_mat(const ImBuf *image_buffer, + const ARegion *region, + float r_mat[4][4]) const = 0; +}; // namespace blender::draw::image_engine + +/** + * Abstract class for a drawing mode of the image engine. + * + * The drawing mode decides how to draw the image on the screen. Each way how to draw would have + * its own subclass. For now there is only a single drawing mode. #DefaultDrawingMode. + **/ +class AbstractDrawingMode { + public: + virtual ~AbstractDrawingMode() = default; + virtual void cache_init(IMAGE_Data *vedata) const = 0; + virtual void cache_image(AbstractSpaceAccessor *space, + IMAGE_Data *vedata, + Image *image, + ImageUser *iuser, + ImBuf *image_buffer) const = 0; + virtual void draw_scene(IMAGE_Data *vedata) const = 0; + virtual void draw_finish(IMAGE_Data *vedata) const = 0; +}; + +/* image_shader.c */ +GPUShader *IMAGE_shader_image_get(bool is_tiled_image); +void IMAGE_shader_library_ensure(void); +void IMAGE_shader_free(void); + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_shader.c b/source/blender/draw/engines/image/image_shader.cc index 691c0d7029a..1c6abf36505 100644 --- a/source/blender/draw/engines/image/image_shader.c +++ b/source/blender/draw/engines/image/image_shader.cc @@ -27,27 +27,31 @@ #include "GPU_batch.h" #include "image_engine.h" -#include "image_private.h" +#include "image_private.hh" +extern "C" { extern char datatoc_common_colormanagement_lib_glsl[]; extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_engine_image_frag_glsl[]; extern char datatoc_engine_image_vert_glsl[]; +} + +namespace blender::draw::image_engine { -typedef struct IMAGE_Shaders { +struct IMAGE_Shaders { GPUShader *image_sh[2]; -} IMAGE_Shaders; +}; static struct { IMAGE_Shaders shaders; DRWShaderLibrary *lib; -} e_data = {{{0}}}; /* Engine data */ +} e_data = {{{nullptr}}}; /* Engine data */ -void IMAGE_shader_library_ensure(void) +void IMAGE_shader_library_ensure() { - if (e_data.lib == NULL) { + if (e_data.lib == nullptr) { e_data.lib = DRW_shader_library_create(); /* NOTE: These need to be ordered by dependencies. */ DRW_SHADER_LIB_ADD(e_data.lib, common_colormanagement_lib); @@ -60,18 +64,18 @@ GPUShader *IMAGE_shader_image_get(bool is_tiled_image) { const int index = is_tiled_image ? 1 : 0; IMAGE_Shaders *sh_data = &e_data.shaders; - if (!sh_data->image_sh[index]) { + if (sh_data->image_sh[index] == nullptr) { sh_data->image_sh[index] = DRW_shader_create_with_shaderlib( datatoc_engine_image_vert_glsl, - NULL, + nullptr, datatoc_engine_image_frag_glsl, e_data.lib, - is_tiled_image ? "#define TILED_IMAGE\n" : NULL); + is_tiled_image ? "#define TILED_IMAGE\n" : nullptr); } return sh_data->image_sh[index]; } -void IMAGE_shader_free(void) +void IMAGE_shader_free() { GPUShader **sh_data_as_array = (GPUShader **)&e_data.shaders; for (int i = 0; i < (sizeof(IMAGE_Shaders) / sizeof(GPUShader *)); i++) { @@ -80,3 +84,5 @@ void IMAGE_shader_free(void) DRW_SHADER_LIB_FREE_SAFE(e_data.lib); } + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_space_image.hh b/source/blender/draw/engines/image/image_space_image.hh new file mode 100644 index 00000000000..7728a963254 --- /dev/null +++ b/source/blender/draw/engines/image/image_space_image.hh @@ -0,0 +1,182 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class SpaceImageAccessor : public AbstractSpaceAccessor { + SpaceImage *sima; + + public: + SpaceImageAccessor(SpaceImage *sima) : sima(sima) + { + } + + Image *get_image(Main *UNUSED(bmain)) override + { + return ED_space_image(sima); + } + + ImageUser *get_image_user() override + { + return &sima->iuser; + } + + ImBuf *acquire_image_buffer(Image *UNUSED(image), void **lock) override + { + return ED_space_image_acquire_buffer(sima, lock, 0); + } + + void release_buffer(Image *UNUSED(image), ImBuf *image_buffer, void *lock) override + { + ED_space_image_release_buffer(sima, image_buffer, lock); + } + + void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *image_buffer, + bool is_tiled) override + { + const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer); + const bool do_repeat = (!is_tiled) && ((sima->flag & SI_DRAW_TILE) != 0); + SET_FLAG_FROM_TEST(r_shader_parameters.flags, do_repeat, IMAGE_DRAW_FLAG_DO_REPEAT); + SET_FLAG_FROM_TEST(r_shader_parameters.flags, is_tiled, IMAGE_DRAW_FLAG_USE_WORLD_POS); + if ((sima_flag & SI_USE_ALPHA) != 0) { + /* Show RGBA */ + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + else if ((sima_flag & SI_SHOW_ALPHA) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f); + } + else if ((sima_flag & SI_SHOW_ZBUF) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_DEPTH | IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_R) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_G) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f); + } + else if ((sima_flag & SI_SHOW_B) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f); + } + else /* RGB */ { + if (IMB_alpha_affects_rgb(image_buffer)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + } + } + + bool has_view_override() const override + { + return false; + } + DRWView *create_view_override(const ARegion *UNUSED(region)) override + { + return nullptr; + } + + void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *image_buffer, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) override + { + if (image->rr != nullptr) { + /* Update multi-index and pass for the current eye. */ + BKE_image_multilayer_index(image->rr, iuser); + } + else { + BKE_image_multiview_index(image, iuser); + } + + if (image_buffer == nullptr) { + return; + } + + if (image_buffer->rect == nullptr && image_buffer->rect_float == nullptr) { + /* This code-path is only supposed to happen when drawing a lazily-allocatable render result. + * In all the other cases the `ED_space_image_acquire_buffer()` is expected to return nullptr + * as an image buffer when it has no pixels. */ + + BLI_assert(image->type == IMA_TYPE_R_RESULT); + + float zero[4] = {0, 0, 0, 0}; + *r_gpu_texture = GPU_texture_create_2d(__func__, 1, 1, 0, GPU_RGBA16F, zero); + *r_owns_texture = true; + return; + } + + const int sima_flag = sima->flag & ED_space_image_get_display_channel_mask(image_buffer); + if (sima_flag & SI_SHOW_ZBUF && + (image_buffer->zbuf || image_buffer->zbuf_float || (image_buffer->channels == 1))) { + if (image_buffer->zbuf) { + BLI_assert_msg(0, "Integer based depth buffers not supported"); + } + else if (image_buffer->zbuf_float) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->zbuf_float); + *r_owns_texture = true; + } + else if (image_buffer->rect_float && image_buffer->channels == 1) { + *r_gpu_texture = GPU_texture_create_2d( + __func__, image_buffer->x, image_buffer->y, 0, GPU_R16F, image_buffer->rect_float); + *r_owns_texture = true; + } + } + else if (image->source == IMA_SRC_TILED) { + *r_gpu_texture = BKE_image_get_gpu_tiles(image, iuser, image_buffer); + *r_tex_tile_data = BKE_image_get_gpu_tilemap(image, iuser, nullptr); + *r_owns_texture = false; + } + else { + *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, image_buffer); + *r_owns_texture = false; + } + } + + void get_image_mat(const ImBuf *UNUSED(image_buffer), + const ARegion *UNUSED(region), + float r_mat[4][4]) const override + { + unit_m4(r_mat); + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/image/image_space_node.hh b/source/blender/draw/engines/image/image_space_node.hh new file mode 100644 index 00000000000..3ca18eec742 --- /dev/null +++ b/source/blender/draw/engines/image/image_space_node.hh @@ -0,0 +1,138 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * Copyright 2021, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#pragma once + +#include "image_private.hh" + +namespace blender::draw::image_engine { + +class SpaceNodeAccessor : public AbstractSpaceAccessor { + SpaceNode *snode; + + public: + SpaceNodeAccessor(SpaceNode *snode) : snode(snode) + { + } + + Image *get_image(Main *bmain) override + { + return BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); + } + + ImageUser *get_image_user() override + { + return nullptr; + } + + ImBuf *acquire_image_buffer(Image *image, void **lock) override + { + return BKE_image_acquire_ibuf(image, nullptr, lock); + } + + void release_buffer(Image *image, ImBuf *ibuf, void *lock) override + { + BKE_image_release_ibuf(image, ibuf, lock); + } + + bool has_view_override() const override + { + return true; + } + + DRWView *create_view_override(const ARegion *region) override + { + /* Setup a screen pixel view. The backdrop of the node editor doesn't follow the region. */ + float winmat[4][4], viewmat[4][4]; + orthographic_m4(viewmat, 0.0, region->winx, 0.0, region->winy, 0.0, 1.0); + unit_m4(winmat); + return DRW_view_create(viewmat, winmat, nullptr, nullptr, nullptr); + } + + void get_shader_parameters(ShaderParameters &r_shader_parameters, + ImBuf *ibuf, + bool UNUSED(is_tiled)) override + { + if ((snode->flag & SNODE_USE_ALPHA) != 0) { + /* Show RGBA */ + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHOW_ALPHA | IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + else if ((snode->flag & SNODE_SHOW_ALPHA) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 0.0f, 1.0f); + } + else if ((snode->flag & SNODE_SHOW_R) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 1.0f, 0.0f, 0.0f, 0.0f); + } + else if ((snode->flag & SNODE_SHOW_G) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 1.0f, 0.0f, 0.0f); + } + else if ((snode->flag & SNODE_SHOW_B) != 0) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_SHUFFLING; + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + copy_v4_fl4(r_shader_parameters.shuffle, 0.0f, 0.0f, 1.0f, 0.0f); + } + else /* RGB */ { + if (IMB_alpha_affects_rgb(ibuf)) { + r_shader_parameters.flags |= IMAGE_DRAW_FLAG_APPLY_ALPHA; + } + } + } + + void get_gpu_textures(Image *image, + ImageUser *iuser, + ImBuf *ibuf, + GPUTexture **r_gpu_texture, + bool *r_owns_texture, + GPUTexture **r_tex_tile_data) override + { + *r_gpu_texture = BKE_image_get_gpu_texture(image, iuser, ibuf); + *r_owns_texture = false; + *r_tex_tile_data = nullptr; + } + + void get_image_mat(const ImBuf *image_buffer, + const ARegion *region, + float r_mat[4][4]) const override + { + unit_m4(r_mat); + const float ibuf_width = image_buffer->x; + const float ibuf_height = image_buffer->y; + + r_mat[0][0] = ibuf_width * snode->zoom; + r_mat[1][1] = ibuf_height * snode->zoom; + r_mat[3][0] = (region->winx - snode->zoom * ibuf_width) / 2 + snode->xof; + r_mat[3][1] = (region->winy - snode->zoom * ibuf_height) / 2 + snode->yof; + } +}; + +} // namespace blender::draw::image_engine diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl index 92d5df1a13a..c4580e6ffc3 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_dof_frag.glsl @@ -95,7 +95,7 @@ void main() /** * ----------------- STEP 0.5 ------------------ - * Custom Coc aware downsampling. Quater res pass. + * Custom Coc aware downsampling. Quarter res pass. */ #ifdef DOWNSAMPLE diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 59ed5316c02..1c7e8bd8ad6 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1368,11 +1368,11 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) } /* update a viewport which belongs to a GPUOffscreen */ -void DRW_notify_view_update_offscreen(struct Depsgraph *depsgraph, - RenderEngineType *engine_type, - ARegion *region, - View3D *v3d, - GPUViewport *viewport) +static void DRW_notify_view_update_offscreen(struct Depsgraph *depsgraph, + RenderEngineType *engine_type, + ARegion *region, + View3D *v3d, + GPUViewport *viewport) { if (viewport && GPU_viewport_do_update(viewport)) { diff --git a/source/blender/draw/tests/shaders_test.cc b/source/blender/draw/tests/shaders_test.cc index a9810b4cc77..ef702821a59 100644 --- a/source/blender/draw/tests/shaders_test.cc +++ b/source/blender/draw/tests/shaders_test.cc @@ -13,15 +13,18 @@ #include "intern/draw_manager_testing.h" +#include "engines/basic/basic_private.h" #include "engines/eevee/eevee_private.h" #include "engines/gpencil/gpencil_engine.h" -#include "engines/image/image_private.h" +#include "engines/image/image_private.hh" #include "engines/overlay/overlay_private.h" #include "engines/workbench/workbench_private.h" #include "intern/draw_shader.h" namespace blender::draw { +using namespace blender::draw::image_engine; + static void test_workbench_glsl_shaders() { workbench_shader_library_ensure(); @@ -394,4 +397,17 @@ static void test_draw_glsl_shaders() } DRAW_TEST(draw_glsl_shaders) +static void test_basic_glsl_shaders() +{ + for (int i = 0; i < GPU_SHADER_CFG_LEN; i++) { + eGPUShaderConfig sh_cfg = static_cast<eGPUShaderConfig>(i); + BASIC_shaders_depth_sh_get(sh_cfg); + BASIC_shaders_pointcloud_depth_sh_get(sh_cfg); + BASIC_shaders_depth_conservative_sh_get(sh_cfg); + BASIC_shaders_pointcloud_depth_conservative_sh_get(sh_cfg); + } + BASIC_shaders_free(); +} +DRAW_TEST(basic_glsl_shaders) + } // namespace blender::draw diff --git a/source/blender/editors/animation/anim_channels_defines.c b/source/blender/editors/animation/anim_channels_defines.c index e5dc9a83ebb..9f2681fbf7a 100644 --- a/source/blender/editors/animation/anim_channels_defines.c +++ b/source/blender/editors/animation/anim_channels_defines.c @@ -199,7 +199,7 @@ static void acf_generic_channel_color(bAnimContext *ac, bAnimListElem *ale, floa } /* set color for normal channels - * - use 3 shades of color group/standard color for 3 indention level + * - use 3 shades of color group/standard color for 3 indentation level * - only use group colors if allowed to, and if actually feasible */ if (showGroupColors && (grp) && (grp->customCol)) { diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 6fe32699907..05837ed17b9 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -145,6 +145,22 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) } } } + /* For node sockets, it is useful to include the node name as well (multiple similar nodes + * are not distinguishable otherwise). Unfortunately, the node label cannot be retrieved + * from the rna path, for this to work access to the underlying node is needed (but finding + * the node iterates all nodes & sockets which would result in bad performance in some + * circumstances). */ + if (RNA_struct_is_a(ptr.type, &RNA_NodeSocket)) { + char nodename[256]; + if (BLI_str_quoted_substr(fcu->rna_path, "nodes[", nodename, sizeof(nodename))) { + const char *structname_all = BLI_sprintfN("%s : %s", nodename, structname); + if (free_structname) { + MEM_freeN((void *)structname); + } + structname = structname_all; + free_structname = 1; + } + } } /* Property Name is straightforward */ diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c index 0d812198d04..335034fef6e 100644 --- a/source/blender/editors/animation/anim_motion_paths.c +++ b/source/blender/editors/animation/anim_motion_paths.c @@ -176,11 +176,11 @@ static void motionpaths_calc_bake_targets(ListBase *targets, int cframe) copy_v3_v3(mpv->co, pchan_eval->pose_tail); } - /* result must be in worldspace */ + /* Result must be in world-space. */ mul_m4_v3(ob_eval->obmat, mpv->co); } else { - /* worldspace object location */ + /* World-space object location. */ copy_v3_v3(mpv->co, ob_eval->obmat[3]); } diff --git a/source/blender/editors/armature/armature_relations.c b/source/blender/editors/armature/armature_relations.c index 32fd1c9ad41..b06e4b6a9e7 100644 --- a/source/blender/editors/armature/armature_relations.c +++ b/source/blender/editors/armature/armature_relations.c @@ -745,6 +745,10 @@ void ARMATURE_OT_separate(wmOperatorType *ot) #define ARM_PAR_CONNECT 1 #define ARM_PAR_OFFSET 2 +/* armature un-parenting options */ +#define ARM_PAR_CLEAR 1 +#define ARM_PAR_CLEAR_DISCONNECT 2 + /* check for null, before calling! */ static void bone_connect_to_existing_parent(EditBone *bone) { @@ -904,19 +908,29 @@ static int armature_parent_set_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event)) { - bool all_childbones = false; + /* False when all selected bones are parented to the active bone. */ + bool enable_offset = false; + /* False when all selected bones are connected to the active bone. */ + bool enable_connect = false; { Object *ob = CTX_data_edit_object(C); bArmature *arm = ob->data; EditBone *actbone = arm->act_edbone; LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { - if (EBONE_EDITABLE(ebone) && (ebone->flag & BONE_SELECTED)) { - if (ebone != actbone) { - if (ebone->parent != actbone) { - all_childbones = true; - break; - } - } + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone == actbone) { + continue; + } + + if (ebone->parent != actbone) { + enable_offset = true; + enable_connect = true; + break; + } + if (!(ebone->flag & BONE_CONNECTED)) { + enable_connect = true; } } } @@ -924,11 +938,14 @@ static int armature_parent_set_invoke(bContext *C, uiPopupMenu *pup = UI_popup_menu_begin( C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Make Parent"), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); - if (all_childbones) { - /* Object becomes parent, make the associated menus. */ - uiItemEnumO(layout, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); - } + + uiLayout *row_offset = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_offset, enable_offset); + uiItemEnumO(row_offset, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_OFFSET); + + uiLayout *row_connect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_connect, enable_connect); + uiItemEnumO(row_connect, "ARMATURE_OT_parent_set", NULL, 0, "type", ARM_PAR_CONNECT); UI_popup_menu_end(C, pup); @@ -955,8 +972,8 @@ void ARMATURE_OT_parent_set(wmOperatorType *ot) } static const EnumPropertyItem prop_editarm_clear_parent_types[] = { - {1, "CLEAR", 0, "Clear Parent", ""}, - {2, "DISCONNECT", 0, "Disconnect Bone", ""}, + {ARM_PAR_CLEAR, "CLEAR", 0, "Clear Parent", ""}, + {ARM_PAR_CLEAR_DISCONNECT, "DISCONNECT", 0, "Disconnect Bone", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1012,6 +1029,51 @@ static int armature_parent_clear_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int armature_parent_clear_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(event)) +{ + /* False when no selected bones are connected to the active bone. */ + bool enable_disconnect = false; + /* False when no selected bones are parented to the active bone. */ + bool enable_clear = false; + { + Object *ob = CTX_data_edit_object(C); + bArmature *arm = ob->data; + LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { + if (!EBONE_EDITABLE(ebone) || !(ebone->flag & BONE_SELECTED)) { + continue; + } + if (ebone->parent == NULL) { + continue; + } + enable_clear = true; + + if (ebone->flag & BONE_CONNECTED) { + enable_disconnect = true; + break; + } + } + } + + uiPopupMenu *pup = UI_popup_menu_begin( + C, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Clear Parent"), ICON_NONE); + uiLayout *layout = UI_popup_menu_layout(pup); + + uiLayout *row_clear = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_clear, enable_clear); + uiItemEnumO(row_clear, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR); + + uiLayout *row_disconnect = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row_disconnect, enable_disconnect); + uiItemEnumO( + row_disconnect, "ARMATURE_OT_parent_clear", NULL, 0, "type", ARM_PAR_CLEAR_DISCONNECT); + + UI_popup_menu_end(C, pup); + + return OPERATOR_INTERFACE; +} + void ARMATURE_OT_parent_clear(wmOperatorType *ot) { /* identifiers */ @@ -1021,7 +1083,7 @@ void ARMATURE_OT_parent_clear(wmOperatorType *ot) "Remove the parent-child relationship between selected bones and their parents"; /* api callbacks */ - ot->invoke = WM_menu_invoke; + ot->invoke = armature_parent_clear_invoke; ot->exec = armature_parent_clear_exec; ot->poll = ED_operator_editarmature; diff --git a/source/blender/editors/armature/pose_transform.c b/source/blender/editors/armature/pose_transform.c index 279f79ac44b..70d6fa93104 100644 --- a/source/blender/editors/armature/pose_transform.c +++ b/source/blender/editors/armature/pose_transform.c @@ -797,13 +797,13 @@ static int pose_copy_exec(bContext *C, wmOperator *op) BLI_addtail(&temp_bmain->objects, &ob_copy); BLI_addtail(&temp_bmain->armatures, &arm_copy); /* begin copy buffer on a temp bmain. */ - BKE_copybuffer_begin(temp_bmain); + BKE_copybuffer_copy_begin(temp_bmain); /* Store the whole object to the copy buffer because pose can't be * existing on its own. */ - BKE_copybuffer_tag_ID(&ob_copy.id); + BKE_copybuffer_copy_tag_ID(&ob_copy.id); BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer_pose.blend"); - BKE_copybuffer_save(temp_bmain, str, op->reports); + BKE_copybuffer_copy_end(temp_bmain, str, op->reports); /* We clear the lists so no datablocks gets freed, * This is required because objects in temp bmain shares same pointers * as the real ones. diff --git a/source/blender/editors/asset/ED_asset_list.hh b/source/blender/editors/asset/ED_asset_list.hh index dcc07f54e75..24def2fb4ab 100644 --- a/source/blender/editors/asset/ED_asset_list.hh +++ b/source/blender/editors/asset/ED_asset_list.hh @@ -35,4 +35,4 @@ std::string ED_assetlist_asset_filepath_get(const bContext *C, /* Can return false to stop iterating. */ using AssetListIterFn = blender::FunctionRef<bool(AssetHandle)>; -void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn); +void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn); diff --git a/source/blender/editors/asset/intern/asset_catalog.cc b/source/blender/editors/asset/intern/asset_catalog.cc index 8e1e5be2e47..9634665be7b 100644 --- a/source/blender/editors/asset/intern/asset_catalog.cc +++ b/source/blender/editors/asset/intern/asset_catalog.cc @@ -19,7 +19,6 @@ */ #include "BKE_asset_catalog.hh" -#include "BKE_asset_catalog_path.hh" #include "BKE_asset_library.hh" #include "BKE_main.h" diff --git a/source/blender/editors/asset/intern/asset_filter.cc b/source/blender/editors/asset/intern/asset_filter.cc index 329342a30cd..c22bbc923eb 100644 --- a/source/blender/editors/asset/intern/asset_filter.cc +++ b/source/blender/editors/asset/intern/asset_filter.cc @@ -22,7 +22,6 @@ #include "BLI_listbase.h" -#include "DNA_ID.h" #include "DNA_asset_types.h" #include "ED_asset_filter.h" diff --git a/source/blender/editors/asset/intern/asset_handle.cc b/source/blender/editors/asset/intern/asset_handle.cc index 5c8d0b1349c..363bd9226da 100644 --- a/source/blender/editors/asset/intern/asset_handle.cc +++ b/source/blender/editors/asset/intern/asset_handle.cc @@ -26,7 +26,6 @@ #include <string> -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BLO_readfile.h" diff --git a/source/blender/editors/asset/intern/asset_library_reference_enum.cc b/source/blender/editors/asset/intern/asset_library_reference_enum.cc index 5a83893f8e1..102b2a97859 100644 --- a/source/blender/editors/asset/intern/asset_library_reference_enum.cc +++ b/source/blender/editors/asset/intern/asset_library_reference_enum.cc @@ -27,7 +27,6 @@ #include "BKE_preferences.h" -#include "DNA_asset_types.h" #include "DNA_userdef_types.h" #include "UI_resources.h" diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 4bc15e842fc..c1b1e33d428 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -32,7 +32,6 @@ #include "BLI_path_util.h" #include "BLI_utility_mixins.hh" -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BKE_preferences.h" @@ -40,7 +39,6 @@ #include "ED_fileselect.h" #include "WM_api.h" -#include "WM_types.h" /* XXX uses private header of file-space. */ #include "../space_file/filelist.h" @@ -458,9 +456,9 @@ bool ED_assetlist_storage_has_list_for_library(const AssetLibraryReference *libr return AssetListStorage::lookup_list(*library_reference) != nullptr; } -void ED_assetlist_iterate(const AssetLibraryReference *library_reference, AssetListIterFn fn) +void ED_assetlist_iterate(const AssetLibraryReference &library_reference, AssetListIterFn fn) { - AssetList *list = AssetListStorage::lookup_list(*library_reference); + AssetList *list = AssetListStorage::lookup_list(library_reference); if (list) { list->iterate(fn); } diff --git a/source/blender/editors/asset/intern/asset_mark_clear.cc b/source/blender/editors/asset/intern/asset_mark_clear.cc index a0a2c63b407..2e5bdb63359 100644 --- a/source/blender/editors/asset/intern/asset_mark_clear.cc +++ b/source/blender/editors/asset/intern/asset_mark_clear.cc @@ -20,9 +20,6 @@ * Functions for marking and clearing assets. */ -#include <memory> -#include <string> - #include "DNA_ID.h" #include "BKE_asset.h" @@ -32,8 +29,6 @@ #include "BKE_lib_id.h" #include "BKE_main.h" -#include "BLO_readfile.h" - #include "UI_interface_icons.h" #include "RNA_access.h" diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index 41cca71b323..a228b275558 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -18,8 +18,6 @@ * \ingroup edasset */ -#include "BKE_asset.h" -#include "BKE_asset_catalog.hh" #include "BKE_asset_library.hh" #include "BKE_bpath.h" #include "BKE_context.h" @@ -32,11 +30,7 @@ #include "BLI_fileops.h" #include "BLI_fnmatch.h" #include "BLI_path_util.h" -#include "BLI_string_ref.hh" -#include "BLI_vector.hh" - #include "ED_asset.h" -#include "ED_asset_catalog.hh" #include "ED_util.h" /* XXX needs access to the file list, should all be done via the asset system in future. */ #include "ED_fileselect.h" @@ -45,7 +39,6 @@ #include "RNA_define.h" #include "WM_api.h" -#include "WM_types.h" #include "DNA_space_types.h" diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index f664eab5cbb..f136c08f129 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -23,7 +23,6 @@ #include <new> -#include "DNA_asset_types.h" #include "DNA_space_types.h" #include "BKE_report.h" diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 46bf1f6c9b5..3b05975d22d 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4909,7 +4909,9 @@ bool ED_curve_editnurb_select_pick( /** \name Spin Operator * \{ */ -/* 'cent' is in object space and 'dvec' in worldspace. +/** + * \param axis: is in world-space. + * \param cent: is in object-space. */ bool ed_editnurb_spin( float viewmat[4][4], View3D *v3d, Object *obedit, const float axis[3], const float cent[3]) diff --git a/source/blender/editors/curve/editcurve_paint.c b/source/blender/editors/curve/editcurve_paint.c index 26906b0ddcd..784f67ac4f1 100644 --- a/source/blender/editors/curve/editcurve_paint.c +++ b/source/blender/editors/curve/editcurve_paint.c @@ -102,7 +102,7 @@ struct CurveDrawData { /* offset projection by this value */ bool use_offset; - float offset[3]; /* worldspace */ + float offset[3]; /* world-space */ float surface_offset; bool use_surface_offset_absolute; } project; diff --git a/source/blender/editors/curve/editfont.c b/source/blender/editors/curve/editfont.c index 1b44cf88db1..6f18798bd2a 100644 --- a/source/blender/editors/curve/editfont.c +++ b/source/blender/editors/curve/editfont.c @@ -2155,8 +2155,8 @@ void FONT_OT_open(wmOperatorType *ot) FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, - FILE_DEFAULTDISPLAY, - FILE_SORT_DEFAULT); + FILE_IMGDISPLAY, + FILE_SORT_ALPHA); } /** \} */ diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index ba603cdd6ec..bf53241a947 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -123,6 +123,8 @@ typedef struct tGPsdata { ARegion *region; /** needed for GP_STROKE_2DSPACE. */ View2D *v2d; + /** For operations that require occlusion testing. */ + ViewDepths *depths; /** for using the camera rect within the 3d view. */ rctf *subrect; rctf subrect_data; @@ -972,12 +974,13 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points"); + const ViewDepths *depths = p->depths; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1086,7 +1089,10 @@ static bool annotation_stroke_eraser_is_occluded(tGPsdata *p, const int mval_i[2] = {x, y}; float mval_3d[3]; - if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) { + float p_depth; + if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) { + ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d); + const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d); const float depth_pt = ED_view3d_calc_depth_for_comparison(rv3d, &pt->x); @@ -1189,7 +1195,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p, /* Second Pass: Remove any points that are tagged */ if (do_cull) { BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } } @@ -1211,7 +1217,8 @@ static void annotation_stroke_doeraser(tGPsdata *p) if (p->flags & GP_PAINTFLAG_V3D_ERASER_DEPTH) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + ED_view3d_depth_override( + p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths); } } @@ -1499,6 +1506,9 @@ static void annotation_session_cleanup(tGPsdata *p) static void annotation_session_free(tGPsdata *p) { + if (p->depths) { + ED_view3d_depths_free(p->depths); + } MEM_freeN(p); } diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 406a7ac77fc..656fec565df 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1834,7 +1834,7 @@ static int image_to_gpencil_exec(bContext *C, wmOperator *op) /* Delete any selected point. */ LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } BKE_reportf(op->reports, RPT_INFO, "Object created"); diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index a77d3bee025..db2104dfdf9 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1321,78 +1321,102 @@ void GPENCIL_OT_layer_isolate(wmOperatorType *ot) } /* ********************** Merge Layer with the next layer **************************** */ +enum { + GP_LAYER_MERGE_ACTIVE = 0, + GP_LAYER_MERGE_ALL = 1, +}; -static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) +static void apply_layer_settings(bGPDlayer *gpl) { - bGPdata *gpd = ED_gpencil_data_get_active(C); - bGPDlayer *gpl_src = BKE_gpencil_layer_active_get(gpd); - bGPDlayer *gpl_dst = gpl_src->prev; + /* Apply layer attributes. */ + LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { + LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) { + gps->fill_opacity_fac *= gpl->opacity; + gps->vert_color_fill[3] *= gpl->opacity; + for (int p = 0; p < gps->totpoints; p++) { + bGPDspoint *pt = &gps->points[p]; + float factor = (((float)gps->thickness * pt->pressure) + (float)gpl->line_change) / + ((float)gps->thickness * pt->pressure); + pt->pressure *= factor; + pt->strength *= gpl->opacity; - if (ELEM(NULL, gpd, gpl_dst, gpl_src)) { - BKE_report(op->reports, RPT_ERROR, "No layers to merge"); - return OPERATOR_CANCELLED; + /* Layer transformation. */ + mul_v3_m4v3(&pt->x, gpl->layer_mat, &pt->x); + zero_v3(gpl->location); + zero_v3(gpl->rotation); + copy_v3_fl(gpl->scale, 1.0f); + } + } } - /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */ - GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64); - LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) { - BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); - } + gpl->line_change = 0; + gpl->opacity = 1.0f; + unit_m4(gpl->layer_mat); + invert_m4_m4(gpl->layer_invmat, gpl->layer_mat); +} - /* Read all frames from merge layer and add any missing in destination layer, - * copying all previous strokes to keep the image equals. - * Need to do it in a separated loop to avoid strokes accumulation. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - /* Try to find frame in destination layer hash table. */ - bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); - if (!gpf_dst) { - gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); - /* Use same frame type. */ - gpf_dst->key_type = gpf_src->key_type; - BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); - } - } +static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + bGPDlayer *gpl_active = BKE_gpencil_layer_active_get(gpd); + bGPDlayer *gpl_dst = gpl_active->prev; + const int mode = RNA_enum_get(op->ptr, "mode"); - /* Read all frames from merge layer and add strokes. */ - LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { - /* Try to find frame in destination layer hash table. */ - bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); - /* Apply layer transformation. */ - LISTBASE_FOREACH (bGPDstroke *, gps_src, &gpf_src->strokes) { - for (int p = 0; p < gps_src->totpoints; p++) { - bGPDspoint *pt = &gps_src->points[p]; - mul_v3_m4v3(&pt->x, gpl_src->layer_mat, &pt->x); - } + if (mode == GP_LAYER_MERGE_ACTIVE) { + if (ELEM(NULL, gpd, gpl_dst, gpl_active)) { + BKE_report(op->reports, RPT_ERROR, "No layers to merge"); + return OPERATOR_CANCELLED; } - - /* Add to tail all strokes. */ - if (gpf_dst) { - BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); + } + else { + if (ELEM(NULL, gpd, gpl_active)) { + BKE_report(op->reports, RPT_ERROR, "No layers to flatten"); + return OPERATOR_CANCELLED; } } - /* Add Masks to destination layer. */ - LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) { - /* Don't add merged layers or missing layer names. */ - if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) || - STREQ(mask->name, gpl_dst->info)) { - continue; + if (mode == GP_LAYER_MERGE_ACTIVE) { + /* Apply destination layer attributes. */ + apply_layer_settings(gpl_active); + ED_gpencil_layer_merge(gpd, gpl_active, gpl_dst, false); + } + else if (mode == GP_LAYER_MERGE_ALL) { + /* Apply layer attributes to all layers. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + apply_layer_settings(gpl); } - if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) { - bGPDlayer_Mask *mask_new = MEM_dupallocN(mask); - BLI_addtail(&gpl_dst->mask_layers, mask_new); - gpl_dst->act_mask++; + gpl_dst = gpl_active; + /* Merge layers on top of active layer. */ + if (gpd->layers.last != gpl_dst) { + LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) { + if (gpl == gpl_dst) { + break; + } + ED_gpencil_layer_merge(gpd, gpl, gpl->prev, false); + } } + /* Merge layers below active layer. */ + LISTBASE_FOREACH_BACKWARD_MUTABLE (bGPDlayer *, gpl, &gpd->layers) { + if (gpl == gpl_dst) { + continue; + } + ED_gpencil_layer_merge(gpd, gpl, gpl_dst, true); + } + /* Set general layers settings to default values. */ + gpl_active->blend_mode = eGplBlendMode_Regular; + gpl_active->flag &= ~GP_LAYER_LOCKED; + gpl_active->flag &= ~GP_LAYER_HIDE; + gpl_active->flag |= GP_LAYER_USE_LIGHTS; + gpl_active->onion_flag |= GP_LAYER_ONIONSKIN; + } + else { + return OPERATOR_CANCELLED; } - /* Set destination layer as active. */ - BKE_gpencil_layer_active_set(gpd, gpl_dst); - - /* Now delete next layer */ - BKE_gpencil_layer_delete(gpd, gpl_src); - BLI_ghash_free(gh_frames_dst, NULL, NULL); - /* Reorder masking. */ - BKE_gpencil_layer_mask_sort(gpd, gpl_dst); + /* Clear any invalid mask. Some other layer could be using the merged layer. */ + LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) { + BKE_gpencil_layer_mask_cleanup(gpd, gpl); + } /* notifiers */ DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); @@ -1404,10 +1428,16 @@ static int gpencil_merge_layer_exec(bContext *C, wmOperator *op) void GPENCIL_OT_layer_merge(wmOperatorType *ot) { + static const EnumPropertyItem merge_modes[] = { + {GP_LAYER_MERGE_ACTIVE, "ACTIVE", 0, "Active", "Combine active layer into the layer below"}, + {GP_LAYER_MERGE_ALL, "ALL", 0, "All", "Combine all layers into the active layer"}, + {0, NULL, 0, NULL, NULL}, + }; + /* identifiers */ ot->name = "Merge Down"; ot->idname = "GPENCIL_OT_layer_merge"; - ot->description = "Merge the current layer with the layer below"; + ot->description = "Combine Layers"; /* callbacks */ ot->exec = gpencil_merge_layer_exec; @@ -1415,6 +1445,8 @@ void GPENCIL_OT_layer_merge(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + ot->prop = RNA_def_enum(ot->srna, "mode", merge_modes, GP_LAYER_MERGE_ACTIVE, "Mode", ""); } /* ********************** Change Layer ***************************** */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f6012883e1f..3fc08096ab5 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -2635,7 +2635,7 @@ static int gpencil_delete_selected_points(bContext *C) else { /* delete unwanted points by splitting stroke into several smaller ones */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } changed = true; @@ -4656,11 +4656,11 @@ static int gpencil_stroke_separate_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, 0); + gpd_dst, gpf_dst, gps_dst, NULL, GP_SPOINT_SELECT, false, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd_src, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } /* selected strokes mode */ @@ -4839,11 +4839,11 @@ static int gpencil_stroke_split_exec(bContext *C, wmOperator *op) /* delete selected points from destination stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, 0); + gpd, gpf, gps_dst, NULL, GP_SPOINT_SELECT, true, false, 0); /* delete selected points from origin stroke */ BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, 0); + gpd, gpf, gps, gps->next, GP_SPOINT_SELECT, false, false, 0); } } } @@ -5039,7 +5039,7 @@ static void gpencil_cutter_dissolve(bGPdata *gpd, } BKE_gpencil_stroke_delete_tagged_points( - gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, 1); + gpd, hit_layer->actframe, hit_stroke, gpsn, GP_SPOINT_TAG, false, flat_caps, 1); } } diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 1b69947b294..9860c75f290 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -127,6 +127,8 @@ typedef struct tGPDfill { struct bGPDstroke *gps_mouse; /** Pointer to report messages. */ struct ReportList *reports; + /** For operations that require occlusion testing. */ + struct ViewDepths *depths; /** flags */ short flag; /** avoid too fast events */ @@ -1374,7 +1376,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) /* need to restore the original projection settings before packing up */ view3d_region_operator_needs_opengl(tgpf->win, tgpf->region); ED_view3d_depth_override( - tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + tgpf->depsgraph, tgpf->region, tgpf->v3d, NULL, V3D_DEPTH_NO_GPENCIL, &tgpf->depths); /* Since strokes are so fine, when using their depth we need a margin * otherwise they might get missed. */ @@ -1385,6 +1387,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) int interp_depth = 0; int found_depth = 0; + const ViewDepths *depths = tgpf->depths; tgpf->depth_arr = MEM_mallocN(sizeof(float) * totpoints, "depth_points"); for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { @@ -1392,11 +1395,9 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) int mval_i[2]; round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(tgpf->region, mval_i, depth_margin, tgpf->depth_arr + i) == - 0) && - (i && - (ED_view3d_autodist_depth_seg( - tgpf->region, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, tgpf->depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1771,6 +1772,11 @@ static void gpencil_fill_exit(bContext *C, wmOperator *op) ED_region_draw_cb_exit(tgpf->region->type, tgpf->draw_handle_3d); } + /* Remove depth buffer in cache. */ + if (tgpf->depths) { + ED_view3d_depths_free(tgpf->depths); + } + /* finally, free memory used by temp data */ MEM_freeN(tgpf); } diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index b6730cb123b..3f3fd4fff39 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -155,6 +155,8 @@ typedef struct tGPDprimitive { struct Material *material; /** current brush */ struct Brush *brush; + /** For operations that require occlusion testing. */ + struct ViewDepths *depths; /** Settings to pass to gp_points_to_xy(). */ GP_SpaceConversion gsc; diff --git a/source/blender/editors/gpencil/gpencil_merge.c b/source/blender/editors/gpencil/gpencil_merge.c index 259b2882589..925c2e1cd7f 100644 --- a/source/blender/editors/gpencil/gpencil_merge.c +++ b/source/blender/editors/gpencil/gpencil_merge.c @@ -182,7 +182,8 @@ static void gpencil_dissolve_points(bContext *C) } LISTBASE_FOREACH_MUTABLE (bGPDstroke *, gps, &gpf->strokes) { - BKE_gpencil_stroke_delete_tagged_points(gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + BKE_gpencil_stroke_delete_tagged_points( + gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } } CTX_DATA_END; diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 3e9f22f25d3..f0118988559 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -161,6 +161,8 @@ typedef struct tGPsdata { ARegion *region; /** needed for GP_STROKE_2DSPACE. */ View2D *v2d; + /** For operations that require occlusion testing. */ + ViewDepths *depths; /** for using the camera rect within the 3d view. */ rctf *subrect; rctf subrect_data; @@ -1090,14 +1092,16 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) int found_depth = 0; depth_arr = MEM_mallocN(sizeof(float) * gpd->runtime.sbuffer_used, "depth_points"); + + const ViewDepths *depths = p->depths; int i; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(p->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - p->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1346,7 +1350,10 @@ static bool gpencil_stroke_eraser_is_occluded( /* calculate difference matrix if parent object */ BKE_gpencil_layer_transform_matrix_get(p->depsgraph, obact, gpl, diff_mat); - if (ED_view3d_autodist_simple(p->region, mval_i, mval_3d, 0, NULL)) { + float p_depth; + if (ED_view3d_depth_read_cached(p->depths, mval_i, 0, &p_depth)) { + ED_view3d_depth_unproject_v3(p->region, mval_i, (double)p_depth, mval_3d); + const float depth_mval = ED_view3d_calc_depth_for_comparison(rv3d, mval_3d); mul_v3_m4v3(fpt, diff_mat, &pt->x); @@ -1692,7 +1699,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } BKE_gpencil_stroke_delete_tagged_points( - p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, 0); + p->gpd, gpf, gps, gps->next, GP_SPOINT_TAG, false, false, 0); } gpencil_update_cache(p->gpd); } @@ -1733,7 +1740,7 @@ static void gpencil_stroke_doeraser(tGPsdata *p) if ((gp_settings != NULL) && (gp_settings->flag & GP_BRUSH_OCCLUDE_ERASER)) { View3D *v3d = p->area->spacedata.first; view3d_region_operator_needs_opengl(p->win, p->region); - ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, NULL); + ED_view3d_depth_override(p->depsgraph, p->region, v3d, NULL, V3D_DEPTH_NO_GPENCIL, &p->depths); } /* loop over all layers too, since while it's easy to restrict editing to @@ -2087,6 +2094,9 @@ static void gpencil_session_free(tGPsdata *p) if (p->rng != NULL) { BLI_rng_free(p->rng); } + if (p->depths != NULL) { + ED_view3d_depths_free(p->depths); + } MEM_freeN(p); } @@ -2267,8 +2277,9 @@ static void gpencil_paint_initstroke(tGPsdata *p, static void gpencil_paint_strokeend(tGPsdata *p) { ToolSettings *ts = p->scene->toolsettings; - /* for surface sketching, need to set the right OpenGL context stuff so that - * the conversions will project the values correctly... + const bool is_eraser = (p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) != 0; + /* for surface sketching, need to set the right OpenGL context stuff so + * that the conversions will project the values correctly... */ if (gpencil_project_check(p)) { View3D *v3d = p->area->spacedata.first; @@ -2282,11 +2293,11 @@ static void gpencil_paint_strokeend(tGPsdata *p) (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? V3D_DEPTH_GPENCIL_ONLY : V3D_DEPTH_NO_GPENCIL, - NULL); + is_eraser ? NULL : &p->depths); } /* check if doing eraser or not */ - if ((p->gpd->runtime.sbuffer_sflag & GP_STROKE_ERASER) == 0) { + if (!is_eraser) { /* transfer stroke to frame */ gpencil_stroke_newfrombuffer(p); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index f8cfc130e35..7382aca9a87 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -795,15 +795,16 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? V3D_DEPTH_GPENCIL_ONLY : V3D_DEPTH_NO_GPENCIL, - NULL); + &tgpi->depths); depth_arr = MEM_mallocN(sizeof(float) * gps->totpoints, "depth_points"); + const ViewDepths *depths = tgpi->depths; tGPspoint *ptc = &points2D[0]; for (int i = 0; i < gps->totpoints; i++, ptc++) { round_v2i_v2fl(mval_i, &ptc->x); - if ((ED_view3d_autodist_depth(tgpi->region, mval_i, depth_margin, depth_arr + i) == 0) && - (i && (ED_view3d_autodist_depth_seg( - tgpi->region, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { + if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && + (i && (ED_view3d_depth_read_cached_seg( + depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { interp_depth = true; } else { @@ -1154,6 +1155,11 @@ static void gpencil_primitive_exit(bContext *C, wmOperator *op) BLI_rng_free(tgpi->rng); } + /* Remove depth buffer in cache. */ + if (tgpi->depths) { + ED_view3d_depths_free(tgpi->depths); + } + MEM_freeN(tgpi); } diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index d3640c6eebd..86df452f49a 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -979,7 +979,7 @@ bool gpencil_point_xy_to_3d(const GP_SpaceConversion *gsc, * to 3D coordinates. * * \param point2D: The screen-space 2D point data to convert. - * \param depth: Depth array (via #ED_view3d_autodist_depth()). + * \param depth: Depth array (via #ED_view3d_depth_read_cached()). * \param r_out: The resulting 2D point data. */ void gpencil_stroke_convertcoords_tpoint(Scene *scene, @@ -3372,7 +3372,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim( } /* Remove tagged points to trim stroke. */ gps_final = BKE_gpencil_stroke_delete_tagged_points( - gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, 0); + gpd, gpf, gps_dst, gps_dst->next, GP_SPOINT_TAG, false, false, 0); } /* Join both strokes. */ @@ -3415,3 +3415,71 @@ void ED_gpencil_stroke_close_by_distance(bGPDstroke *gps, const float threshold) BKE_gpencil_stroke_close(gps); } } + +/* Merge two layers. */ +void ED_gpencil_layer_merge(bGPdata *gpd, + bGPDlayer *gpl_src, + bGPDlayer *gpl_dst, + const bool reverse) +{ + /* Collect frames of gpl_dst in hash table to avoid O(n^2) lookups. */ + GHash *gh_frames_dst = BLI_ghash_int_new_ex(__func__, 64); + LISTBASE_FOREACH (bGPDframe *, gpf_dst, &gpl_dst->frames) { + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_dst->framenum), gpf_dst); + } + + /* Read all frames from merge layer and add any missing in destination layer, + * copying all previous strokes to keep the image equals. + * Need to do it in a separated loop to avoid strokes accumulation. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + if (!gpf_dst) { + gpf_dst = BKE_gpencil_layer_frame_get(gpl_dst, gpf_src->framenum, GP_GETFRAME_ADD_COPY); + /* Use same frame type. */ + gpf_dst->key_type = gpf_src->key_type; + BLI_ghash_insert(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum), gpf_dst); + } + } + + /* Read all frames from merge layer and add strokes. */ + LISTBASE_FOREACH (bGPDframe *, gpf_src, &gpl_src->frames) { + /* Try to find frame in destination layer hash table. */ + bGPDframe *gpf_dst = BLI_ghash_lookup(gh_frames_dst, POINTER_FROM_INT(gpf_src->framenum)); + /* Add to tail all strokes. */ + if (gpf_dst) { + if (reverse) { + BLI_movelisttolist_reverse(&gpf_dst->strokes, &gpf_src->strokes); + } + else { + BLI_movelisttolist(&gpf_dst->strokes, &gpf_src->strokes); + } + } + } + + /* Add Masks to destination layer. */ + LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl_src->mask_layers) { + /* Don't add merged layers or missing layer names. */ + if (!BKE_gpencil_layer_named_get(gpd, mask->name) || STREQ(mask->name, gpl_src->info) || + STREQ(mask->name, gpl_dst->info)) { + continue; + } + if (!BKE_gpencil_layer_mask_named_get(gpl_dst, mask->name)) { + bGPDlayer_Mask *mask_new = MEM_dupallocN(mask); + BLI_addtail(&gpl_dst->mask_layers, mask_new); + gpl_dst->act_mask++; + } + } + + /* Set destination layer as active. */ + BKE_gpencil_layer_active_set(gpd, gpl_dst); + + /* Now delete merged layer. */ + BKE_gpencil_layer_delete(gpd, gpl_src); + BLI_ghash_free(gh_frames_dst, NULL, NULL); + + /* Reorder masking. */ + if (gpl_dst->mask_layers.first) { + BKE_gpencil_layer_mask_sort(gpd, gpl_dst); + } +} diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c index 5c3a7cf9e6f..891bd3ca5ec 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_ops.c +++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c @@ -54,7 +54,7 @@ static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -1142,7 +1142,7 @@ void GPENCIL_OT_stroke_reset_vertex_color(wmOperatorType *ot) static EnumPropertyItem mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Reset Vertex Color to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 21d8a28e2c9..4fa78eddec4 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -65,7 +65,7 @@ struct ImBuf *ED_space_clip_get_stable_buffer(struct SpaceClip *sc, float *angle); bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]); bool ED_space_clip_color_sample(struct SpaceClip *sc, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index c760b661373..1cf15ce3a48 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -205,6 +205,11 @@ void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode) bool ED_gpencil_layer_frames_delete(struct bGPDlayer *gpl); void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl); +void ED_gpencil_layer_merge(struct bGPdata *gpd, + struct bGPDlayer *gpl_src, + struct bGPDlayer *gpl_dst, + const bool reverse); + void ED_gpencil_layer_frames_keytype_set(struct bGPDlayer *gpl, short type); void ED_gpencil_layer_snap_frames(struct bGPDlayer *gpl, struct Scene *scene, short mode); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index ef3ff7874df..eee119c0712 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -31,6 +31,8 @@ #include "DNA_object_enums.h" +#include "WM_types.h" + #include "BLI_compiler_attrs.h" #ifdef __cplusplus @@ -380,7 +382,7 @@ struct bUserMenu *ED_screen_user_menu_ensure(struct bContext *C); struct bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(struct ListBase *lb, const struct wmOperatorType *ot, struct IDProperty *prop, - short opcontext); + wmOperatorCallContext opcontext); struct bUserMenuItem_Menu *ED_screen_user_menu_item_find_menu(struct ListBase *lb, const struct MenuType *mt); struct bUserMenuItem_Prop *ED_screen_user_menu_item_find_prop(struct ListBase *lb, @@ -392,7 +394,7 @@ void ED_screen_user_menu_item_add_operator(struct ListBase *lb, const char *ui_name, const struct wmOperatorType *ot, const struct IDProperty *prop, - short opcontext); + wmOperatorCallContext opcontext); void ED_screen_user_menu_item_add_menu(struct ListBase *lb, const char *ui_name, const struct MenuType *mt); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 8e19628ec87..008ad5b3203 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -588,8 +588,6 @@ float ED_view3d_radius_to_dist(const struct View3D *v3d, const bool use_aspect, const float radius); -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], unsigned int pos); - /* Back-buffer select and draw support. */ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist); @@ -609,12 +607,8 @@ bool ED_view3d_autodist_simple(struct ARegion *region, float mouse_worldloc[3], int margin, const float *force_depth); -bool ED_view3d_autodist_depth(struct ARegion *region, const int mval[2], int margin, float *depth); -bool ED_view3d_autodist_depth_seg(struct ARegion *region, - const int mval_sta[2], - const int mval_end[2], - int margin, - float *depth); +bool ED_view3d_depth_read_cached_seg( + const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth); /* select */ #define MAXPICKELEMS 2500 diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 065b0a2d057..c587425c47f 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -27,6 +27,7 @@ #include "BLI_sys_types.h" /* size_t */ #include "BLI_utildefines.h" #include "UI_interface_icons.h" +#include "WM_types.h" #ifdef __cplusplus extern "C" { @@ -244,10 +245,10 @@ enum { }; /* Default font size for normal text. */ -#define UI_DEFAULT_TEXT_POINTS 11 +#define UI_DEFAULT_TEXT_POINTS 11.0f /* Larger size used for title text. */ -#define UI_DEFAULT_TITLE_POINTS 11 +#define UI_DEFAULT_TITLE_POINTS 11.0f #define UI_PANEL_WIDTH 340 #define UI_COMPACT_PANEL_WIDTH 160 @@ -399,9 +400,8 @@ typedef enum { /** Resize handle (resize uilist). */ UI_BTYPE_GRIP = 57 << 9, UI_BTYPE_DECORATOR = 58 << 9, - UI_BTYPE_DATASETROW = 59 << 9, /* An item in a tree view. Parent items may be collapsible. */ - UI_BTYPE_TREEROW = 60 << 9, + UI_BTYPE_TREEROW = 59 << 9, } eButType; #define BUTTYPE (63 << 9) @@ -691,7 +691,7 @@ void UI_popup_block_ex(struct bContext *C, void uiPupBlockOperator(struct bContext *C, uiBlockCreateFunc func, struct wmOperator *op, - int opcontext); + wmOperatorCallContext opcontext); #endif void UI_popup_block_close(struct bContext *C, struct wmWindow *win, uiBlock *block); @@ -731,8 +731,8 @@ bool UI_block_is_search_only(const uiBlock *block); void UI_block_set_search_only(uiBlock *block, bool search_only); void UI_block_free(const struct bContext *C, uiBlock *block); -void UI_blocklist_free(const struct bContext *C, struct ListBase *lb); -void UI_blocklist_free_inactive(const struct bContext *C, struct ListBase *lb); +void UI_blocklist_free(const struct bContext *C, struct ARegion *region); +void UI_blocklist_free_inactive(const struct bContext *C, struct ARegion *region); void UI_screen_free_active_but(const struct bContext *C, struct bScreen *screen); void UI_block_region_set(uiBlock *block, struct ARegion *region); @@ -1003,7 +1003,7 @@ uiBut *uiDefButR_prop(uiBlock *block, uiBut *uiDefButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -1013,7 +1013,7 @@ uiBut *uiDefButO(uiBlock *block, uiBut *uiDefButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -1186,7 +1186,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block, uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -1196,7 +1196,7 @@ uiBut *uiDefIconButO(uiBlock *block, uiBut *uiDefIconButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -1382,7 +1382,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block, uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -1393,7 +1393,7 @@ uiBut *uiDefIconTextButO(uiBlock *block, uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, struct wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -1675,11 +1675,7 @@ int UI_searchbox_size_x(void); int UI_search_items_find_index(uiSearchItems *items, const char *name); void UI_but_hint_drawstr_set(uiBut *but, const char *string); -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation); -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type); -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain); -uint8_t UI_but_datasetrow_component_get(uiBut *but); -uint8_t UI_but_datasetrow_domain_get(uiBut *but); + void UI_but_treerow_indentation_set(uiBut *but, int indentation); void UI_but_node_link_set(uiBut *but, struct bNodeSocket *socket, const float draw_color[4]); @@ -1724,7 +1720,7 @@ void UI_but_func_pushed_state_set(uiBut *but, uiButPushedStateFunc func, const v struct PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, const char *opname, - short opcontext, + wmOperatorCallContext opcontext, int icon); struct wmOperatorType *UI_but_extra_operator_icon_optype_get(struct uiButExtraOpIcon *extra_icon); struct PointerRNA *UI_but_extra_operator_icon_opptr_get(struct uiButExtraOpIcon *extra_icon); @@ -1964,7 +1960,7 @@ void UI_paneltype_draw(struct bContext *C, struct PanelType *pt, struct uiLayout /* Only for convenience. */ void uiLayoutSetContextFromBut(uiLayout *layout, uiBut *but); -void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext); +void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext); void uiLayoutSetActive(uiLayout *layout, bool active); void uiLayoutSetActiveDefault(uiLayout *layout, bool active_default); void uiLayoutSetActivateInit(uiLayout *layout, bool activate_init); @@ -2392,7 +2388,7 @@ void uiItemFullO_ptr(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr); void uiItemFullO(uiLayout *layout, @@ -2400,7 +2396,7 @@ void uiItemFullO(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, struct PointerRNA *r_opptr); void uiItemFullOMenuHold_ptr(uiLayout *layout, @@ -2408,7 +2404,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout, const char *name, int icon, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const char *menu_id, /* extra menu arg. */ struct PointerRNA *r_opptr); @@ -2488,14 +2484,14 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag); void uiItemsFullEnumO_items(uiLayout *layout, struct wmOperatorType *ot, struct PointerRNA ptr, struct PropertyRNA *prop, struct IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const struct EnumPropertyItem *item_array, int totitem); diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 0d18eedeac9..8caf17741a7 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -217,15 +217,11 @@ class AbstractTreeViewItem : public TreeViewItemContainer { friend class TreeViewLayoutBuilder; public: - using IsActiveFn = std::function<bool()>; - private: bool is_open_ = false; bool is_active_ = false; bool is_renaming_ = false; - IsActiveFn is_active_fn_; - protected: /** This label is used for identifying an item (together with its parent's labels). */ std::string label_{}; @@ -239,11 +235,6 @@ class AbstractTreeViewItem : public TreeViewItemContainer { virtual void build_context_menu(bContext &C, uiLayout &column) const; virtual void on_activate(); - /** - * Set a custom callback to check if this item should be active. There's a version without - * arguments for checking if the item is currently in an active state. - */ - virtual void is_active(IsActiveFn is_active_fn); /** * Queries if the tree-view item supports renaming in principle. Renaming may still fail, e.g. if @@ -329,6 +320,17 @@ class AbstractTreeViewItem : public TreeViewItemContainer { */ void activate(); + /** + * If the result is not empty, it controls whether the item should be active or not, + * usually depending on the data that the view represents. + */ + virtual std::optional<bool> should_be_active() const; + + /** + * Return whether the item can be collapsed. Used to disable collapsing for items with children. + */ + virtual bool supports_collapsing() const; + private: static void rename_button_fn(bContext *, void *, char *); static AbstractTreeViewItem *find_tree_item_from_rename_button(const uiBut &but); @@ -416,6 +418,7 @@ class AbstractTreeViewItemDropController { */ class BasicTreeViewItem : public AbstractTreeViewItem { public: + using IsActiveFn = std::function<bool()>; using ActivateFn = std::function<void(BasicTreeViewItem &new_active)>; BIFIconID icon; @@ -423,7 +426,11 @@ class BasicTreeViewItem : public AbstractTreeViewItem { void build_row(uiLayout &row) override; void add_label(uiLayout &layout, StringRefNull label_override = ""); - void on_activate(ActivateFn fn); + void set_on_activate_fn(ActivateFn fn); + /** + * Set a custom callback to check if this item should be active. + */ + void set_is_active_fn(IsActiveFn fn); protected: /** @@ -433,9 +440,12 @@ class BasicTreeViewItem : public AbstractTreeViewItem { */ ActivateFn activate_fn_; + IsActiveFn is_active_fn_; + private: static void tree_row_click_fn(struct bContext *C, void *arg1, void *arg2); + std::optional<bool> should_be_active() const override; void on_activate() override; }; diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index 84172c7efce..bc3075f9de8 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -66,14 +66,14 @@ set(SRC interface_region_menu_popup.c interface_region_popover.c interface_region_popup.c - interface_region_search.c + interface_region_search.cc interface_region_tooltip.c interface_regions.c interface_style.c interface_template_asset_view.cc interface_template_list.cc interface_template_attribute_search.cc - interface_template_search_menu.c + interface_template_search_menu.cc interface_template_search_operator.c interface_templates.c interface_undo.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6ad0ef9de18..55fab04e9a4 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -37,6 +37,7 @@ #include "DNA_workspace_types.h" #include "BLI_alloca.h" +#include "BLI_ghash.h" #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" @@ -1638,7 +1639,7 @@ typedef enum PredefinedExtraOpIconType { static PointerRNA *ui_but_extra_operator_icon_add_ptr(uiBut *but, wmOperatorType *optype, - short opcontext, + wmOperatorCallContext opcontext, int icon) { uiButExtraOpIcon *extra_op_icon = MEM_mallocN(sizeof(*extra_op_icon), __func__); @@ -1678,7 +1679,7 @@ void ui_but_extra_operator_icons_free(uiBut *but) PointerRNA *UI_but_extra_operator_icon_add(uiBut *but, const char *opname, - short opcontext, + wmOperatorCallContext opcontext, int icon) { wmOperatorType *optype = WM_operatortype_find(opname, false); @@ -1881,7 +1882,7 @@ bool ui_but_context_poll_operator_ex(bContext *C, bool ui_but_context_poll_operator(bContext *C, wmOperatorType *ot, const uiBut *but) { - const int opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT; + const wmOperatorCallContext opcontext = but ? but->opcontext : WM_OP_INVOKE_DEFAULT; return ui_but_context_poll_operator_ex( C, but, &(wmOperatorCallParams){.optype = ot, .opcontext = opcontext}); } @@ -1993,23 +1994,9 @@ void UI_block_end(const bContext *C, uiBlock *block) /* ************** BLOCK DRAWING FUNCTION ************* */ -void ui_fontscale(short *points, float aspect) +void ui_fontscale(float *points, float aspect) { - if (aspect < 0.9f || aspect > 1.1f) { - float pointsf = *points; - - /* For some reason scaling fonts goes too fast compared to widget size. */ - /* XXX(ton): not true anymore? */ - // aspect = sqrt(aspect); - pointsf /= aspect; - - if (aspect > 1.0f) { - *points = ceilf(pointsf); - } - else { - *points = floorf(pointsf); - } - } + *points /= aspect; } /* Project button or block (but==NULL) to pixels in region-space. */ @@ -3535,22 +3522,35 @@ void UI_blocklist_draw(const bContext *C, const ListBase *lb) } /* can be called with C==NULL */ -void UI_blocklist_free(const bContext *C, ListBase *lb) +void UI_blocklist_free(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; uiBlock *block; while ((block = BLI_pophead(lb))) { UI_block_free(C, block); } + if (region->runtime.block_name_map != NULL) { + BLI_ghash_free(region->runtime.block_name_map, NULL, NULL); + region->runtime.block_name_map = NULL; + } } -void UI_blocklist_free_inactive(const bContext *C, ListBase *lb) +void UI_blocklist_free_inactive(const bContext *C, ARegion *region) { + ListBase *lb = ®ion->uiblocks; + LISTBASE_FOREACH_MUTABLE (uiBlock *, block, lb) { if (!block->handle) { if (block->active) { block->active = false; } else { + if (region->runtime.block_name_map != NULL) { + uiBlock *b = BLI_ghash_lookup(region->runtime.block_name_map, block->name); + if (b == block) { + BLI_ghash_remove(region->runtime.block_name_map, b->name, NULL, NULL); + } + } BLI_remlink(lb, block); UI_block_free(C, block); } @@ -3566,7 +3566,10 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* each listbase only has one block with this name, free block * if is already there so it can be rebuilt from scratch */ if (lb) { - oldblock = BLI_findstring(lb, block->name, offsetof(uiBlock, name)); + if (region->runtime.block_name_map == NULL) { + region->runtime.block_name_map = BLI_ghash_str_new(__func__); + } + oldblock = (uiBlock *)BLI_ghash_lookup(region->runtime.block_name_map, block->name); if (oldblock) { oldblock->active = false; @@ -3576,6 +3579,7 @@ void UI_block_region_set(uiBlock *block, ARegion *region) /* at the beginning of the list! for dynamical menus/blocks */ BLI_addhead(lb, block); + BLI_ghash_reinsert(region->runtime.block_name_map, block->name, block, NULL, NULL); } block->oldblock = oldblock; @@ -3991,10 +3995,6 @@ static void ui_but_alloc_info(const eButType type, alloc_size = sizeof(uiButCurveProfile); alloc_str = "uiButCurveProfile"; break; - case UI_BTYPE_DATASETROW: - alloc_size = sizeof(uiButDatasetRow); - alloc_str = "uiButDatasetRow"; - break; case UI_BTYPE_TREEROW: alloc_size = sizeof(uiButTreeRow); alloc_str = "uiButTreeRow"; @@ -4197,7 +4197,6 @@ static uiBut *ui_def_but(uiBlock *block, UI_BTYPE_BLOCK, UI_BTYPE_BUT_MENU, UI_BTYPE_SEARCH_MENU, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW, UI_BTYPE_POPOVER)) { but->drawflag |= (UI_BUT_TEXT_LEFT | UI_BUT_ICON_LEFT); @@ -4755,7 +4754,7 @@ static uiBut *ui_def_but_rna_propname(uiBlock *block, static uiBut *ui_def_but_operator_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5293,7 +5292,7 @@ uiBut *uiDefButR_prop(uiBlock *block, uiBut *uiDefButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5308,7 +5307,7 @@ uiBut *uiDefButO_ptr(uiBlock *block, uiBut *uiDefButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, const char *str, int x, int y, @@ -5676,7 +5675,7 @@ uiBut *uiDefIconButR_prop(uiBlock *block, uiBut *uiDefIconButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -5691,7 +5690,7 @@ uiBut *uiDefIconButO_ptr(uiBlock *block, uiBut *uiDefIconButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, int x, int y, @@ -6079,7 +6078,7 @@ uiBut *uiDefIconTextButR_prop(uiBlock *block, uiBut *uiDefIconTextButO_ptr(uiBlock *block, int type, wmOperatorType *ot, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -6096,7 +6095,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, uiBut *uiDefIconTextButO(uiBlock *block, int type, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, int icon, const char *str, int x, @@ -6938,15 +6937,6 @@ uiBut *uiDefSearchButO_ptr(uiBlock *block, return but; } -void UI_but_datasetrow_indentation_set(uiBut *but, int indentation) -{ - uiButDatasetRow *but_dataset = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset->indentation = indentation; - BLI_assert(indentation >= 0); -} - void UI_but_treerow_indentation_set(uiBut *but, int indentation) { uiButTreeRow *but_row = (uiButTreeRow *)but; @@ -6964,38 +6954,6 @@ void UI_but_hint_drawstr_set(uiBut *but, const char *string) ui_but_add_shortcut(but, string, false); } -void UI_but_datasetrow_component_set(uiBut *but, uint8_t geometry_component_type) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->geometry_component_type = geometry_component_type; -} - -void UI_but_datasetrow_domain_set(uiBut *but, uint8_t attribute_domain) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - but_dataset_row->attribute_domain = attribute_domain; -} - -uint8_t UI_but_datasetrow_component_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->geometry_component_type; -} - -uint8_t UI_but_datasetrow_domain_get(uiBut *but) -{ - uiButDatasetRow *but_dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - - return but_dataset_row->attribute_domain; -} - void UI_but_node_link_set(uiBut *but, bNodeSocket *socket, const float draw_color[4]) { but->flag |= UI_BUT_NODE_LINK; diff --git a/source/blender/editors/interface/interface_context_path.cc b/source/blender/editors/interface/interface_context_path.cc index b0f8d186afa..3f5efd187d8 100644 --- a/source/blender/editors/interface/interface_context_path.cc +++ b/source/blender/editors/interface/interface_context_path.cc @@ -82,4 +82,4 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path) } // namespace blender::ui -/** \} */
\ No newline at end of file +/** \} */ diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index c3633e11f83..e45619d89e8 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -268,28 +268,28 @@ static bool eyedropper_cryptomatte_sample_fl( return false; } - ARegion *ar = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); - if (!ar) { + ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + if (!region) { return false; } - int mval[2] = {mx - ar->winrct.xmin, my - ar->winrct.ymin}; + int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; switch (sa->spacetype) { case SPACE_IMAGE: { SpaceImage *sima = sa->spacedata.first; - ED_space_image_get_position(sima, ar, mval, fpos); + ED_space_image_get_position(sima, region, mval, fpos); break; } case SPACE_NODE: { Main *bmain = CTX_data_main(C); SpaceNode *snode = sa->spacedata.first; - ED_space_node_get_position(bmain, snode, ar, mval, fpos); + ED_space_node_get_position(bmain, snode, region, mval, fpos); break; } case SPACE_CLIP: { SpaceClip *sc = sa->spacedata.first; - ED_space_clip_get_position(sc, ar, mval, fpos); + ED_space_clip_get_position(sc, region, mval, fpos); break; } default: { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6d69724efef..d18b3fdf505 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -492,7 +492,7 @@ typedef struct uiAfterFunc { wmOperator *popup_op; wmOperatorType *optype; - int opcontext; + wmOperatorCallContext opcontext; PointerRNA *opptr; PointerRNA rnapoin; @@ -775,7 +775,7 @@ static uiAfterFunc *ui_afterfunc_new(void) */ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot, PointerRNA **properties, - int opcontext, + wmOperatorCallContext opcontext, const uiBut *context_but) { uiAfterFunc *after = ui_afterfunc_new(); @@ -796,7 +796,7 @@ static void ui_handle_afterfunc_add_operator_ex(wmOperatorType *ot, } } -void ui_handle_afterfunc_add_operator(wmOperatorType *ot, int opcontext) +void ui_handle_afterfunc_add_operator(wmOperatorType *ot, wmOperatorCallContext opcontext) { ui_handle_afterfunc_add_operator_ex(ot, NULL, opcontext, NULL); } @@ -2334,9 +2334,6 @@ static void ui_apply_but( case UI_BTYPE_LISTROW: ui_apply_but_LISTROW(C, block, but, data); break; - case UI_BTYPE_DATASETROW: - ui_apply_but_ROW(C, block, but, data); - break; case UI_BTYPE_TAB: ui_apply_but_TAB(C, but, data); break; @@ -8012,7 +8009,6 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_CHECKBOX: case UI_BTYPE_CHECKBOX_N: case UI_BTYPE_ROW: - case UI_BTYPE_DATASETROW: retval = ui_do_but_TOG(C, but, data, event); break; case UI_BTYPE_TREEROW: @@ -11344,8 +11340,7 @@ static void ui_region_handler_remove(bContext *C, void *UNUSED(userdata)) return; } - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); bScreen *screen = CTX_wm_screen(C); if (screen == NULL) { return; diff --git a/source/blender/editors/interface/interface_icons_event.c b/source/blender/editors/interface/interface_icons_event.c index 3962ff6a702..577db6a0338 100644 --- a/source/blender/editors/interface/interface_icons_event.c +++ b/source/blender/editors/interface/interface_icons_event.c @@ -77,7 +77,7 @@ static void icon_draw_rect_input_text(const rctf *rect, const float color[4], const char *str, - int font_size) + float font_size) { BLF_batch_draw_flush(); const int font_id = BLF_default(); @@ -97,7 +97,7 @@ static void icon_draw_rect_input_symbol(const rctf *rect, const float color[4], BLF_batch_draw_flush(); const int font_id = blf_mono_font; BLF_color4fv(font_id, color); - BLF_size(font_id, 19 * U.pixelsize, U.dpi); + BLF_size(font_id, 19.0f * U.pixelsize, U.dpi); const float x = rect->xmin + (2.0f * U.pixelsize); const float y = rect->ymin + (1.0f * U.pixelsize); BLF_position(font_id, x, y, 0.0f); @@ -152,12 +152,12 @@ void icon_draw_rect_input(float x, if ((event_type >= EVT_AKEY) && (event_type <= EVT_ZKEY)) { const char str[2] = {'A' + (event_type - EVT_AKEY), '\0'}; - icon_draw_rect_input_text(&rect, color, str, 13); + icon_draw_rect_input_text(&rect, color, str, 13.0f); } else if ((event_type >= EVT_F1KEY) && (event_type <= EVT_F12KEY)) { char str[4]; SNPRINTF(str, "F%d", 1 + (event_type - EVT_F1KEY)); - icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8 : 10); + icon_draw_rect_input_text(&rect, color, str, event_type > EVT_F9KEY ? 8.0f : 10.0f); } else if (event_type == EVT_LEFTSHIFTKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x87, 0xa7, 0x0}); @@ -167,7 +167,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0x83, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Ctrl", 9); + icon_draw_rect_input_text(&rect, color, "Ctrl", 9.0f); } } else if (event_type == EVT_LEFTALTKEY) { @@ -175,7 +175,7 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8c, 0xa5, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Alt", 10); + icon_draw_rect_input_text(&rect, color, "Alt", 10.0f); } } else if (event_type == EVT_OSKEY) { @@ -186,20 +186,20 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x9d, 0x96, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "OS", 10); + icon_draw_rect_input_text(&rect, color, "OS", 10.0f); } } else if (event_type == EVT_DELKEY) { - icon_draw_rect_input_text(&rect, color, "Del", 9); + icon_draw_rect_input_text(&rect, color, "Del", 9.0f); } else if (event_type == EVT_TABKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0xad, 0xbe, 0x0}); } else if (event_type == EVT_HOMEKEY) { - icon_draw_rect_input_text(&rect, color, "Home", 6); + icon_draw_rect_input_text(&rect, color, "Home", 6.0f); } else if (event_type == EVT_ENDKEY) { - icon_draw_rect_input_text(&rect, color, "End", 8); + icon_draw_rect_input_text(&rect, color, "End", 8.0f); } else if (event_type == EVT_RETKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8f, 0x8e, 0x0}); @@ -209,14 +209,14 @@ void icon_draw_rect_input(float x, icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x8e, 0x8b, 0x0}); } else { - icon_draw_rect_input_text(&rect, color, "Esc", 8); + icon_draw_rect_input_text(&rect, color, "Esc", 8.0f); } } else if (event_type == EVT_PAGEUPKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x91, 0x0}, 8.0f); } else if (event_type == EVT_PAGEDOWNKEY) { - icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8); + icon_draw_rect_input_text(&rect, color, (const char[]){'P', 0xe2, 0x86, 0x93, 0x0}, 8.0f); } else if (event_type == EVT_LEFTARROWKEY) { icon_draw_rect_input_symbol(&rect, color, (const char[]){0xe2, 0x86, 0x90, 0x0}); diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index f766bb1465f..e0686c1ff7a 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -255,7 +255,7 @@ struct uiBut { /* Operator data */ struct wmOperatorType *optype; struct PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; /** When non-zero, this is the key used to activate a menu items (`a-z` always lower case). */ uchar menu_key; @@ -351,14 +351,6 @@ typedef struct uiButProgressbar { float progress; } uiButProgressbar; -/** Derived struct for #UI_BTYPE_DATASETROW. */ -typedef struct uiButDatasetRow { - uiBut but; - - uint8_t geometry_component_type; - uint8_t attribute_domain; - int indentation; -} uiButDatasetRow; /** Derived struct for #UI_BTYPE_TREEROW. */ typedef struct uiButTreeRow { @@ -609,7 +601,7 @@ typedef struct uiSafetyRct { /* interface.c */ -void ui_fontscale(short *points, float aspect); +void ui_fontscale(float *points, float aspect); extern void ui_block_to_region_fl(const struct ARegion *region, uiBlock *block, @@ -882,7 +874,7 @@ void ui_pie_menu_level_create(uiBlock *block, struct IDProperty *properties, const EnumPropertyItem *items, int totitem, - int context, + wmOperatorCallContext context, int flag); /* interface_region_popup.c */ @@ -960,7 +952,8 @@ const char *ui_textedit_undo(struct uiUndoStack_Text *undo_stack, int *r_cursor_index); /* interface_handlers.c */ -extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, int opcontext); +extern void ui_handle_afterfunc_add_operator(struct wmOperatorType *ot, + wmOperatorCallContext opcontext); extern void ui_pan_to_scroll(const struct wmEvent *event, int *type, int *val); extern void ui_but_activate_event(struct bContext *C, struct ARegion *region, uiBut *but); extern void ui_but_activate_over(struct bContext *C, struct ARegion *region, uiBut *but); diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 20e95ef4e9c..b792c59481c 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -82,7 +82,7 @@ typedef struct uiLayoutRoot { struct uiLayoutRoot *next, *prev; int type; - int opcontext; + wmOperatorCallContext opcontext; int emw, emh; int padding; @@ -1218,7 +1218,7 @@ static uiBut *uiItemFullO_ptr_ex(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1350,7 +1350,7 @@ void uiItemFullO_ptr(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1362,7 +1362,7 @@ void uiItemFullOMenuHold_ptr(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const char *menu_id, PointerRNA *r_opptr) @@ -1376,7 +1376,7 @@ void uiItemFullO(uiLayout *layout, const char *name, int icon, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, PointerRNA *r_opptr) { @@ -1474,7 +1474,7 @@ void uiItemsFullEnumO_items(uiLayout *layout, PointerRNA ptr, PropertyRNA *prop, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag, const EnumPropertyItem *item_array, int totitem) @@ -1623,7 +1623,7 @@ void uiItemsFullEnumO(uiLayout *layout, const char *opname, const char *propname, IDProperty *properties, - int context, + wmOperatorCallContext context, int flag) { wmOperatorType *ot = WM_operatortype_find(opname, 0); /* print error next */ @@ -3433,7 +3433,7 @@ void uiItemMenuFN(uiLayout *layout, const char *name, int icon, uiMenuCreateFunc } typedef struct MenuItemLevel { - int opcontext; + wmOperatorCallContext opcontext; /* don't use pointers to the strings because python can dynamically * allocate strings and free before the menu draws, see T27304. */ char opname[OP_MAX_TYPENAME]; @@ -5672,7 +5672,7 @@ bool uiLayoutGetFixedSize(uiLayout *layout) return (layout->item.flag & UI_ITEM_FIXED_SIZE) != 0; } -void uiLayoutSetOperatorContext(uiLayout *layout, int opcontext) +void uiLayoutSetOperatorContext(uiLayout *layout, wmOperatorCallContext opcontext) { layout->root->opcontext = opcontext; } diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 072362492d8..6acbaf03476 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1348,7 +1348,7 @@ void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) const uiStyle *style = UI_style_get(); const uiFontStyle *fstyle = &style->widget; const int fontid = fstyle->uifont_id; - short fstyle_points = fstyle->points; + float fstyle_points = fstyle->points; const float aspect = ((uiBlock *)region->uiblocks.first)->aspect; const float zoom = 1.0f / aspect; const int px = U.pixelsize; diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index bdf93d7c82e..a07222854d2 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -69,7 +69,6 @@ bool ui_but_is_toggle(const uiBut *but) UI_BTYPE_CHECKBOX, UI_BTYPE_CHECKBOX_N, UI_BTYPE_ROW, - UI_BTYPE_DATASETROW, UI_BTYPE_TREEROW); } diff --git a/source/blender/editors/interface/interface_region_menu_pie.c b/source/blender/editors/interface/interface_region_menu_pie.c index 01562b25da1..0ffbdd6911c 100644 --- a/source/blender/editors/interface/interface_region_menu_pie.c +++ b/source/blender/editors/interface/interface_region_menu_pie.c @@ -330,7 +330,7 @@ typedef struct PieMenuLevelData { wmOperatorType *ot; const char *propname; IDProperty *properties; - int context, flag; + wmOperatorCallContext context, flag; } PieMenuLevelData; /** @@ -381,7 +381,7 @@ void ui_pie_menu_level_create(uiBlock *block, IDProperty *properties, const EnumPropertyItem *items, int totitem, - int context, + wmOperatorCallContext context, int flag) { const int totitem_parent = PIE_MAX_ITEMS - 1; diff --git a/source/blender/editors/interface/interface_region_menu_popup.c b/source/blender/editors/interface/interface_region_menu_popup.c index 4e20466326e..408953f8d0e 100644 --- a/source/blender/editors/interface/interface_region_menu_popup.c +++ b/source/blender/editors/interface/interface_region_menu_popup.c @@ -640,7 +640,7 @@ void UI_popup_block_ex(bContext *C, } #if 0 /* UNUSED */ -void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, int opcontext) +void uiPupBlockOperator(bContext *C, uiBlockCreateFunc func, wmOperator *op, wmOperatorCallContext opcontext) { wmWindow *window = CTX_wm_window(C); uiPopupBlockHandle *handle; diff --git a/source/blender/editors/interface/interface_region_popover.c b/source/blender/editors/interface/interface_region_popover.c index f8f19c2e43d..5e7e0bfe9b5 100644 --- a/source/blender/editors/interface/interface_region_popover.c +++ b/source/blender/editors/interface/interface_region_popover.c @@ -90,7 +90,7 @@ struct uiPopover { #endif }; -static void ui_popover_create_block(bContext *C, uiPopover *pup, int opcontext) +static void ui_popover_create_block(bContext *C, uiPopover *pup, wmOperatorCallContext opcontext) { BLI_assert(pup->ui_size_x != 0); diff --git a/source/blender/editors/interface/interface_region_popup.c b/source/blender/editors/interface/interface_region_popup.c index 0e53100f91b..0f903bd4af9 100644 --- a/source/blender/editors/interface/interface_region_popup.c +++ b/source/blender/editors/interface/interface_region_popup.c @@ -743,7 +743,7 @@ uiBlock *ui_popup_block_refresh(bContext *C, if (block_old) { block->oldblock = block_old; UI_block_update_from_old(C, block); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); } /* checks which buttons are visible, sets flags to prevent draw (do after region init) */ diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.cc index b8a19d06be1..eaf1ed3693b 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.cc @@ -23,9 +23,9 @@ * Search Box Region & Interaction */ -#include <stdarg.h> -#include <stdlib.h> -#include <string.h> +#include <cstdarg> +#include <cstdlib> +#include <cstring> #include "DNA_ID.h" #include "MEM_guardedalloc.h" @@ -84,7 +84,7 @@ struct uiSearchItems { void *active; }; -typedef struct uiSearchboxData { +struct uiSearchboxData { rcti bbox; uiFontStyle fstyle; uiSearchItems items; @@ -102,7 +102,7 @@ typedef struct uiSearchboxData { * Used so we can show leading text to menu items less prominently (not related to 'use_sep'). */ const char *sep_string; -} uiSearchboxData; +}; #define SEARCH_ITEMS 10 @@ -166,9 +166,9 @@ bool UI_search_item_add(uiSearchItems *items, if (name_prefix_offset != 0) { /* Lazy initialize, as this isn't used often. */ - if (items->name_prefix_offsets == NULL) { - items->name_prefix_offsets = MEM_callocN( - items->maxitem * sizeof(*items->name_prefix_offsets), "search name prefix offsets"); + if (items->name_prefix_offsets == nullptr) { + items->name_prefix_offsets = (uint8_t *)MEM_callocN( + items->maxitem * sizeof(*items->name_prefix_offsets), __func__); } items->name_prefix_offsets[items->totitem] = name_prefix_offset; } @@ -198,7 +198,7 @@ int UI_searchbox_size_x(void) int UI_search_items_find_index(uiSearchItems *items, const char *name) { - if (items->name_prefix_offsets != NULL) { + if (items->name_prefix_offsets != nullptr) { for (int i = 0; i < items->totitem; i++) { if (STREQ(name, items->names[i] + items->name_prefix_offsets[i])) { return i; @@ -218,7 +218,7 @@ int UI_search_items_find_index(uiSearchItems *items, const char *name) /* region is the search box itself */ static void ui_searchbox_select(bContext *C, ARegion *region, uiBut *but, int step) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* apply step */ data->active += step; @@ -285,14 +285,14 @@ static void ui_searchbox_butrect(rcti *r_rect, uiSearchboxData *data, int itemnr int ui_searchbox_find_index(ARegion *region, const char *name) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return UI_search_items_find_index(&data->items, name); } /* x and y in screen-coords. */ bool ui_searchbox_inside(ARegion *region, const int xy[2]) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); return BLI_rcti_isect_pt(&data->bbox, xy[0] - region->winrct.xmin, xy[1] - region->winrct.ymin); } @@ -300,12 +300,12 @@ bool ui_searchbox_inside(ARegion *region, const int xy[2]) /* string validated to be of correct length (but->hardmax) */ bool ui_searchbox_apply(uiBut *but, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); - search_but->item_active = NULL; + search_but->item_active = nullptr; if (data->active != -1) { const char *name = data->items.names[data->active] + @@ -314,7 +314,7 @@ bool ui_searchbox_apply(uiBut *but, ARegion *region) data->items.name_prefix_offsets[data->active] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; /* Search button with dynamic string properties may have their own method of applying * the search results, so only copy the result if there is a proper space for it. */ @@ -356,7 +356,7 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, } ARegion *searchbox_region = UI_region_searchbox_region_get(region); - uiSearchboxData *data = searchbox_region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(searchbox_region->regiondata); BLI_assert(data->items.pointers[data->active] == search_but->item_active); @@ -367,13 +367,13 @@ static struct ARegion *wm_searchbox_tooltip_init(struct bContext *C, C, region, &rect, search_but->arg, search_but->item_active); } } - return NULL; + return nullptr; } bool ui_searchbox_event( bContext *C, ARegion *region, uiBut *but, ARegion *butregion, const wmEvent *event) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); uiButSearch *search_but = (uiButSearch *)but; int type = event->type, val = event->val; bool handled = false; @@ -481,7 +481,7 @@ static void ui_searchbox_update_fn(bContext *C, void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool reset) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -499,7 +499,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re if (search_but->items_update_fn && search_but->item_active) { data->items.active = search_but->item_active; ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); - data->items.active = NULL; + data->items.active = nullptr; /* found active item, calculate real offset by centering it */ if (data->items.totitem) { @@ -538,7 +538,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re /* Never include the prefix in the button. */ (data->items.name_prefix_offsets ? data->items.name_prefix_offsets[a] : 0); - const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : NULL; + const char *name_sep = data->use_shortcut_sep ? strrchr(name, UI_SEP_CHAR) : nullptr; if (STREQLEN(but->editstr, name, name_sep ? (name_sep - name) : data->items.maxstrlen)) { data->active = a; break; @@ -558,7 +558,7 @@ void ui_searchbox_update(bContext *C, ARegion *region, uiBut *but, const bool re int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *str) { uiButSearch *search_but = (uiButSearch *)but; - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); int match = AUTOCOMPLETE_NO_MATCH; BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); @@ -569,7 +569,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st ui_searchbox_update_fn(C, search_but, but->editstr, &data->items); match = UI_autocomplete_end(data->items.autocpl, str); - data->items.autocpl = NULL; + data->items.autocpl = nullptr; } return match; @@ -577,7 +577,7 @@ int ui_searchbox_autocomplete(bContext *C, ARegion *region, uiBut *but, char *st static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -630,7 +630,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; char *name = data->items.names[a]; int icon = data->items.icons[a]; - char *name_sep_test = NULL; + char *name_sep_test = nullptr; uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE; if (data->use_shortcut_sep) { @@ -652,15 +652,15 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* Simple menu item. */ - ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, nullptr); } else { /* Split menu item, faded text before the separator. */ - char *name_sep = NULL; + char *name_sep = nullptr; do { name_sep = name_sep_test; name_sep_test = strstr(name_sep + search_sep_len, data->sep_string); - } while (name_sep_test != NULL); + } while (name_sep_test != nullptr); name_sep += search_sep_len; const char name_sep_prev = *name_sep; @@ -683,7 +683,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) } /* The previous menu item draws the active selection. */ - ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name_sep, icon, state, separator_type, nullptr); } } /* indicate more */ @@ -705,7 +705,7 @@ static void ui_searchbox_region_draw_fn(const bContext *C, ARegion *region) static void ui_searchbox_region_free_fn(ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* free search data */ for (int a = 0; a < data->items.maxitem; a++) { @@ -716,12 +716,12 @@ static void ui_searchbox_region_free_fn(ARegion *region) MEM_freeN(data->items.icons); MEM_freeN(data->items.states); - if (data->items.name_prefix_offsets != NULL) { + if (data->items.name_prefix_offsets != nullptr) { MEM_freeN(data->items.name_prefix_offsets); } MEM_freeN(data); - region->regiondata = NULL; + region->regiondata = nullptr; } static ARegion *ui_searchbox_create_generic_ex(bContext *C, @@ -746,7 +746,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, region->type = &type; /* create searchbox data */ - uiSearchboxData *data = MEM_callocN(sizeof(uiSearchboxData), "uiSearchboxData"); + uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__); /* set font, get bb */ data->fstyle = style->widget; /* copy struct */ @@ -767,7 +767,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, data->prv_cols = but->a2; } - if (but->optype != NULL || use_shortcut_sep) { + if (but->optype != nullptr || use_shortcut_sep) { data->use_shortcut_sep = true; } data->sep_string = search_but->item_sep_string; @@ -881,13 +881,13 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, /* In case the button's string is dynamic, make sure there are buffers available. */ data->items.maxstrlen = but->hardmax == 0 ? UI_MAX_NAME_STR : but->hardmax; data->items.totitem = 0; - data->items.names = MEM_callocN(data->items.maxitem * sizeof(void *), "search names"); - data->items.pointers = MEM_callocN(data->items.maxitem * sizeof(void *), "search pointers"); - data->items.icons = MEM_callocN(data->items.maxitem * sizeof(int), "search icons"); - data->items.states = MEM_callocN(data->items.maxitem * sizeof(int), "search flags"); - data->items.name_prefix_offsets = NULL; /* Lazy initialized as needed. */ + data->items.names = (char **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.pointers = (void **)MEM_callocN(data->items.maxitem * sizeof(void *), __func__); + data->items.icons = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.states = (int *)MEM_callocN(data->items.maxitem * sizeof(int), __func__); + data->items.name_prefix_offsets = nullptr; /* Lazy initialized as needed. */ for (int i = 0; i < data->items.maxitem; i++) { - data->items.names[i] = MEM_callocN(data->items.maxstrlen + 1, "search pointers"); + data->items.names[i] = (char *)MEM_callocN(data->items.maxstrlen + 1, __func__); } return region; @@ -924,7 +924,7 @@ static void str_tolower_titlecaps_ascii(char *str, const size_t len) static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARegion *region) { - uiSearchboxData *data = region->regiondata; + uiSearchboxData *data = static_cast<uiSearchboxData *>(region->regiondata); /* pixel space */ wmOrtho2_region_pixelspace(region); @@ -952,10 +952,10 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe { const int state = ((a == data->active) ? UI_ACTIVE : 0) | data->items.states[a]; - wmOperatorType *ot = data->items.pointers[a]; + wmOperatorType *ot = static_cast<wmOperatorType *>(data->items.pointers[a]); char text_pre[128]; - char *text_pre_p = strstr(ot->idname, "_OT_"); - if (text_pre_p == NULL) { + const char *text_pre_p = strstr(ot->idname, "_OT_"); + if (text_pre_p == nullptr) { text_pre[0] = '\0'; } else { @@ -975,7 +975,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe data->items.icons[a], state, UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); ui_draw_menu_item(&data->fstyle, &rect_post, data->items.names[a], @@ -983,7 +983,7 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe state, data->use_shortcut_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT : UI_MENU_ITEM_SEPARATOR_NONE, - NULL); + nullptr); } } /* indicate more */ @@ -1044,17 +1044,17 @@ void ui_but_search_refresh(uiButSearch *search_but) return; } - uiSearchItems *items = MEM_callocN(sizeof(uiSearchItems), "search items"); + uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__); /* setup search struct */ items->maxitem = 10; items->maxstrlen = 256; - items->names = MEM_callocN(items->maxitem * sizeof(void *), "search names"); + items->names = (char **)MEM_callocN(items->maxitem * sizeof(void *), __func__); for (int i = 0; i < items->maxitem; i++) { - items->names[i] = MEM_callocN(but->hardmax + 1, "search names"); + items->names[i] = (char *)MEM_callocN(but->hardmax + 1, __func__); } - ui_searchbox_update_fn(but->block->evil_C, search_but, but->drawstr, items); + ui_searchbox_update_fn((bContext *)but->block->evil_C, search_but, but->drawstr, items); if (!search_but->results_are_suggestions) { /* Only red-alert when we are sure of it, this can miss cases when >10 matches. */ diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index eb25d896d26..0d8bdfc5817 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -960,7 +960,8 @@ static uiTooltipData *ui_tooltip_data_from_button_or_extra_icon(bContext *C, /* if operator poll check failed, it can give pretty precise info why */ if (optype) { - const int opcontext = extra_icon ? extra_icon->optype_params->opcontext : but->opcontext; + const wmOperatorCallContext opcontext = extra_icon ? extra_icon->optype_params->opcontext : + but->opcontext; CTX_wm_operator_poll_msg_clear(C); ui_but_context_poll_operator_ex( C, but, &(wmOperatorCallParams){.optype = optype, .opcontext = opcontext}); diff --git a/source/blender/editors/interface/interface_regions_intern.h b/source/blender/editors/interface/interface_regions_intern.h index 0cb1fee9a92..ce938852520 100644 --- a/source/blender/editors/interface/interface_regions_intern.h +++ b/source/blender/editors/interface/interface_regions_intern.h @@ -22,9 +22,17 @@ #pragma once +#ifdef __cplusplus +extern "C" { +#endif + /* interface_region_menu_popup.c */ uint ui_popup_menu_hash(const char *str); /* interface_regions_intern.h */ ARegion *ui_region_temp_add(bScreen *screen); void ui_region_temp_remove(struct bContext *C, bScreen *screen, ARegion *region); + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 92a9f14c77d..8bb1e477506 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -419,7 +419,7 @@ int UI_fontstyle_height_max(const uiFontStyle *fs) /* reading without uifont will create one */ void uiStyleInit(void) { - uiStyle *style = U.uistyles.first; + const uiStyle *style = U.uistyles.first; /* recover from uninitialized dpi */ if (U.dpi == 0) { @@ -483,16 +483,20 @@ void uiStyleInit(void) * Yes, this build the glyph cache and create * the texture. */ - BLF_size(font->blf_id, 11 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 12 * U.pixelsize, U.dpi); - BLF_size(font->blf_id, 14 * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 11.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 12.0f * U.pixelsize, U.dpi); + BLF_size(font->blf_id, 14.0f * U.pixelsize, U.dpi); } } if (style == NULL) { - ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); + style = ui_style_new(&U.uistyles, "Default Style", UIFONT_DEFAULT); } + BLF_cache_flush_set_fn(UI_widgetbase_draw_cache_flush); + + BLF_default_size(style->widgetlabel.points); + /* XXX, this should be moved into a style, * but for now best only load the monospaced font once. */ BLI_assert(blf_mono_font == -1); @@ -506,7 +510,7 @@ void uiStyleInit(void) blf_mono_font = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font, 12.0f * U.pixelsize, 72); /* Set default flags based on UI preferences (not render fonts) */ { @@ -551,7 +555,7 @@ void uiStyleInit(void) blf_mono_font_render = BLF_load_mono_default(unique); } - BLF_size(blf_mono_font_render, 12 * U.pixelsize, 72); + BLF_size(blf_mono_font_render, 12.0f * U.pixelsize, 72); } void UI_fontstyle_set(const uiFontStyle *fs) diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc index d3ce7ebc3db..7b2fb8f784e 100644 --- a/source/blender/editors/interface/interface_template_asset_view.cc +++ b/source/blender/editors/interface/interface_template_asset_view.cc @@ -178,7 +178,7 @@ static void asset_view_template_refresh_asset_collection( RNA_property_collection_clear(&assets_dataptr, assets_prop); - ED_assetlist_iterate(&asset_library_ref, [&](AssetHandle asset) { + ED_assetlist_iterate(asset_library_ref, [&](AssetHandle asset) { if (!ED_asset_filter_matches_asset(&filter_settings, &asset)) { /* Don't do anything else, but return true to continue iterating. */ return true; diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.cc index 5877b4fe6d7..fe7660e4221 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -21,8 +21,8 @@ * Accessed via the #WM_OT_search_menu operator. */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -85,16 +85,16 @@ struct MenuSearch_Context { }; struct MenuSearch_Parent { - struct MenuSearch_Parent *parent; + MenuSearch_Parent *parent; MenuType *parent_mt; const char *drawstr; /** Set while writing menu items only. */ - struct MenuSearch_Parent *temp_child; + MenuSearch_Parent *temp_child; }; struct MenuSearch_Item { - struct MenuSearch_Item *next, *prev; + MenuSearch_Item *next, *prev; const char *drawstr; const char *drawwstr_full; /** Support a single level sub-menu nesting (for operator buttons that expand). */ @@ -102,12 +102,12 @@ struct MenuSearch_Item { int icon; int state; - struct MenuSearch_Parent *menu_parent; + MenuSearch_Parent *menu_parent; MenuType *mt; - enum { - MENU_SEARCH_TYPE_OP = 1, - MENU_SEARCH_TYPE_RNA = 2, + enum Type { + Operator = 1, + RNA = 2, } type; union { @@ -115,7 +115,7 @@ struct MenuSearch_Item { struct { wmOperatorType *type; PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; bContextStore *context; } op; @@ -129,8 +129,8 @@ struct MenuSearch_Item { } rna; }; - /** Set when we need each menu item to be able to set its own context. may be NULL. */ - struct MenuSearch_Context *wm_context; + /** Set when we need each menu item to be able to set its own context. may be nullptr. */ + MenuSearch_Context *wm_context; }; struct MenuSearch_Data { @@ -148,15 +148,15 @@ struct MenuSearch_Data { static int menu_item_sort_by_drawstr_full(const void *menu_item_a_v, const void *menu_item_b_v) { - const struct MenuSearch_Item *menu_item_a = menu_item_a_v; - const struct MenuSearch_Item *menu_item_b = menu_item_b_v; + const MenuSearch_Item *menu_item_a = (MenuSearch_Item *)menu_item_a_v; + const MenuSearch_Item *menu_item_b = (MenuSearch_Item *)menu_item_b_v; return strcmp(menu_item_a->drawwstr_full, menu_item_b->drawwstr_full); } static const char *strdup_memarena(MemArena *memarena, const char *str) { const uint str_size = strlen(str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); memcpy(str_dst, str, str_size); return str_dst; } @@ -164,50 +164,53 @@ static const char *strdup_memarena(MemArena *memarena, const char *str) static const char *strdup_memarena_from_dynstr(MemArena *memarena, DynStr *dyn_str) { const uint str_size = BLI_dynstr_get_len(dyn_str) + 1; - char *str_dst = BLI_memarena_alloc(memarena, str_size); + char *str_dst = (char *)BLI_memarena_alloc(memarena, str_size); BLI_dynstr_get_cstring_ex(dyn_str, str_dst); return str_dst; } -static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *data, +static bool menu_items_from_ui_create_item_from_button(MenuSearch_Data *data, MemArena *memarena, struct MenuType *mt, const char *drawstr_submenu, uiBut *but, - struct MenuSearch_Context *wm_context) + MenuSearch_Context *wm_context) { - struct MenuSearch_Item *item = NULL; + MenuSearch_Item *item = nullptr; /* Use override if the name is empty, this can happen with popovers. */ - const char *drawstr_override = NULL; + const char *drawstr_override = nullptr; const char *drawstr_sep = (but->flag & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; const bool drawstr_is_empty = (drawstr_sep == but->drawstr) || (but->drawstr[0] == '\0'); - if (but->optype != NULL) { + if (but->optype != nullptr) { if (drawstr_is_empty) { drawstr_override = WM_operatortype_name(but->optype, but->opptr); } - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = but->optype; item->op.opcontext = but->opcontext; item->op.context = but->context; item->op.opptr = but->opptr; - but->opptr = NULL; + but->opptr = nullptr; } - else if (but->rnaprop != NULL) { + else if (but->rnaprop != nullptr) { const int prop_type = RNA_property_type(but->rnaprop); if (drawstr_is_empty) { if (prop_type == PROP_ENUM) { const int value_enum = (int)but->hardmax; EnumPropertyItem enum_item; - if (RNA_property_enum_item_from_value_gettexted( - but->block->evil_C, &but->rnapoin, but->rnaprop, value_enum, &enum_item)) { + if (RNA_property_enum_item_from_value_gettexted((bContext *)but->block->evil_C, + &but->rnapoin, + but->rnaprop, + value_enum, + &enum_item)) { drawstr_override = enum_item.name; } else { @@ -229,8 +232,8 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d prop_type); } else { - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_RNA; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::RNA; item->rna.ptr = but->rnapoin; item->rna.prop = but->rnaprop; @@ -242,13 +245,12 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d } } - if (item != NULL) { + if (item != nullptr) { /* Handle shared settings. */ - if (drawstr_override != NULL) { + if (drawstr_override != nullptr) { const char *drawstr_suffix = drawstr_sep ? drawstr_sep : ""; - char *drawstr_alloc = BLI_string_joinN("(", drawstr_override, ")", drawstr_suffix); - item->drawstr = strdup_memarena(memarena, drawstr_alloc); - MEM_freeN(drawstr_alloc); + std::string drawstr = std::string("(") + drawstr_override + ")" + drawstr_suffix; + item->drawstr = strdup_memarena(memarena, drawstr.c_str()); } else { item->drawstr = strdup_memarena(memarena, but->drawstr); @@ -258,7 +260,7 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d item->state = (but->flag & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_BUT_REDALERT | UI_BUT_HAS_SEP_CHAR)); item->mt = mt; - item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : NULL; + item->drawstr_submenu = drawstr_submenu ? strdup_memarena(memarena, drawstr_submenu) : nullptr; item->wm_context = wm_context; @@ -272,11 +274,11 @@ static bool menu_items_from_ui_create_item_from_button(struct MenuSearch_Data *d /** * Populate a fake button from a menu item (use for context menu). */ -static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) +static bool menu_items_to_ui_button(MenuSearch_Item *item, uiBut *but) { bool changed = false; switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { but->optype = item->op.type; but->opcontext = item->op.opcontext; but->context = item->op.context; @@ -284,7 +286,7 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) changed = true; break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { const int prop_type = RNA_property_type(item->rna.prop); but->rnapoin = item->rna.ptr; @@ -302,12 +304,12 @@ static bool menu_items_to_ui_button(struct MenuSearch_Item *item, uiBut *but) if (changed) { STRNCPY(but->drawstr, item->drawstr); char *drawstr_sep = (item->state & UI_BUT_HAS_SEP_CHAR) ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; if (drawstr_sep) { *drawstr_sep = '\0'; } - but->icon = item->icon; + but->icon = (BIFIconID)item->icon; but->str = but->strdata; } @@ -327,13 +329,13 @@ static void menu_types_add_from_keymap_items(bContext *C, { wmWindowManager *wm = CTX_wm_manager(C); ListBase *handlers[] = { - region ? ®ion->handlers : NULL, - area ? &area->handlers : NULL, + region ? ®ion->handlers : nullptr, + area ? &area->handlers : nullptr, &win->handlers, }; for (int handler_index = 0; handler_index < ARRAY_SIZE(handlers); handler_index++) { - if (handlers[handler_index] == NULL) { + if (handlers[handler_index] == nullptr) { continue; } LISTBASE_FOREACH (wmEventHandler *, handler_base, handlers[handler_index]) { @@ -345,7 +347,7 @@ static void menu_types_add_from_keymap_items(bContext *C, continue; } - if (handler_base->poll == NULL || handler_base->poll(region, win->eventstate)) { + if (handler_base->poll == nullptr || handler_base->poll(region, win->eventstate)) { wmEventHandler_Keymap *handler = (wmEventHandler_Keymap *)handler_base; wmEventHandler_KeymapResult km_result; WM_event_get_keymaps_from_handler(wm, win, handler, &km_result); @@ -382,16 +384,16 @@ static void menu_types_add_from_keymap_items(bContext *C, /** * Display all operators (last). Developer-only convenience feature. */ -static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *data) +static void menu_items_from_all_operators(bContext *C, MenuSearch_Data *data) { /* Add to temporary list so we can sort them separately. */ - ListBase operator_items = {NULL, NULL}; + ListBase operator_items = {nullptr, nullptr}; MemArena *memarena = data->memarena; GHashIterator iter; for (WM_operatortype_iter(&iter); !BLI_ghashIterator_done(&iter); BLI_ghashIterator_step(&iter)) { - wmOperatorType *ot = BLI_ghashIterator_getValue(&iter); + wmOperatorType *ot = (wmOperatorType *)BLI_ghashIterator_getValue(&iter); if ((ot->flag & OPTYPE_INTERNAL) && (G.debug & G_DEBUG_WM) == 0) { continue; @@ -400,13 +402,13 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d if (WM_operator_poll((bContext *)C, ot)) { const char *ot_ui_name = CTX_IFACE_(ot->translation_context, ot->name); - struct MenuSearch_Item *item = NULL; - item = BLI_memarena_calloc(memarena, sizeof(*item)); - item->type = MENU_SEARCH_TYPE_OP; + MenuSearch_Item *item = nullptr; + item = (MenuSearch_Item *)BLI_memarena_calloc(memarena, sizeof(*item)); + item->type = MenuSearch_Item::Type::Operator; item->op.type = ot; item->op.opcontext = WM_OP_INVOKE_DEFAULT; - item->op.context = NULL; + item->op.context = nullptr; char idname_as_py[OP_MAX_TYPENAME]; char uiname[256]; @@ -417,7 +419,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d item->drawwstr_full = strdup_memarena(memarena, uiname); item->drawstr = ot_ui_name; - item->wm_context = NULL; + item->wm_context = nullptr; BLI_addtail(&operator_items, item); } @@ -434,7 +436,7 @@ static void menu_items_from_all_operators(bContext *C, struct MenuSearch_Data *d * - Look up predefined editor-menus. * - Look up key-map items which call menus. */ -static struct MenuSearch_Data *menu_items_from_ui_create( +static MenuSearch_Data *menu_items_from_ui_create( bContext *C, wmWindow *win, ScrArea *area_init, ARegion *region_init, bool include_all_areas) { MemArena *memarena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -444,12 +446,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( const uiStyle *style = UI_style_get_dpi(); /* Convert into non-ui structure. */ - struct MenuSearch_Data *data = MEM_callocN(sizeof(*data), __func__); + MenuSearch_Data *data = (MenuSearch_Data *)MEM_callocN(sizeof(*data), __func__); DynStr *dyn_str = BLI_dynstr_new_memarena(); /* Use a stack of menus to handle and discover new menus in passes. */ - LinkNode *menu_stack = NULL; + LinkNode *menu_stack = nullptr; /* Tag menu types not to add, either because they have already been added * or they have been blacklisted. @@ -466,7 +468,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { BLI_gset_add(menu_tagged, mt); } } @@ -483,7 +485,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (WM_menutype_iter(&iter); (!BLI_ghashIterator_done(&iter)); (BLI_ghashIterator_step(&iter))) { - MenuType *mt = BLI_ghashIterator_getValue(&iter); + MenuType *mt = (MenuType *)BLI_ghashIterator_getValue(&iter); if (BLI_str_endswith(mt->idname, "_context_menu")) { BLI_gset_add(menu_tagged, mt); } @@ -494,34 +496,33 @@ static struct MenuSearch_Data *menu_items_from_ui_create( }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { - BLI_gset_remove(menu_tagged, mt, NULL); + if (mt != nullptr) { + BLI_gset_remove(menu_tagged, mt, nullptr); } } } /* Collect contexts, one for each 'ui_type'. */ - struct MenuSearch_Context *wm_contexts = NULL; + MenuSearch_Context *wm_contexts = nullptr; - const EnumPropertyItem *space_type_ui_items = NULL; + const EnumPropertyItem *space_type_ui_items = nullptr; int space_type_ui_items_len = 0; bool space_type_ui_items_free = false; /* Text used as prefix for top-bar menu items. */ - const char *global_menu_prefix = NULL; + const char *global_menu_prefix = nullptr; if (include_all_areas) { bScreen *screen = WM_window_get_active_screen(win); /* First create arrays for ui_type. */ - PropertyRNA *prop_ui_type = NULL; + PropertyRNA *prop_ui_type = nullptr; { /* This must be a valid pointer, with only it's type checked. */ - ScrArea area_dummy = { - /* Anything besides #SPACE_EMPTY is fine, - * as this value is only included in the enum when set. */ - .spacetype = SPACE_TOPBAR, - }; + ScrArea area_dummy = {nullptr}; + /* Anything besides #SPACE_EMPTY is fine, + * as this value is only included in the enum when set. */ + area_dummy.spacetype = SPACE_TOPBAR; PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, &area_dummy, &ptr); prop_ui_type = RNA_struct_find_property(&ptr, "ui_type"); @@ -532,7 +533,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( &space_type_ui_items_len, &space_type_ui_items_free); - wm_contexts = BLI_memarena_calloc(memarena, sizeof(*wm_contexts) * space_type_ui_items_len); + wm_contexts = (MenuSearch_Context *)BLI_memarena_calloc( + memarena, sizeof(*wm_contexts) * space_type_ui_items_len); for (int i = 0; i < space_type_ui_items_len; i++) { wm_contexts[i].space_type_ui_index = -1; } @@ -540,7 +542,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - if (region != NULL) { + if (region != nullptr) { PointerRNA ptr; RNA_pointer_create(&screen->id, &RNA_Area, area, &ptr); const int space_type_ui = RNA_property_enum_get(&ptr, prop_ui_type); @@ -573,16 +575,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( for (int space_type_ui_index = -1; space_type_ui_index < space_type_ui_items_len; space_type_ui_index += 1) { - ScrArea *area = NULL; - ARegion *region = NULL; - struct MenuSearch_Context *wm_context = NULL; + ScrArea *area = nullptr; + ARegion *region = nullptr; + MenuSearch_Context *wm_context = nullptr; if (include_all_areas) { if (space_type_ui_index == -1) { /* First run without any context, to populate the top-bar without. */ - wm_context = NULL; - area = NULL; - region = NULL; + wm_context = nullptr; + area = nullptr; + region = nullptr; } else { wm_context = &wm_contexts[space_type_ui_index]; @@ -607,7 +609,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * from the buttons, however this is quite involved and can be avoided as by convention * each space-type has a single root-menu that headers use. */ { - const char *idname_array[2] = {NULL}; + const char *idname_array[2] = {nullptr}; int idname_array_len = 0; /* Use negative for global (no area) context, populate the top-bar. */ @@ -623,8 +625,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( case space_type: \ break - if (area != NULL) { - SpaceLink *sl = area->spacedata.first; + if (area != nullptr) { + SpaceLink *sl = (SpaceLink *)area->spacedata.first; switch ((eSpace_Type)area->spacetype) { SPACE_MENU_MAP(SPACE_VIEW3D, "VIEW3D_MT_editor_menus"); SPACE_MENU_MAP(SPACE_GRAPH, "GRAPH_MT_editor_menus"); @@ -656,7 +658,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } for (int i = 0; i < idname_array_len; i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); - if (mt != NULL) { + if (mt != nullptr) { /* Check if this exists because of 'include_all_areas'. */ if (BLI_gset_add(menu_tagged, mt)) { BLI_linklist_prepend(&menu_stack, mt); @@ -669,8 +671,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( bool has_keymap_menu_items = false; - while (menu_stack != NULL) { - MenuType *mt = BLI_linklist_pop(&menu_stack); + while (menu_stack != nullptr) { + MenuType *mt = (MenuType *)BLI_linklist_pop(&menu_stack); if (!WM_menutype_poll(C, mt)) { continue; } @@ -687,7 +689,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( UI_block_end(C, block); LISTBASE_FOREACH (uiBut *, but, &block->buttons) { - MenuType *mt_from_but = NULL; + MenuType *mt_from_but = nullptr; /* Support menu titles with dynamic from initial labels * (used by edit-mesh context menu). */ if (but->type == UI_BTYPE_LABEL) { @@ -698,13 +700,13 @@ static struct MenuSearch_Data *menu_items_from_ui_create( but_test = but_test->prev; } - if (but_test == NULL) { + if (but_test == nullptr) { BLI_ghash_insert( menu_display_name_map, mt, (void *)strdup_memarena(memarena, but->drawstr)); } } else if (menu_items_from_ui_create_item_from_button( - data, memarena, mt, NULL, but, wm_context)) { + data, memarena, mt, nullptr, but, wm_context)) { /* pass */ } else if ((mt_from_but = UI_but_menutype_get(but))) { @@ -714,8 +716,8 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (!BLI_ghash_haskey(menu_parent_map, mt_from_but)) { - struct MenuSearch_Parent *menu_parent = BLI_memarena_calloc(memarena, - sizeof(*menu_parent)); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_memarena_calloc( + memarena, sizeof(*menu_parent)); /* Use brackets for menu key shortcuts, * converting "Text|Some-Shortcut" to "Text (Some-Shortcut)". * This is needed so we don't right align sub-menu contents @@ -723,9 +725,9 @@ static struct MenuSearch_Data *menu_items_from_ui_create( */ const char *drawstr_sep = but->flag & UI_BUT_HAS_SEP_CHAR ? strrchr(but->drawstr, UI_SEP_CHAR) : - NULL; + nullptr; bool drawstr_is_empty = false; - if (drawstr_sep != NULL) { + if (drawstr_sep != nullptr) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); /* Detect empty string, fallback to menu name. */ const char *drawstr = but->drawstr; @@ -760,7 +762,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } } - else if (but->menu_create_func != NULL) { + else if (but->menu_create_func != nullptr) { /* A non 'MenuType' menu button. */ /* Only expand one level deep, this is mainly for expanding operator menus. */ @@ -785,19 +787,21 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, sub_block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, sub_block); } - UI_block_free(NULL, sub_block); + UI_block_free(nullptr, sub_block); } } if (region) { + BLI_ghash_remove(region->runtime.block_name_map, block->name, nullptr, nullptr); BLI_remlink(®ion->uiblocks, block); } - UI_block_free(NULL, block); + UI_block_free(nullptr, block); /* Add key-map items as a second pass, * so all menus are accessed from the header & top-bar before key shortcuts are expanded. */ - if ((menu_stack == NULL) && (has_keymap_menu_items == false)) { + if ((menu_stack == nullptr) && (has_keymap_menu_items == false)) { has_keymap_menu_items = true; menu_types_add_from_keymap_items( C, win, area, region, &menu_stack, menu_to_kmi, menu_tagged); @@ -805,33 +809,34 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { - item->menu_parent = BLI_ghash_lookup(menu_parent_map, item->mt); + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { + item->menu_parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, item->mt); } GHASH_ITER (iter, menu_parent_map) { - struct MenuSearch_Parent *menu_parent = BLI_ghashIterator_getValue(&iter); - menu_parent->parent = BLI_ghash_lookup(menu_parent_map, menu_parent->parent_mt); + MenuSearch_Parent *menu_parent = (MenuSearch_Parent *)BLI_ghashIterator_getValue(&iter); + menu_parent->parent = (MenuSearch_Parent *)BLI_ghash_lookup(menu_parent_map, + menu_parent->parent_mt); } /* NOTE: currently this builds the full path for each menu item, * that could be moved into the parent menu. */ /* Set names as full paths. */ - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_assert(BLI_dynstr_get_len(dyn_str) == 0); if (include_all_areas) { BLI_dynstr_appendf(dyn_str, "%s: ", - (item->wm_context != NULL) ? + (item->wm_context != nullptr) ? space_type_ui_items[item->wm_context->space_type_ui_index].name : global_menu_prefix); } - if (item->menu_parent != NULL) { - struct MenuSearch_Parent *menu_parent = item->menu_parent; - menu_parent->temp_child = NULL; + if (item->menu_parent != nullptr) { + MenuSearch_Parent *menu_parent = item->menu_parent; + menu_parent->temp_child = nullptr; while (menu_parent && menu_parent->parent) { menu_parent->parent->temp_child = menu_parent; menu_parent = menu_parent->parent; @@ -843,14 +848,14 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } } else { - const char *drawstr = BLI_ghash_lookup(menu_display_name_map, item->mt); - if (drawstr == NULL) { + const char *drawstr = (const char *)BLI_ghash_lookup(menu_display_name_map, item->mt); + if (drawstr == nullptr) { drawstr = CTX_IFACE_(item->mt->translation_context, item->mt->label); } BLI_dynstr_append(dyn_str, drawstr); - wmKeyMapItem *kmi = BLI_ghash_lookup(menu_to_kmi, item->mt); - if (kmi != NULL) { + wmKeyMapItem *kmi = (wmKeyMapItem *)BLI_ghash_lookup(menu_to_kmi, item->mt); + if (kmi != nullptr) { char kmi_str[128]; WM_keymap_item_to_string(kmi, false, kmi_str, sizeof(kmi_str)); BLI_dynstr_appendf(dyn_str, " (%s)", kmi_str); @@ -860,7 +865,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( } /* Optional nested menu. */ - if (item->drawstr_submenu != NULL) { + if (item->drawstr_submenu != nullptr) { BLI_dynstr_append(dyn_str, item->drawstr_submenu); BLI_dynstr_append(dyn_str, " " UI_MENU_ARROW_SEP " "); } @@ -877,12 +882,12 @@ static struct MenuSearch_Data *menu_items_from_ui_create( * NOTE: we might want to keep the in-menu order, for now sort all. */ BLI_listbase_sort(&data->items, menu_item_sort_by_drawstr_full); - BLI_ghash_free(menu_parent_map, NULL, NULL); - BLI_ghash_free(menu_display_name_map, NULL, NULL); + BLI_ghash_free(menu_parent_map, nullptr, nullptr); + BLI_ghash_free(menu_display_name_map, nullptr, nullptr); - BLI_ghash_free(menu_to_kmi, NULL, NULL); + BLI_ghash_free(menu_to_kmi, nullptr, nullptr); - BLI_gset_free(menu_tagged, NULL); + BLI_gset_free(menu_tagged, nullptr); data->memarena = memarena; @@ -915,16 +920,16 @@ static struct MenuSearch_Data *menu_items_from_ui_create( static void menu_search_arg_free_fn(void *data_v) { - struct MenuSearch_Data *data = data_v; - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + MenuSearch_Data *data = (MenuSearch_Data *)data_v; + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { switch (item->type) { - case MENU_SEARCH_TYPE_OP: { - if (item->op.opptr != NULL) { + case MenuSearch_Item::Type::Operator: { + if (item->op.opptr != nullptr) { WM_operator_properties_free(item->op.opptr); MEM_freeN(item->op.opptr); } } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { break; } } @@ -937,8 +942,8 @@ static void menu_search_arg_free_fn(void *data_v) static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) { - struct MenuSearch_Item *item = arg2; - if (item == NULL) { + MenuSearch_Item *item = (MenuSearch_Item *)arg2; + if (item == nullptr) { return; } if (item->state & UI_BUT_DISABLED) { @@ -948,20 +953,20 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } switch (item->type) { - case MENU_SEARCH_TYPE_OP: { + case MenuSearch_Item::Type::Operator: { CTX_store_set(C, item->op.context); WM_operator_name_call_ptr_with_depends_on_cursor( C, item->op.type, item->op.opcontext, item->op.opptr, item->drawstr); - CTX_store_set(C, NULL); + CTX_store_set(C, nullptr); break; } - case MENU_SEARCH_TYPE_RNA: { + case MenuSearch_Item::Type::RNA: { PointerRNA *ptr = &item->rna.ptr; PropertyRNA *prop = item->rna.prop; const int index = item->rna.index; @@ -992,7 +997,7 @@ static void menu_search_exec_fn(bContext *C, void *UNUSED(arg1), void *arg2) } } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1004,19 +1009,19 @@ static void menu_search_update_fn(const bContext *UNUSED(C), uiSearchItems *items, const bool UNUSED(is_first)) { - struct MenuSearch_Data *data = arg; + MenuSearch_Data *data = (MenuSearch_Data *)arg; StringSearch *search = BLI_string_search_new(); - LISTBASE_FOREACH (struct MenuSearch_Item *, item, &data->items) { + LISTBASE_FOREACH (MenuSearch_Item *, item, &data->items) { BLI_string_search_add(search, item->drawwstr_full, item); } - struct MenuSearch_Item **filtered_items; + MenuSearch_Item **filtered_items; const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items); for (int i = 0; i < filtered_amount; i++) { - struct MenuSearch_Item *item = filtered_items[i]; + MenuSearch_Item *item = filtered_items[i]; if (!UI_search_item_add(items, item->drawwstr_full, item, item->icon, item->state, 0)) { break; } @@ -1041,8 +1046,8 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, void *active, const struct wmEvent *event) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; bool has_menu = false; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); @@ -1055,7 +1060,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } @@ -1064,7 +1069,7 @@ static bool ui_search_menu_create_context_menu(struct bContext *C, has_menu = true; } - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } @@ -1085,8 +1090,8 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void *arg, void *active) { - struct MenuSearch_Data *data = arg; - struct MenuSearch_Item *item = active; + MenuSearch_Data *data = (MenuSearch_Data *)arg; + MenuSearch_Item *item = (MenuSearch_Item *)active; memset(&data->context_menu_data, 0x0, sizeof(data->context_menu_data)); uiBut *but = &data->context_menu_data.but; @@ -1112,21 +1117,21 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, ScrArea *area_prev = CTX_wm_area(C); ARegion *region_prev = CTX_wm_region(C); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, item->wm_context->area); CTX_wm_region_set(C, item->wm_context->region); } ARegion *region_tip = UI_tooltip_create_from_button(C, region, but, false); - if (item->wm_context != NULL) { + if (item->wm_context != nullptr) { CTX_wm_area_set(C, area_prev); CTX_wm_region_set(C, region_prev); } return region_tip; } - return NULL; + return nullptr; } /** \} */ @@ -1137,14 +1142,13 @@ static struct ARegion *ui_search_menu_create_tooltip(struct bContext *C, void UI_but_func_menu_search(uiBut *but) { - bContext *C = but->block->evil_C; + bContext *C = (bContext *)but->block->evil_C; wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); ARegion *region = CTX_wm_region(C); /* When run from top-bar scan all areas in the current window. */ const bool include_all_areas = (area && (area->spacetype == SPACE_TOPBAR)); - struct MenuSearch_Data *data = menu_items_from_ui_create( - C, win, area, region, include_all_areas); + MenuSearch_Data *data = menu_items_from_ui_create(C, win, area, region, include_all_areas); UI_but_func_search_set(but, /* Generic callback. */ ui_searchbox_create_menu, @@ -1153,7 +1157,7 @@ void UI_but_func_menu_search(uiBut *but) false, menu_search_arg_free_fn, menu_search_exec_fn, - NULL); + nullptr); UI_but_func_search_set_context_menu(but, ui_search_menu_create_context_menu); UI_but_func_search_set_tooltip(but, ui_search_menu_create_tooltip); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 1d349aa0596..b30a86c5fcf 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1741,7 +1741,7 @@ static void template_search_add_button_name(uiBlock *block, static void template_search_add_button_operator(uiBlock *block, const char *const operator_name, - const int opcontext, + const wmOperatorCallContext opcontext, const int icon, const bool editable) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 7d1b7b80ccd..784f87d36c1 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -114,7 +114,6 @@ typedef enum { UI_WTYPE_LISTITEM, UI_WTYPE_PROGRESSBAR, UI_WTYPE_NODESOCKET, - UI_WTYPE_DATASETROW, UI_WTYPE_TREEROW, } uiWidgetTypeEnum; @@ -3675,13 +3674,7 @@ static void widget_treerow( widget_treerow_exec(wcol, rect, state, roundboxalign, tree_row->indentation); } -static void widget_datasetrow( - uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign) -{ - uiButDatasetRow *dataset_row = (uiButDatasetRow *)but; - BLI_assert(but->type == UI_BTYPE_DATASETROW); - widget_treerow_exec(wcol, rect, state, roundboxalign, dataset_row->indentation); -} + static void widget_nodesocket( uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign)) @@ -4476,9 +4469,6 @@ static uiWidgetType *widget_type(uiWidgetTypeEnum type) wt.custom = widget_progressbar; break; - case UI_WTYPE_DATASETROW: - wt.custom = widget_datasetrow; - break; case UI_WTYPE_TREEROW: wt.custom = widget_treerow; @@ -4811,11 +4801,6 @@ void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBu fstyle = &style->widgetlabel; break; - case UI_BTYPE_DATASETROW: - wt = widget_type(UI_WTYPE_DATASETROW); - fstyle = &style->widgetlabel; - break; - case UI_BTYPE_TREEROW: wt = widget_type(UI_WTYPE_TREEROW); fstyle = &style->widgetlabel; diff --git a/source/blender/editors/interface/tree_view.cc b/source/blender/editors/interface/tree_view.cc index fcc878c440c..5fcf78dd565 100644 --- a/source/blender/editors/interface/tree_view.cc +++ b/source/blender/editors/interface/tree_view.cc @@ -111,7 +111,10 @@ void AbstractTreeView::update_from_old(uiBlock &new_block) uiTreeViewHandle *old_view_handle = ui_block_view_find_matching_in_old_block( &new_block, reinterpret_cast<uiTreeViewHandle *>(this)); - BLI_assert(old_view_handle); + if (old_view_handle == nullptr) { + is_reconstructed_ = true; + return; + } AbstractTreeView &old_view = reinterpret_cast<AbstractTreeView &>(*old_view_handle); @@ -350,9 +353,14 @@ void AbstractTreeViewItem::on_activate() /* Do nothing by default. */ } -void AbstractTreeViewItem::is_active(IsActiveFn is_active_fn) +std::optional<bool> AbstractTreeViewItem::should_be_active() const { - is_active_fn_ = is_active_fn; + return std::nullopt; +} + +bool AbstractTreeViewItem::supports_collapsing() const +{ + return true; } std::unique_ptr<AbstractTreeViewItemDragController> AbstractTreeViewItem::create_drag_controller() @@ -504,7 +512,10 @@ void AbstractTreeViewItem::set_collapsed(bool collapsed) bool AbstractTreeViewItem::is_collapsible() const { - return !children_.is_empty(); + if (children_.is_empty()) { + return false; + } + return this->supports_collapsing(); } bool AbstractTreeViewItem::is_renaming() const @@ -546,7 +557,8 @@ uiButTreeRow *AbstractTreeViewItem::tree_row_button() void AbstractTreeViewItem::change_state_delayed() { - if (is_active_fn_()) { + const std::optional<bool> should_be_active = this->should_be_active(); + if (should_be_active.has_value() && *should_be_active) { activate(); } } @@ -670,11 +682,24 @@ void BasicTreeViewItem::on_activate() } } -void BasicTreeViewItem::on_activate(ActivateFn fn) +void BasicTreeViewItem::set_on_activate_fn(ActivateFn fn) { activate_fn_ = fn; } +void BasicTreeViewItem::set_is_active_fn(IsActiveFn is_active_fn) +{ + is_active_fn_ = is_active_fn; +} + +std::optional<bool> BasicTreeViewItem::should_be_active() const +{ + if (is_active_fn_) { + return is_active_fn_(); + } + return std::nullopt; +} + } // namespace blender::ui using namespace blender::ui; diff --git a/source/blender/editors/io/io_gpencil_export.c b/source/blender/editors/io/io_gpencil_export.c index b49be324372..556fae70828 100644 --- a/source/blender/editors/io/io_gpencil_export.c +++ b/source/blender/editors/io/io_gpencil_export.c @@ -410,6 +410,7 @@ void WM_OT_gpencil_export_pdf(wmOperatorType *ot) static const EnumPropertyItem gpencil_export_frame_items[] = { {GP_EXPORT_FRAME_ACTIVE, "ACTIVE", 0, "Active", "Include only active frame"}, {GP_EXPORT_FRAME_SELECTED, "SELECTED", 0, "Selected", "Include selected frames"}, + {GP_EXPORT_FRAME_SCENE, "SCENE", 0, "Scene", "Include all scene frames"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index e4cd48d95bb..912399c25b3 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -821,8 +821,8 @@ static int edbm_dupli_extrude_cursor_invoke(bContext *C, wmOperator *op, const w float view_vec[3], cross[3]; /* convert the 2D normal into 3D */ - mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* worldspace */ - mul_mat3_m4_v3(vc.obedit->imat, nor); /* local space */ + mul_mat3_m4_v3(vc.rv3d->viewinv, nor); /* World-space. */ + mul_mat3_m4_v3(vc.obedit->imat, nor); /* Local-space. */ /* correct the normal to be aligned on the view plane */ mul_v3_mat3_m4v3(view_vec, vc.obedit->imat, vc.rv3d->viewinv[2]); diff --git a/source/blender/editors/mesh/editmesh_extrude_spin.c b/source/blender/editors/mesh/editmesh_extrude_spin.c index 2146207308c..d7eaf58653f 100644 --- a/source/blender/editors/mesh/editmesh_extrude_spin.c +++ b/source/blender/editors/mesh/editmesh_extrude_spin.c @@ -80,7 +80,7 @@ static int edbm_spin_exec(bContext *C, wmOperator *op) BMesh *bm = em->bm; BMOperator spinop; - /* keep the values in worldspace since we're passing the obmat */ + /* Keep the values in world-space since we're passing the `obmat`. */ if (!EDBM_op_init(em, &spinop, op, diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index ee227c58fe7..18fe9cf7ad3 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -114,6 +114,7 @@ static void edbm_intersect_select(BMEditMesh *em, struct Mesh *me, bool do_selec } } } + EDBM_select_flush(em); } EDBM_update(me, diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index b712cfc24ed..76d48432834 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -236,7 +236,7 @@ typedef struct KnifeTool_OpData { GHash *facetrimap; KnifeBVH bvh; - const float (**cagecos)[3]; + float (**cagecos)[3]; BLI_mempool *kverts; BLI_mempool *kedges; @@ -491,7 +491,7 @@ static void knifetool_draw_visible_distances(const KnifeTool_OpData *kcd) float numstr_size[2]; float posit[2]; const float bg_margin = 4.0f * U.dpi_fac; - const int font_size = 14.0f * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int distance_precision = 4; /* Calculate distance and convert to string. */ @@ -561,7 +561,7 @@ static void knifetool_draw_angle(const KnifeTool_OpData *kcd, const float arc_size = 64.0f * U.dpi_fac; const float bg_margin = 4.0f * U.dpi_fac; const float cap_size = 4.0f * U.dpi_fac; - const int font_size = 14 * U.pixelsize; + const float font_size = 14.0f * U.pixelsize; const int angle_precision = 3; /* Angle arc in 3d space. */ @@ -3975,7 +3975,7 @@ static void knifetool_init_cagecos(KnifeTool_OpData *kcd, Object *ob, uint base_ BM_mesh_elem_index_ensure(em_eval->bm, BM_VERT); - kcd->cagecos[base_index] = (const float(*)[3])BKE_editmesh_vert_coords_alloc( + kcd->cagecos[base_index] = BKE_editmesh_vert_coords_alloc( kcd->vc.depsgraph, em_eval, scene_eval, obedit_eval, NULL); } diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index f81e2a65b9f..c77db10d74b 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -2166,7 +2166,7 @@ static void copy_object_set_idnew(bContext *C) Main *bmain = CTX_data_main(C); CTX_DATA_BEGIN (C, Object *, ob, selected_editable_objects) { - BKE_libblock_relink_to_newid(&ob->id); + BKE_libblock_relink_to_newid(bmain, &ob->id, 0); } CTX_DATA_END; @@ -2399,7 +2399,7 @@ static void make_object_duplilist_real(bContext *C, Object *ob_dst = BLI_ghash_lookup(dupli_gh, dob); /* Remap new object to itself, and clear again newid pointer of orig object. */ - BKE_libblock_relink_to_newid(&ob_dst->id); + BKE_libblock_relink_to_newid(bmain, &ob_dst->id, 0); DEG_id_tag_update(&ob_dst->id, ID_RECALC_GEOMETRY); @@ -3395,8 +3395,11 @@ Base *ED_object_add_duplicate( ob = basen->object; - /* link own references to the newly duplicated data T26816. */ - BKE_libblock_relink_to_newid(&ob->id); + /* Link own references to the newly duplicated data T26816. + * Note that this function can be called from edit-mode code, in which case we may have to + * enforce remapping obdata (by default this is forbidden in edit mode). */ + const int remap_flag = BKE_object_is_in_editmode(ob) ? ID_REMAP_FORCE_OBDATA_IN_EDITMODE : 0; + BKE_libblock_relink_to_newid(bmain, &ob->id, remap_flag); /* DAG_relations_tag_update(bmain); */ /* caller must do */ diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index aa15ce36582..b51644eebf3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1685,18 +1685,20 @@ static bool single_data_needs_duplication(ID *id) return (id != NULL && (id->us > 1 || ID_IS_LINKED(id))); } -static void libblock_relink_collection(Collection *collection, const bool do_collection) +static void libblock_relink_collection(Main *bmain, + Collection *collection, + const bool do_collection) { if (do_collection) { - BKE_libblock_relink_to_newid(&collection->id); + BKE_libblock_relink_to_newid(bmain, &collection->id, 0); } for (CollectionObject *cob = collection->gobject.first; cob != NULL; cob = cob->next) { - BKE_libblock_relink_to_newid(&cob->ob->id); + BKE_libblock_relink_to_newid(bmain, &cob->ob->id, 0); } LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - libblock_relink_collection(child->collection, true); + libblock_relink_collection(bmain, child->collection, true); } } @@ -1766,10 +1768,10 @@ static void single_object_users( single_object_users_collection(bmain, scene, master_collection, flag, copy_collections, true); /* Will also handle the master collection. */ - BKE_libblock_relink_to_newid(&scene->id); + BKE_libblock_relink_to_newid(bmain, &scene->id, 0); /* Collection and object pointers in collections */ - libblock_relink_collection(scene->master_collection, false); + libblock_relink_collection(bmain, scene->master_collection, false); /* We also have to handle runtime things in UI. */ if (v3d) { @@ -2654,7 +2656,7 @@ void OBJECT_OT_drop_named_material(wmOperatorType *ot) /* api callbacks */ ot->invoke = drop_named_material_invoke; - ot->poll = ED_operator_objectmode; + ot->poll = ED_operator_objectmode_poll_msg; /* flags */ ot->flag = OPTYPE_UNDO | OPTYPE_INTERNAL; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 97f3b96cd18..fc80767be9e 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -3903,8 +3903,8 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(co, key->co); mul_m4_v3(mat, co); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, co); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); @@ -3993,15 +3993,15 @@ static void brush_puff(PEData *data, int point_index, float mouse_distance) copy_v3_v3(oco, key->co); mul_m4_v3(mat, oco); - /* use 'kco' as the object space version of worldspace 'co', - * ob->imat is set before calling */ + /* Use `kco` as the object space version of world-space `co`, + * `ob->imat` is set before calling. */ mul_v3_m4v3(kco, data->ob->imat, oco); point_index = BLI_kdtree_3d_find_nearest(edit->emitter_field, kco, NULL); if (point_index != -1) { copy_v3_v3(onor, &edit->emitter_cosnos[point_index * 6 + 3]); - mul_mat3_m4_v3(data->ob->obmat, onor); /* normal into worldspace */ - mul_mat3_m4_v3(imat, onor); /* worldspace into particle space */ + mul_mat3_m4_v3(data->ob->obmat, onor); /* Normal into world-space. */ + mul_mat3_m4_v3(imat, onor); /* World-space into particle-space. */ normalize_v3(onor); } else { diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 80c14371c16..38eadf95bde 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -594,7 +594,7 @@ void ED_region_do_draw(bContext *C, ARegion *region) memset(®ion->drawrct, 0, sizeof(region->drawrct)); - UI_blocklist_free_inactive(C, ®ion->uiblocks); + UI_blocklist_free_inactive(C, region); if (area) { const bScreen *screen = WM_window_get_active_screen(win); @@ -1377,7 +1377,7 @@ static void region_rect_recursive( else if (alignment == RGN_ALIGN_FLOAT) { /** * \note Currently this window type is only used for #RGN_TYPE_HUD, - * We expect the panel to resize it's self to be larger. + * We expect the panel to resize itself to be larger. * * This aligns to the lower left of the area. */ @@ -1985,7 +1985,7 @@ void ED_area_init(wmWindowManager *wm, wmWindow *win, ScrArea *area) } else { /* prevent uiblocks to run */ - UI_blocklist_free(NULL, ®ion->uiblocks); + UI_blocklist_free(NULL, region); } /* Some AZones use View2D data which is only updated in region init, so call that first! */ @@ -3323,7 +3323,7 @@ bool ED_region_property_search(const bContext *C, } /* Free the panels and blocks, as they are only used for search. */ - UI_blocklist_free(C, ®ion->uiblocks); + UI_blocklist_free(C, region); UI_panels_free_instanced(C, region); BKE_area_region_panels_free(®ion->panels); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index fa0cfd16817..3c8fb2e7446 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -1495,8 +1495,7 @@ ScrArea *ED_screen_state_toggle(bContext *C, wmWindow *win, ScrArea *area, const * switching screens with tooltip open because region and tooltip * are no longer in the same screen */ LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { - UI_blocklist_free(C, ®ion->uiblocks); - + UI_blocklist_free(C, region); if (region->regiontimer) { WM_event_remove_timer(wm, NULL, region->regiontimer); region->regiontimer = NULL; diff --git a/source/blender/editors/screen/screen_user_menu.c b/source/blender/editors/screen/screen_user_menu.c index bc370c64b0c..4cad97652dd 100644 --- a/source/blender/editors/screen/screen_user_menu.c +++ b/source/blender/editors/screen/screen_user_menu.c @@ -111,7 +111,7 @@ bUserMenu *ED_screen_user_menu_ensure(bContext *C) bUserMenuItem_Op *ED_screen_user_menu_item_find_operator(ListBase *lb, const wmOperatorType *ot, IDProperty *prop, - short opcontext) + wmOperatorCallContext opcontext) { LISTBASE_FOREACH (bUserMenuItem *, umi, lb) { if (umi->type == USER_MENU_TYPE_OPERATOR) { @@ -160,7 +160,7 @@ void ED_screen_user_menu_item_add_operator(ListBase *lb, const char *ui_name, const wmOperatorType *ot, const IDProperty *prop, - short opcontext) + wmOperatorCallContext opcontext) { bUserMenuItem_Op *umi_op = (bUserMenuItem_Op *)BKE_blender_user_menu_item_add( lb, USER_MENU_TYPE_OPERATOR); diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index 3b668a1bd4c..b826ff8701d 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -44,6 +44,7 @@ set(SRC paint_hide.c paint_image.c paint_image_2d.c + paint_image_2d_curve_mask.cc paint_image_proj.c paint_mask.c paint_ops.c diff --git a/source/blender/editors/sculpt_paint/paint_image_2d.c b/source/blender/editors/sculpt_paint/paint_image_2d.c index 63f61b6c5c1..7191431cf4c 100644 --- a/source/blender/editors/sculpt_paint/paint_image_2d.c +++ b/source/blender/editors/sculpt_paint/paint_image_2d.c @@ -78,12 +78,13 @@ typedef struct BrushPainterCache { ImBuf *ibuf; ImBuf *texibuf; - ushort *curve_mask; ushort *tex_mask; ushort *tex_mask_old; uint tex_mask_old_w; uint tex_mask_old_h; + CurveMaskCache curve_mask_cache; + int image_size[2]; } BrushPainterCache; @@ -169,9 +170,6 @@ static void brush_painter_2d_require_imbuf( if (cache->ibuf) { IMB_freeImBuf(cache->ibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -179,7 +177,6 @@ static void brush_painter_2d_require_imbuf( MEM_freeN(cache->tex_mask_old); } cache->ibuf = NULL; - cache->curve_mask = NULL; cache->tex_mask = NULL; cache->lastdiameter = -1; /* force ibuf create in refresh */ cache->invert = invert; @@ -200,9 +197,7 @@ static void brush_painter_cache_2d_free(BrushPainterCache *cache) if (cache->texibuf) { IMB_freeImBuf(cache->texibuf); } - if (cache->curve_mask) { - MEM_freeN(cache->curve_mask); - } + paint_curve_mask_cache_free_data(&cache->curve_mask_cache); if (cache->tex_mask) { MEM_freeN(cache->tex_mask); } @@ -380,79 +375,6 @@ static void brush_painter_mask_imbuf_partial_update(BrushPainter *painter, cache->tex_mask_old_h = diameter; } -/* create a mask with the falloff strength */ -static ushort *brush_painter_curve_mask_new(BrushPainter *painter, - int diameter, - float radius, - const float pos[2]) -{ - Brush *brush = painter->brush; - - int offset = (int)floorf(diameter / 2.0f); - - ushort *mask, *m; - - mask = MEM_mallocN(sizeof(ushort) * diameter * diameter, "brush_painter_mask"); - m = mask; - - int aa_samples = 1.0f / (radius * 0.20f); - if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { - aa_samples = clamp_i(aa_samples, 3, 16); - } - else { - aa_samples = 1; - } - - /* Temporal until we have the brush properties */ - const float hardness = 1.0f; - const float rotation = 0.0f; - - float aa_offset = 1.0f / (2.0f * (float)aa_samples); - float aa_step = 1.0f / (float)aa_samples; - - float bpos[2]; - bpos[0] = pos[0] - floorf(pos[0]) + offset - aa_offset; - bpos[1] = pos[1] - floorf(pos[1]) + offset - aa_offset; - - const float co = cosf(DEG2RADF(rotation)); - const float si = sinf(DEG2RADF(rotation)); - - float norm_factor = 65535.0f / (float)(aa_samples * aa_samples); - - for (int y = 0; y < diameter; y++) { - for (int x = 0; x < diameter; x++, m++) { - float total_samples = 0; - for (int i = 0; i < aa_samples; i++) { - for (int j = 0; j < aa_samples; j++) { - float pixel_xy[2] = {x + (aa_step * i), y + (aa_step * j)}; - float xy_rot[2]; - sub_v2_v2(pixel_xy, bpos); - - xy_rot[0] = co * pixel_xy[0] - si * pixel_xy[1]; - xy_rot[1] = si * pixel_xy[0] + co * pixel_xy[1]; - - float len = len_v2(xy_rot); - float p = len / radius; - if (hardness < 1.0f) { - p = (p - hardness) / (1.0f - hardness); - p = 1.0f - p; - CLAMP(p, 0.0f, 1.0f); - } - else { - p = 1.0; - } - float hardness_factor = 3.0f * p * p - 2.0f * p * p * p; - float curve = BKE_brush_curve_strength_clamped(brush, len, radius); - total_samples += curve * hardness_factor; - } - } - *m = (ushort)(total_samples * norm_factor); - } - } - - return mask; -} - /* create imbuf with brush color */ static ImBuf *brush_painter_imbuf_new( BrushPainter *painter, ImagePaintTile *tile, const int size, float pressure, float distance) @@ -858,10 +780,8 @@ static void brush_painter_2d_refresh_cache(ImagePaintState *s, } } - /* curve mask can only change if the size changes */ - MEM_SAFE_FREE(cache->curve_mask); - - cache->curve_mask = brush_painter_curve_mask_new(painter, diameter, size, pos); + /* Re-initialize the curve mask. Mask is always recreated due to the change of position. */ + paint_curve_mask_cache_update(&cache->curve_mask_cache, brush, diameter, size, pos); /* detect if we need to recreate image brush buffer */ if (diameter != cache->lastdiameter || (tex_rotation != cache->last_tex_rotation) || do_random || @@ -1325,7 +1245,7 @@ static void paint_2d_do_making_brush(ImagePaintState *s, &tmpbuf, frombuf, mask, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region->destx, @@ -1474,7 +1394,7 @@ static int paint_2d_op(void *state, canvas, frombuf, NULL, - tile->cache.curve_mask, + tile->cache.curve_mask_cache.curve_mask, tile->cache.tex_mask, mask_max, region[a].destx, diff --git a/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc new file mode 100644 index 00000000000..8d57a3d9152 --- /dev/null +++ b/source/blender/editors/sculpt_paint/paint_image_2d_curve_mask.cc @@ -0,0 +1,188 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + */ + +/** \file + * \ingroup ed + */ + +#include "BLI_math.h" + +#include "MEM_guardedalloc.h" + +#include "DNA_brush_types.h" + +#include "BKE_brush.h" + +#include "paint_intern.h" + +namespace blender::ed::sculpt_paint { + +constexpr int AntiAliasingSamplesPerTexelAxisMin = 3; +constexpr int AntiAliasingSamplesPerTexelAxisMax = 16; +/** + * \brief Number of samples to use between 0..1. + */ +constexpr int CurveSamplesBaseLen = 1024; +/** + * \brief Number of samples to store in the cache. + * + * M_SQRT2 is used as brushes are circles and the curve_mask is square. + * + 1 to fix floating rounding issues. + */ +constexpr int CurveSamplesLen = M_SQRT2 * CurveSamplesBaseLen + 1; + +static int aa_samples_per_texel_axis(const Brush *brush, const float radius) +{ + int aa_samples = 1.0f / (radius * 0.20f); + if (brush->sampling_flag & BRUSH_PAINT_ANTIALIASING) { + aa_samples = clamp_i( + aa_samples, AntiAliasingSamplesPerTexelAxisMin, AntiAliasingSamplesPerTexelAxisMax); + } + else { + aa_samples = 1; + } + return aa_samples; +} + +/* create a mask with the falloff strength */ +static void update_curve_mask(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + BLI_assert(curve_mask_cache->curve_mask != nullptr); + int offset = (int)floorf(diameter / 2.0f); + + unsigned short *m = curve_mask_cache->curve_mask; + + const int aa_samples = aa_samples_per_texel_axis(brush, radius); + const float aa_offset = 1.0f / (2.0f * (float)aa_samples); + const float aa_step = 1.0f / (float)aa_samples; + + float bpos[2]; + bpos[0] = cursor_position[0] - floorf(cursor_position[0]) + offset; + bpos[1] = cursor_position[1] - floorf(cursor_position[1]) + offset; + + float weight_factor = 65535.0f / (float)(aa_samples * aa_samples); + + for (int y = 0; y < diameter; y++) { + for (int x = 0; x < diameter; x++, m++) { + float pixel_xy[2]; + pixel_xy[0] = static_cast<float>(x) + aa_offset; + float total_weight = 0; + + for (int i = 0; i < aa_samples; i++) { + pixel_xy[1] = static_cast<float>(y) + aa_offset; + for (int j = 0; j < aa_samples; j++) { + const float len = len_v2v2(pixel_xy, bpos); + const int sample_index = min_ii((len / radius) * CurveSamplesBaseLen, + CurveSamplesLen - 1); + const float sample_weight = curve_mask_cache->sampled_curve[sample_index]; + + total_weight += sample_weight; + + pixel_xy[1] += aa_step; + } + pixel_xy[0] += aa_step; + } + *m = (unsigned short)(total_weight * weight_factor); + } + } +} + +static bool is_sampled_curve_valid(const CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + return false; + } + return curve_mask_cache->last_curve_timestamp == brush->curve->changed_timestamp; +} + +static void sampled_curve_free(CurveMaskCache *curve_mask_cache) +{ + MEM_SAFE_FREE(curve_mask_cache->sampled_curve); + curve_mask_cache->last_curve_timestamp = 0; +} + +static void update_sampled_curve(CurveMaskCache *curve_mask_cache, const Brush *brush) +{ + if (curve_mask_cache->sampled_curve == nullptr) { + curve_mask_cache->sampled_curve = static_cast<float *>( + MEM_mallocN(CurveSamplesLen * sizeof(float), __func__)); + } + + for (int i = 0; i < CurveSamplesLen; i++) { + const float len = i / float(CurveSamplesBaseLen); + const float sample_weight = BKE_brush_curve_strength_clamped(brush, len, 1.0f); + curve_mask_cache->sampled_curve[i] = sample_weight; + } + curve_mask_cache->last_curve_timestamp = brush->curve->changed_timestamp; +} + +static size_t diameter_to_curve_mask_size(const int diameter) +{ + return diameter * diameter * sizeof(ushort); +} + +static bool is_curve_mask_size_valid(const CurveMaskCache *curve_mask_cache, const int diameter) +{ + return curve_mask_cache->curve_mask_size == diameter_to_curve_mask_size(diameter); +} + +static void curve_mask_free(CurveMaskCache *curve_mask_cache) +{ + curve_mask_cache->curve_mask_size = 0; + MEM_SAFE_FREE(curve_mask_cache->curve_mask); +} + +static void curve_mask_allocate(CurveMaskCache *curve_mask_cache, const int diameter) +{ + const size_t curve_mask_size = diameter_to_curve_mask_size(diameter); + curve_mask_cache->curve_mask = static_cast<unsigned short *>( + MEM_mallocN(curve_mask_size, __func__)); + curve_mask_cache->curve_mask_size = curve_mask_size; +} + +} // namespace blender::ed::sculpt_paint + +using namespace blender::ed::sculpt_paint; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache) +{ + sampled_curve_free(curve_mask_cache); + curve_mask_free(curve_mask_cache); +} + +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]) +{ + if (!is_sampled_curve_valid(curve_mask_cache, brush)) { + update_sampled_curve(curve_mask_cache, brush); + } + + if (!is_curve_mask_size_valid(curve_mask_cache, diameter)) { + curve_mask_free(curve_mask_cache); + curve_mask_allocate(curve_mask_cache, diameter); + } + update_curve_mask(curve_mask_cache, brush, diameter, radius, cursor_position); +} diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 89263bec7b1..db3e69b0953 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -3125,7 +3125,8 @@ static void project_paint_face_init(const ProjPaintState *ps, uv, v1coSS, v2coSS, v3coSS, uv1co, uv2co, uv3co, pixelScreenCo, w); } - /* a pity we need to get the worldspace pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, ps->mvert_eval[lt_vtri[0]].co, @@ -3208,7 +3209,10 @@ static void project_paint_face_init(const ProjPaintState *ps, else { /* we have a seam - deal with it! */ - /* inset face coords. NOTE!!! ScreenSace for ortho, Worldspace in perspective view */ + /* Inset face coords. + * - screen-space in orthographic view. + * - world-space in perspective view. + */ float insetCos[3][3]; /* Vertex screen-space coords. */ @@ -3373,8 +3377,8 @@ static void project_paint_face_init(const ProjPaintState *ps, if ((ps->do_occlude == false) || !project_bucket_point_occluded( ps, bucketFaceNodes, tri_index, pixel_on_edge)) { - /* a pity we need to get the worldspace - * pixel location here */ + /* A pity we need to get the world-space pixel location here + * because it is a relatively expensive operation. */ if (do_clip || do_3d_mapping) { interp_v3_v3v3v3(wco, vCo[0], vCo[1], vCo[2], w); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 7341d984c91..62320defbb3 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -23,6 +23,13 @@ #pragma once +#include "BKE_paint.h" +#include "DNA_scene_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + struct ARegion; struct Brush; struct ColorManagedDisplay; @@ -43,8 +50,6 @@ struct wmEvent; struct wmKeyConfig; struct wmOperator; struct wmOperatorType; -enum ePaintMode; -enum ePaintSymmetryFlags; typedef struct CoNo { float co[3]; @@ -245,6 +250,45 @@ void PAINT_OT_add_texture_paint_slot(struct wmOperatorType *ot); void PAINT_OT_image_paint(struct wmOperatorType *ot); void PAINT_OT_add_simple_uvs(struct wmOperatorType *ot); +/* paint_image_2d_curve_mask.cc */ +/** + * \brief Caching structure for curve mask. + * + * When 2d painting images the curve mask is used as an input. + */ +typedef struct CurveMaskCache { + /** + * \brief Last #CurveMapping.changed_timestamp being read. + * + * When different the input cache needs to be recalculated. + */ + int last_curve_timestamp; + + /** + * \brief sampled version of the brush curvemapping. + */ + float *sampled_curve; + + /** + * \brief Size in bytes of the curve_mask field. + * + * Used to determine if the curve_mask needs to be re-allocated. + */ + size_t curve_mask_size; + + /** + * \brief Curve mask that can be passed as curve_mask parameter when. + */ + ushort *curve_mask; +} CurveMaskCache; + +void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache); +void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, + const struct Brush *brush, + const int diameter, + const float radius, + const float cursor_position[2]); + /* sculpt_uv.c */ void SCULPT_OT_uv_sculpt_stroke(struct wmOperatorType *ot); @@ -366,3 +410,8 @@ void paint_delete_blur_kernel(BlurKernel *); /* paint curve defines */ #define PAINT_CURVE_NUM_SEGMENTS 40 + +#ifdef __cplusplus +} +#endif + diff --git a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c index f95e1d8d89c..f62d91acddf 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_color_ops.c @@ -210,9 +210,6 @@ static void vertex_color_smooth_looptag(Mesh *me, const bool *mlooptag) int(*scol)[4]; bool has_shared = false; - /* if no mloopcol: do not do */ - /* if mtexpoly: only the involved faces, otherwise all */ - if (me->mloopcol == NULL || me->totvert == 0 || me->totpoly == 0) { return; } diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 696c3332a2b..16df1efd969 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -366,10 +366,12 @@ float *SCULPT_boundary_automasking_init(Object *ob, /* Geodesic distances. */ -/* Returns an array indexed by vertex index containing the geodesic distance to the closest vertex -in the initial vertex set. The caller is responsible for freeing the array. -Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will -fallback to euclidean distances to one of the initial vertices in the set. */ +/** + * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex + * in the initial vertex set. The caller is responsible for freeing the array. + * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will + * fallback to euclidean distances to one of the initial vertices in the set. + */ float *SCULPT_geodesic_distances_create(struct Object *ob, struct GSet *initial_vertices, const float limit_radius); diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index a4fd2d81778..9ff46d96207 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -702,6 +702,9 @@ void ACTION_OT_unlink(wmOperatorType *ot) "Clear Fake User and remove " "copy stashed in this data-block's NLA stack"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } /* ************************************************************************** */ diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index b04291b7ab4..bc701bd7aa5 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -445,7 +445,7 @@ static void property_search_all_tabs(const bContext *C, i, property_search_for_context(C, region_copy, &sbuts_copy)); - UI_blocklist_free(C, ®ion_copy->uiblocks); + UI_blocklist_free(C, region_copy); } BKE_area_region_free(area_copy.type, region_copy); diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 834ef847069..97fcf4ef8ba 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -272,7 +272,7 @@ ImBuf *ED_space_clip_get_stable_buffer(SpaceClip *sc, float loc[2], float *scale } bool ED_space_clip_get_position(struct SpaceClip *sc, - struct ARegion *ar, + struct ARegion *region, int mval[2], float fpos[2]) { @@ -282,7 +282,7 @@ bool ED_space_clip_get_position(struct SpaceClip *sc, } /* map the mouse coords to the backdrop image space */ - ED_clip_mouse_pos(sc, ar, mval, fpos); + ED_clip_mouse_pos(sc, region, mval, fpos); IMB_freeImBuf(ibuf); return true; diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 41559278910..dee5168e30b 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -191,7 +191,8 @@ ui::BasicTreeViewItem &AssetCatalogTreeView::build_catalog_items_recursive( { ui::BasicTreeViewItem &view_item = view_parent_item.add_tree_item<AssetCatalogTreeViewItem>( &catalog); - view_item.is_active([this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); + view_item.set_is_active_fn( + [this, &catalog]() { return is_active_catalog(catalog.get_catalog_id()); }); catalog.foreach_child([&view_item, this](AssetCatalogTreeItem &child) { build_catalog_items_recursive(view_item, child); @@ -205,11 +206,11 @@ void AssetCatalogTreeView::add_all_item() AssetCatalogTreeViewAllItem &item = add_tree_item<AssetCatalogTreeViewAllItem>(IFACE_("All"), ICON_HOME); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_ALL_CATALOGS; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_ALL_CATALOGS; }); } @@ -220,11 +221,11 @@ void AssetCatalogTreeView::add_unassigned_item() AssetCatalogTreeViewUnassignedItem &item = add_tree_item<AssetCatalogTreeViewUnassignedItem>( IFACE_("Unassigned"), ICON_FILE_HIDDEN); - item.on_activate([params](ui::BasicTreeViewItem & /*item*/) { + item.set_on_activate_fn([params](ui::BasicTreeViewItem & /*item*/) { params->asset_catalog_visibility = FILE_SHOW_ASSETS_WITHOUT_CATALOG; WM_main_add_notifier(NC_SPACE | ND_SPACE_ASSET_PARAMS, nullptr); }); - item.is_active( + item.set_is_active_fn( [params]() { return params->asset_catalog_visibility == FILE_SHOW_ASSETS_WITHOUT_CATALOG; }); } diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 51a5c451f6d..6f929c43e13 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -1710,7 +1710,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry return; } - if (entry->flags & FILE_ENTRY_INVALID_PREVIEW) { + if (entry->flags & (FILE_ENTRY_INVALID_PREVIEW | FILE_ENTRY_PREVIEW_LOADING)) { return; } @@ -1741,6 +1741,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), __func__); preview_taskdata->preview = preview; + entry->flags |= FILE_ENTRY_PREVIEW_LOADING; BLI_task_pool_push(cache->previews_pool, filelist_cache_preview_runf, preview_taskdata, @@ -1896,6 +1897,7 @@ static void filelist_clear_asset_library(FileList *filelist) { /* The AssetLibraryService owns the AssetLibrary pointer, so no need for us to free it. */ filelist->asset_library = NULL; + file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter); } void filelist_clear_ex(struct FileList *filelist, @@ -1995,7 +1997,6 @@ void filelist_free(struct FileList *filelist) filelist->selection_state = NULL; } - file_delete_asset_catalog_filter_settings(&filelist->filter_data.asset_catalog_filter); MEM_SAFE_FREE(filelist->asset_library_ref); memset(&filelist->filter_data, 0, sizeof(filelist->filter_data)); @@ -2659,24 +2660,27 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: %d - %s - %p\n", __func__, preview->index, preview->path, preview->img); - if (preview->icon_id) { - /* Due to asynchronous process, a preview for a given image may be generated several times, - * i.e. entry->image may already be set at this point. */ - if (entry && !entry->preview_icon_id) { + if (entry) { + if (preview->icon_id) { + /* The FILE_ENTRY_PREVIEW_LOADING flag should have prevented any other asynchronous + * process from trying to generate the same preview icon. */ + BLI_assert_msg(!entry->preview_icon_id, "Preview icon should not have been generated yet"); + /* Move ownership over icon. */ entry->preview_icon_id = preview->icon_id; preview->icon_id = 0; changed = true; } else { - BKE_icon_delete(preview->icon_id); + /* We want to avoid re-processing this entry continuously! + * Note that, since entries only live in cache, + * preview will be retried quite often anyway. */ + entry->flags |= FILE_ENTRY_INVALID_PREVIEW; } + entry->flags &= ~FILE_ENTRY_PREVIEW_LOADING; } - else if (entry) { - /* We want to avoid re-processing this entry continuously! - * Note that, since entries only live in cache, - * preview will be retried quite often anyway. */ - entry->flags |= FILE_ENTRY_INVALID_PREVIEW; + else { + BKE_icon_delete(preview->icon_id); } MEM_freeN(preview); diff --git a/source/blender/editors/space_graph/graph_buttons.c b/source/blender/editors/space_graph/graph_buttons.c index 26a056ce1fb..41f74b6ade9 100644 --- a/source/blender/editors/space_graph/graph_buttons.c +++ b/source/blender/editors/space_graph/graph_buttons.c @@ -19,6 +19,8 @@ /** \file * \ingroup spgraph + * + * Graph editor space & buttons. */ #include <float.h> @@ -66,11 +68,11 @@ #include "graph_intern.h" /* own include */ -/* ******************* graph editor space & buttons ************** */ - #define B_REDR 1 -/* -------------- */ +/* -------------------------------------------------------------------- */ +/** \name Internal Utilities + * \{ */ static bool graph_panel_context(const bContext *C, bAnimListElem **ale, FCurve **fcu) { @@ -120,7 +122,11 @@ static bool graph_panel_poll(const bContext *C, PanelType *UNUSED(pt)) return graph_panel_context(C, NULL, NULL); } -/* -------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cursor Header + * \{ */ static void graph_panel_cursor_header(const bContext *C, Panel *panel) { @@ -174,7 +180,11 @@ static void graph_panel_cursor(const bContext *C, Panel *panel) uiItemO(sub, IFACE_("Cursor Value to Selection"), ICON_NONE, "GRAPH_OT_snap_cursor_value"); } -/* ******************* active F-Curve ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active F-Curve + * \{ */ static void graph_panel_properties(const bContext *C, Panel *panel) { @@ -243,7 +253,11 @@ static void graph_panel_properties(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* active Keyframe ************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active Keyframe + * \{ */ /* get 'active' keyframe for panel editing */ static bool get_active_fcurve_keyframe_edit(const FCurve *fcu, @@ -610,7 +624,11 @@ static void graph_panel_key_properties(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* drivers ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Drivers + * \{ */ #define B_IPO_DEPCHANGE 10 @@ -1320,8 +1338,13 @@ static void graph_panel_drivers_popover(const bContext *C, Panel *panel) uiItemO(layout, IFACE_("Show in Drivers Editor"), ICON_DRIVER, "SCREEN_OT_drivers_editor_show"); } -/* ******************* F-Modifiers ******************************** */ -/* All the drawing code is in editors/animation/fmodifier_ui.c */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name F-Curve Modifiers + * + * \note All the drawing code is in `editors/animation/fmodifier_ui.c` + * \{ */ #define B_FMODIFIER_REDRAW 20 /** The start of FModifier panels registered for the graph editor. */ @@ -1380,7 +1403,11 @@ static void graph_panel_modifiers(const bContext *C, Panel *panel) MEM_freeN(ale); } -/* ******************* general ******************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration + * \{ */ void graph_buttons_register(ARegionType *art) { @@ -1456,3 +1483,5 @@ void graph_buttons_register(ARegionType *art) pt->draw_header = graph_panel_cursor_header; BLI_addtail(&art->paneltypes, pt); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 1967dfabd21..2afee277847 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -19,6 +19,8 @@ /** \file * \ingroup spgraph + * + * Insert duplicate and bake keyframes. */ #include <float.h> @@ -69,9 +71,6 @@ #include "graph_intern.h" -/* ************************************************************************** */ -/* INSERT DUPLICATE AND BAKE KEYFRAMES */ - /* -------------------------------------------------------------------- */ /** \name Insert Keyframes Operator * \{ */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 32396a70cce..ecafc75fc06 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -52,11 +52,13 @@ /* ************************** view-based operators **********************************/ /* XXX should these really be here? */ -/* Set Cursor --------------------------------------------------------------------- */ -/* The 'cursor' in the Graph Editor consists of two parts: +/* -------------------------------------------------------------------- */ +/** \name Set Cursor + * + * The 'cursor' in the Graph Editor consists of two parts: * 1) Current Frame Indicator (as per ANIM_OT_change_frame) * 2) Value Indicator (stored per Graph Editor instance) - */ + * \{ */ static bool graphview_cursor_poll(bContext *C) { @@ -225,7 +227,11 @@ static void GRAPH_OT_cursor_set(wmOperatorType *ot) RNA_def_float(ot->srna, "value", 0, -FLT_MAX, FLT_MAX, "Value", "", -100.0f, 100.0f); } -/* Hide/Reveal ------------------------------------------------------------ */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Hide/Reveal + * \{ */ static int graphview_curves_hide_exec(bContext *C, wmOperator *op) { @@ -413,7 +419,11 @@ static void GRAPH_OT_reveal(wmOperatorType *ot) RNA_def_boolean(ot->srna, "select", true, "Select", ""); } -/* ************************** registration - operator types **********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration: operator types + * \{ */ void graphedit_operatortypes(void) { @@ -496,7 +506,11 @@ void ED_operatormacros_graph(void) RNA_boolean_set(otmacro->ptr, "use_proportional_edit", false); } -/* ************************** registration - keymaps **********************************/ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Registration: Key-Maps + * \{ */ void graphedit_keymap(wmKeyConfig *keyconf) { @@ -514,3 +528,5 @@ void graphedit_keymap(wmKeyConfig *keyconf) /* keyframes */ WM_keymap_ensure(keyconf, "Graph Editor", SPACE_GRAPH, 0); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index ffe74e20bdf..03bfd1092c6 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -56,8 +56,9 @@ #include "graph_intern.h" -/* ************************************************************************** */ -/* KEYFRAMES STUFF */ +/* -------------------------------------------------------------------- */ +/** \name Internal Keyframe Utilities + * \{ */ /* temp info for caching handle vertices close */ typedef struct tNearestVertInfo { @@ -334,14 +335,19 @@ static tNearestVertInfo *find_nearest_fcurve_vert(bAnimContext *ac, const int mv return nvi; } -/* ******************** Deselect All Operator ***************************** */ -/* This operator works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Deselect All Operator + * + * This operator works in one of three ways: * 1) (de)select all (AKEY) - test if select all or deselect all * 2) invert all (CTRL-IKEY) - invert selection of all keyframes * 3) (de)select all - no testing is done; only for use internal tools as normal function... - */ + * \{ */ -/* Deselects keyframes in the Graph Editor +/** + * Deselects keyframes in the Graph Editor * - This is called by the deselect all operator, as well as other ones! * * - test: check if select or deselect all @@ -490,8 +496,12 @@ void GRAPH_OT_select_all(wmOperatorType *ot) WM_operator_properties_select_all(ot); } -/* ******************** Box Select Operator **************************** */ -/* This operator currently works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Box Select Operator + * + * This operator currently works in one of three ways: * -> BKEY - 1) all keyframes within region are selected (validation with BEZT_OK_REGION) * -> ALT-BKEY - depending on which axis of the region was larger... * -> 2) x-axis, so select all frames within frame range (validation with BEZT_OK_FRAMERANGE) @@ -499,7 +509,7 @@ void GRAPH_OT_select_all(wmOperatorType *ot) * (validation with BEZT_OK_VALUERANGE). * * The selection backend is also reused for the Lasso and Circle select operators. - */ + * \{ */ static rctf initialize_box_select_coords(const bAnimContext *ac, const rctf *rectf_view) { @@ -572,7 +582,8 @@ static void initialize_box_select_key_editing_data(const SpaceGraph *sipo, *r_mapping_flag |= ANIM_get_normalization_flags(ac); } -/* Box Select only selects keyframes, as overshooting handles often get caught too, +/** + * Box Select only selects keyframes, as overshooting handles often get caught too, * which means that they may be inadvertently moved as well. However, incl_handles overrides * this, and allow handles to be considered independently too. * Also, for convenience, handles should get same status as keyframe (if it was within bounds). @@ -667,7 +678,8 @@ static bool box_select_graphkeys(bAnimContext *ac, return any_key_selection_changed; } -/* This function is used to set all the keyframes of a given curve as selectable +/** + * This function is used to set all the keyframes of a given curve as selectable * by the "select_cb" function inside of "box_select_graphcurves". */ static short ok_bezier_always_ok(KeyframeEditData *UNUSED(ked), BezTriple *UNUSED(bezt)) @@ -732,11 +744,12 @@ static bool rectf_curve_intersection( #undef INSIDE #undef BELOW -/* Perform a box selection of the curves themselves. This means this function tries +/** + * Perform a box selection of the curves themselves. This means this function tries * to select a curve by sampling it at various points instead of trying to select the * keyframes directly. * The selection actions done to a curve are actually done on all the keyframes of the curve. - * NOTE: This function is only called if no keyframe is in the selection area. + * \note This function is only called if no keyframe is in the selection area. */ static void box_select_graphcurves(bAnimContext *ac, const rctf *rectf_view, @@ -1107,13 +1120,17 @@ void GRAPH_OT_select_circle(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Column Select Operator **************************** */ -/* This operator works in one of four ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Column Select Operator + * + * This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) * - 2) select all keyframes in the same frame as the current frame marker (CTRL-KKEY) * - 3) select all keyframes in the same frame as a selected markers (SHIFT-KKEY) * - 4) select all keyframes that occur between selected markers (ALT-KKEY) - */ + * \{ */ /* defines for column-select mode */ static const EnumPropertyItem prop_column_select_types[] = { @@ -1297,7 +1314,11 @@ void GRAPH_OT_select_column(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "mode", prop_column_select_types, 0, "Mode", ""); } -/* ******************** Select Linked Operator *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Linked Operator + * \{ */ static int graphkeys_select_linked_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -1353,7 +1374,11 @@ void GRAPH_OT_select_linked(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select More/Less Operators *********************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select More/Less Operators + * \{ */ /* Common code to perform selection */ static void select_moreless_graph_keys(bAnimContext *ac, short mode) @@ -1467,8 +1492,13 @@ void GRAPH_OT_select_less(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ******************** Select Left/Right Operator ************************* */ -/* Select keyframes left/right of the current frame indicator */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Select Left/Right Operator + * + * Select keyframes left/right of the current frame indicator. + * \{ */ /* defines for left-right select tool */ static const EnumPropertyItem prop_graphkeys_leftright_select_types[] = { @@ -1628,15 +1658,19 @@ void GRAPH_OT_select_leftright(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ******************** Mouse-Click Select Operator *********************** */ -/* This operator works in one of three ways: +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Mouse-Click Select Operator + * + * This operator works in one of three ways: * - 1) keyframe under mouse - no special modifiers * - 2) all keyframes on the same side of current frame indicator as mouse - ALT modifier * - 3) column select all keyframes in frame under mouse - CTRL modifier * * In addition to these basic options, the SHIFT modifier can be used to toggle the * selection mode between replacing the selection (without) and inverting the selection (with). - */ + * \{ */ /* option 1) select keyframe directly under mouse */ static int mouse_graph_keys(bAnimContext *ac, @@ -1888,9 +1922,12 @@ static int graphkeys_mselect_column(bAnimContext *ac, return run_modal ? OPERATOR_RUNNING_MODAL : OPERATOR_FINISHED; } -/* ------------------- */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Click Select Operator + * \{ */ -/* handle clicking */ static int graphkeys_clickselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; @@ -1988,4 +2025,4 @@ void GRAPH_OT_clickselect(wmOperatorType *ot) RNA_def_property_flag(prop, PROP_SKIP_SAVE); } -/* ************************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index f04336cab84..4e62ab2df2d 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -17,6 +17,16 @@ * All rights reserved. */ +/** \file + * \ingroup spgraph + * + * Graph Slider Operators + * + * This file contains a collection of operators to modify keyframes in the graph editor. + * All operators are modal and use a slider that allows the user to define a percentage + * to modify the operator. + */ + #include <float.h> #include <string.h> @@ -48,42 +58,17 @@ #include "graph_intern.h" -/* ******************** GRAPH SLIDER OPERATORS ************************* */ -/* This file contains a collection of operators to modify keyframes in the graph editor. All - * operators are modal and use a slider that allows the user to define a percentage to modify the - * operator. */ - -/* ******************** Decimate Keyframes Operator ************************* */ - -static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) -{ - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - int filter; - - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - - /* Loop through filtered data and clean curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { - /* The selection contains unsupported keyframe types! */ - WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); - } - - ale->update |= ANIM_UPDATE_DEFAULT; - } - - ANIM_animdata_update(ac, &anim_data); - ANIM_animdata_freelist(&anim_data); -} +/* -------------------------------------------------------------------- */ +/** \name Internal Struct & Defines + * \{ */ -/* ------------------- */ +/* Used to obtain a list of animation channels for the operators to work on. */ +#define OPERATOR_DATA_FILTER \ + (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | ANIMFILTER_SEL | \ + ANIMFILTER_NODUPLIS) /* This data type is only used for modal operation. */ -typedef struct tDecimateGraphOp { +typedef struct tGraphSliderOp { bAnimContext ac; Scene *scene; ScrArea *area; @@ -98,35 +83,73 @@ typedef struct tDecimateGraphOp { struct tSlider *slider; NumInput num; -} tDecimateGraphOp; +} tGraphSliderOp; typedef struct tBeztCopyData { int tot_vert; BezTriple *bezt; } tBeztCopyData; -typedef enum tDecimModes { - DECIM_RATIO = 1, - DECIM_ERROR, -} tDecimModes; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Utility Functions + * \{ */ + +/* Construct a list with the original bezt arrays so we can restore them during modal operation. + * The data is stored on the struct that is passed.*/ +static void store_original_bezt_arrays(tGraphSliderOp *gso) +{ + ListBase anim_data = {NULL, NULL}; + bAnimContext *ac = &gso->ac; + bAnimListElem *ale; + + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + /* Loop through filtered data and copy the curves. */ + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + + if (fcu->bezt == NULL) { + /* This curve is baked, skip it. */ + continue; + } + + const int arr_size = sizeof(BezTriple) * fcu->totvert; + + tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); + BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); + + copy->tot_vert = fcu->totvert; + memcpy(bezts_copy, fcu->bezt, arr_size); + + copy->bezt = bezts_copy; + + LinkData *link = NULL; + + link = MEM_callocN(sizeof(LinkData), "Bezt Link"); + link->data = copy; + + BLI_addtail(&gso->bezt_arr_list, link); + } + + ANIM_animdata_freelist(&anim_data); +} /* Overwrite the current bezts arrays with the original data. */ -static void decimate_reset_bezts(tDecimateGraphOp *dgo) +static void reset_bezts(tGraphSliderOp *gso) { ListBase anim_data = {NULL, NULL}; LinkData *link_bezt; bAnimListElem *ale; - int filter; - bAnimContext *ac = &dgo->ac; + bAnimContext *ac = &gso->ac; /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); /* Loop through filtered data and reset bezts. */ - for (ale = anim_data.first, link_bezt = dgo->bezt_arr_list.first; ale; ale = ale->next) { + for (ale = anim_data.first, link_bezt = gso->bezt_arr_list.first; ale; ale = ale->next) { FCurve *fcu = (FCurve *)ale->key_data; if (fcu->bezt == NULL) { @@ -151,29 +174,62 @@ static void decimate_reset_bezts(tDecimateGraphOp *dgo) ANIM_animdata_freelist(&anim_data); } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Decimate Keyframes Operator + * \{ */ + +typedef enum tDecimModes { + DECIM_RATIO = 1, + DECIM_ERROR, +} tDecimModes; + +static void decimate_graph_keys(bAnimContext *ac, float remove_ratio, float error_sq_max) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + + /* Filter data. */ + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + /* Loop through filtered data and clean curves. */ + for (ale = anim_data.first; ale; ale = ale->next) { + if (!decimate_fcurve(ale, remove_ratio, error_sq_max)) { + /* The selection contains unsupported keyframe types! */ + WM_report(RPT_WARNING, "Decimate: Skipping non linear/bezier keyframes!"); + } + + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + static void decimate_exit(bContext *C, wmOperator *op) { - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; wmWindow *win = CTX_wm_window(C); /* If data exists, clear its data and exit. */ - if (dgo == NULL) { + if (gso == NULL) { return; } - ScrArea *area = dgo->area; + ScrArea *area = gso->area; LinkData *link; - ED_slider_destroy(C, dgo->slider); + ED_slider_destroy(C, gso->slider); - for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) { + for (link = gso->bezt_arr_list.first; link != NULL; link = link->next) { tBeztCopyData *copy = link->data; MEM_freeN(copy->bezt); MEM_freeN(link->data); } - BLI_freelistN(&dgo->bezt_arr_list); - MEM_freeN(dgo); + BLI_freelistN(&gso->bezt_arr_list); + MEM_freeN(gso); /* Return to normal cursor and header status. */ WM_cursor_modal_restore(win); @@ -184,20 +240,20 @@ static void decimate_exit(bContext *C, wmOperator *op) } /* Draw a percentage indicator in workspace footer. */ -static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo) +static void decimate_draw_status(bContext *C, tGraphSliderOp *gso) { char status_str[UI_MAX_DRAW_STR]; char mode_str[32]; char slider_string[UI_MAX_DRAW_STR]; - ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR); + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); strcpy(mode_str, TIP_("Decimate Keyframes")); - if (hasNumInput(&dgo->num)) { + if (hasNumInput(&gso->num)) { char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit); + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); } @@ -210,76 +266,34 @@ static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo) static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - tDecimateGraphOp *dgo; + tGraphSliderOp *gso; WM_cursor_modal_set(CTX_wm_window(C), WM_CURSOR_EW_SCROLL); /* Init slide-op data. */ - dgo = op->customdata = MEM_callocN(sizeof(tDecimateGraphOp), "tDecimateGraphOp"); + gso = op->customdata = MEM_callocN(sizeof(tGraphSliderOp), "tGraphSliderOp"); /* Get editor data. */ - if (ANIM_animdata_get_context(C, &dgo->ac) == 0) { + if (ANIM_animdata_get_context(C, &gso->ac) == 0) { decimate_exit(C, op); return OPERATOR_CANCELLED; } - dgo->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio"); - - dgo->scene = CTX_data_scene(C); - dgo->area = CTX_wm_area(C); - dgo->region = CTX_wm_region(C); - - dgo->slider = ED_slider_create(C); - ED_slider_init(dgo->slider, event); - ED_slider_allow_overshoot_set(dgo->slider, false); - - decimate_draw_status(C, dgo); - - /* Construct a list with the original bezt arrays so we can restore them during modal operation. - */ - { - ListBase anim_data = {NULL, NULL}; - bAnimContext *ac = &dgo->ac; - bAnimListElem *ale; + gso->percentage_prop = RNA_struct_find_property(op->ptr, "remove_ratio"); - int filter; + gso->scene = CTX_data_scene(C); + gso->area = CTX_wm_area(C); + gso->region = CTX_wm_region(C); - /* Filter data. */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | - ANIMFILTER_SEL | ANIMFILTER_NODUPLIS); - ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + store_original_bezt_arrays(gso); - /* Loop through filtered data and copy the curves. */ - for (ale = anim_data.first; ale; ale = ale->next) { - FCurve *fcu = (FCurve *)ale->key_data; + gso->slider = ED_slider_create(C); + ED_slider_init(gso->slider, event); + ED_slider_allow_overshoot_set(gso->slider, false); - if (fcu->bezt == NULL) { - /* This curve is baked, skip it. */ - continue; - } - - const int arr_size = sizeof(BezTriple) * fcu->totvert; - - tBeztCopyData *copy = MEM_mallocN(sizeof(tBeztCopyData), "bezts_copy"); - BezTriple *bezts_copy = MEM_mallocN(arr_size, "bezts_copy_array"); - - copy->tot_vert = fcu->totvert; - memcpy(bezts_copy, fcu->bezt, arr_size); - - copy->bezt = bezts_copy; - - LinkData *link = NULL; + decimate_draw_status(C, gso); - link = MEM_callocN(sizeof(LinkData), "Bezt Link"); - link->data = copy; - - BLI_addtail(&dgo->bezt_arr_list, link); - } - - ANIM_animdata_freelist(&anim_data); - } - - if (dgo->bezt_arr_list.first == NULL) { + if (gso->bezt_arr_list.first == NULL) { WM_report(RPT_WARNING, "Fcurve Decimate: Can't decimate baked channels. Unbake them and try again."); decimate_exit(C, op); @@ -294,19 +308,19 @@ static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op) { /* Perform decimate updates - in response to some user action * (e.g. pressing a key or moving the mouse). */ - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; - decimate_draw_status(C, dgo); + decimate_draw_status(C, gso); /* Reset keyframe data (so we get back to the original state). */ - decimate_reset_bezts(dgo); + reset_bezts(gso); /* Apply... */ - float remove_ratio = ED_slider_factor_get(dgo->slider); - RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio); + float remove_ratio = ED_slider_factor_get(gso->slider); + RNA_property_float_set(op->ptr, gso->percentage_prop, remove_ratio); /* We don't want to limit the decimation to a certain error margin. */ const float error_sq_max = FLT_MAX; - decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max); + decimate_graph_keys(&gso->ac, remove_ratio, error_sq_max); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); } @@ -316,11 +330,11 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * * and finicky to control with this modal mouse grab method. Therefore, it is expected that the * error margin mode is not adjusted by the modal operator but instead tweaked via the redo * panel. */ - tDecimateGraphOp *dgo = op->customdata; + tGraphSliderOp *gso = op->customdata; - const bool has_numinput = hasNumInput(&dgo->num); + const bool has_numinput = hasNumInput(&gso->num); - ED_slider_modal(dgo->slider, event); + ED_slider_modal(gso->slider, event); switch (event->type) { case LEFTMOUSE: /* Confirm */ @@ -337,7 +351,7 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * case EVT_ESCKEY: /* Cancel */ case RIGHTMOUSE: { if (event->val == KM_PRESS) { - decimate_reset_bezts(dgo); + reset_bezts(gso); WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); @@ -358,18 +372,18 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent * break; } default: { - if ((event->val == KM_PRESS) && handleNumInput(C, &dgo->num, event)) { + if ((event->val == KM_PRESS) && handleNumInput(C, &gso->num, event)) { float value; - float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); + float percentage = RNA_property_float_get(op->ptr, gso->percentage_prop); /* Grab percentage from numeric input, and store this new value for redo * NOTE: users see ints, while internally we use a 0-1 float. */ value = percentage * 100.0f; - applyNumInput(&dgo->num, &value); + applyNumInput(&gso->num, &value); percentage = value / 100.0f; - RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage); + RNA_property_float_set(op->ptr, gso->percentage_prop, percentage); /* Update decimate output to reflect the new values. */ graphkeys_decimate_modal_update(C, op); @@ -520,3 +534,5 @@ void GRAPH_OT_decimate(wmOperatorType *ot) 0.0f, 10.0f); } + +/** \} */ diff --git a/source/blender/editors/space_graph/graph_utils.c b/source/blender/editors/space_graph/graph_utils.c index c37d9f42c12..89e7fefd9ac 100644 --- a/source/blender/editors/space_graph/graph_utils.c +++ b/source/blender/editors/space_graph/graph_utils.c @@ -46,8 +46,9 @@ #include "graph_intern.h" /* own include */ -/* ************************************************************** */ -/* Set Up Drivers Editor */ +/* -------------------------------------------------------------------- */ +/** \name Set Up Drivers Editor + * \{ */ /* Set up UI configuration for Drivers Editor */ /* NOTE: Currently called from window-manager @@ -89,8 +90,11 @@ void ED_drivers_editor_init(bContext *C, ScrArea *area) } } -/* ************************************************************** */ -/* Active F-Curve */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Active F-Curve + * \{ */ /** * Find 'active' F-Curve. @@ -124,8 +128,11 @@ bAnimListElem *get_active_fcurve_channel(bAnimContext *ac) return NULL; } -/* ************************************************************** */ -/* Operator Polling Callbacks */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operator Polling Callbacks + * \{ */ /* Check if there are any visible keyframes (for selection tools) */ bool graphop_visible_keyframes_poll(bContext *C) @@ -321,4 +328,4 @@ bool graphop_selected_fcurve_poll(bContext *C) return true; } -/* ************************************************************** */ +/** \} */ diff --git a/source/blender/editors/space_graph/graph_view.c b/source/blender/editors/space_graph/graph_view.c index 56649c50cfd..a12c6053877 100644 --- a/source/blender/editors/space_graph/graph_view.c +++ b/source/blender/editors/space_graph/graph_view.c @@ -17,6 +17,10 @@ * All rights reserved. */ +/** \file + * \ingroup spgraph + */ + #include <math.h> #include "MEM_guardedalloc.h" @@ -48,7 +52,9 @@ #include "graph_intern.h" -/* *************************** Calculate Range ************************** */ +/* -------------------------------------------------------------------- */ +/** \name Calculate Range + * \{ */ /* Get the min/max keyframes. */ /* NOTE: it should return total boundbox, filter for selection only can be argument... */ @@ -194,7 +200,11 @@ void get_graph_keyframe_extents(bAnimContext *ac, } } -/* ****************** Automatic Preview-Range Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Automatic Preview-Range Operator + * \{ */ static int graphkeys_previewrange_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -241,7 +251,11 @@ void GRAPH_OT_previewrange_set(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } -/* ****************** View-All Operator ****************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View-All Operator + * \{ */ static int graphkeys_viewall(bContext *C, const bool do_sel_only, @@ -347,7 +361,11 @@ void GRAPH_OT_view_selected(wmOperatorType *ot) "Include handles of keyframes when calculating extents"); } -/* ********************** View Frame Operator ****************************** */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name View Frame Operator + * \{ */ static int graphkeys_view_frame_exec(bContext *C, wmOperator *op) { @@ -371,10 +389,14 @@ void GRAPH_OT_view_frame(wmOperatorType *ot) ot->flag = 0; } -/* ******************** Create Ghost-Curves Operator *********************** */ -/* This operator samples the data of the selected F-Curves to F-Points, storing them +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Create Ghost-Curves Operator + * + * This operator samples the data of the selected F-Curves to F-Points, storing them * as 'ghost curves' in the active Graph Editor. - */ + * \{ */ /* Bake each F-Curve into a set of samples, and store as a ghost curve. */ static void create_ghost_curves(bAnimContext *ac, int start, int end) @@ -493,8 +515,13 @@ void GRAPH_OT_ghost_curves_create(wmOperatorType *ot) /* TODO: add props for start/end frames */ } -/* ******************** Clear Ghost-Curves Operator *********************** */ -/* This operator clears the 'ghost curves' for the active Graph Editor */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Clear Ghost-Curves Operator + * + * This operator clears the 'ghost curves' for the active Graph Editor. + * \{ */ static int graphkeys_clear_ghostcurves_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -534,3 +561,5 @@ void GRAPH_OT_ghost_curves_clear(wmOperatorType *ot) /* Flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \} */ diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index 22a43ea3794..d76b1842c94 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -185,7 +185,7 @@ void ED_image_draw_info(Scene *scene, GPU_blend(GPU_BLEND_NONE); - BLF_size(blf_mono_font, 11 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 11.0f * U.pixelsize, U.dpi); BLF_color3ub(blf_mono_font, 255, 255, 255); SNPRINTF(str, "X:%-4d Y:%-4d |", x, y); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 478e484924a..44794439f5f 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -3191,7 +3191,10 @@ void IMAGE_OT_unpack(wmOperatorType *ot) * \{ */ /* Returns mouse position in image space. */ -bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[2], float fpos[2]) +bool ED_space_image_get_position(SpaceImage *sima, + struct ARegion *region, + int mval[2], + float fpos[2]) { void *lock; ImBuf *ibuf = ED_space_image_acquire_buffer(sima, &lock, 0); @@ -3201,7 +3204,7 @@ bool ED_space_image_get_position(SpaceImage *sima, struct ARegion *ar, int mval[ return false; } - UI_view2d_region_to_view(&ar->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); + UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &fpos[0], &fpos[1]); ED_space_image_release_buffer(sima, ibuf, lock); return true; diff --git a/source/blender/editors/space_info/CMakeLists.txt b/source/blender/editors/space_info/CMakeLists.txt index b6df07eec4e..144b21fb9b8 100644 --- a/source/blender/editors/space_info/CMakeLists.txt +++ b/source/blender/editors/space_info/CMakeLists.txt @@ -37,7 +37,7 @@ set(SRC info_draw.c info_ops.c info_report.c - info_stats.c + info_stats.cc space_info.c textview.c diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.cc index 13d15bc50a6..19c98fb4d17 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.cc @@ -18,8 +18,8 @@ * \ingroup spinfo */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -70,9 +70,11 @@ #include "GPU_capabilities.h" +ENUM_OPERATORS(eUserpref_StatusBar_Flag, STATUSBAR_SHOW_VERSION) + #define MAX_INFO_NUM_LEN 16 -typedef struct SceneStats { +struct SceneStats { uint64_t totvert, totvertsel, totvertsculpt; uint64_t totedge, totedgesel; uint64_t totface, totfacesel, totfacesculpt; @@ -81,9 +83,9 @@ typedef struct SceneStats { uint64_t totlamp, totlampsel; uint64_t tottri; uint64_t totgplayer, totgpframe, totgpstroke, totgppoint; -} SceneStats; +}; -typedef struct SceneStatsFmt { +struct SceneStatsFmt { /* Totals */ char totvert[MAX_INFO_NUM_LEN], totvertsel[MAX_INFO_NUM_LEN], totvertsculpt[MAX_INFO_NUM_LEN]; char totface[MAX_INFO_NUM_LEN], totfacesel[MAX_INFO_NUM_LEN]; @@ -94,16 +96,16 @@ typedef struct SceneStatsFmt { char tottri[MAX_INFO_NUM_LEN]; char totgplayer[MAX_INFO_NUM_LEN], totgpframe[MAX_INFO_NUM_LEN]; char totgpstroke[MAX_INFO_NUM_LEN], totgppoint[MAX_INFO_NUM_LEN]; -} SceneStatsFmt; +}; static bool stats_mesheval(const Mesh *me_eval, bool is_selected, SceneStats *stats) { - if (me_eval == NULL) { + if (me_eval == nullptr) { return false; } int totvert, totedge, totface, totloop; - if (me_eval->runtime.subdiv_ccg != NULL) { + if (me_eval->runtime.subdiv_ccg != nullptr) { const SubdivCCG *subdiv_ccg = me_eval->runtime.subdiv_ccg; BKE_subdiv_ccg_topology_counters(subdiv_ccg, &totvert, &totedge, &totface, &totloop); } @@ -166,14 +168,14 @@ static void stats_object(Object *ob, case OB_CURVE: case OB_FONT: { const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); - if ((me_eval != NULL) && !BLI_gset_add(objects_gset, (void *)me_eval)) { + if ((me_eval != nullptr) && !BLI_gset_add(objects_gset, (void *)me_eval)) { break; } if (stats_mesheval(me_eval, is_selected, stats)) { break; } - ATTR_FALLTHROUGH; /* Fallthrough to displist. */ + ATTR_FALLTHROUGH; /* Fall-through to displist. */ } case OB_MBALL: { int totv = 0, totf = 0, tottri = 0; @@ -242,10 +244,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_ARMATURE) { /* Armature Edit */ - bArmature *arm = obedit->data; - EditBone *ebo; + bArmature *arm = static_cast<bArmature *>(obedit->data); - for (ebo = arm->edbo->first; ebo; ebo = ebo->next) { + LISTBASE_FOREACH (EditBone *, ebo, arm->edbo) { stats->totbone++; if ((ebo->flag & BONE_CONNECTED) && ebo->parent) { @@ -274,14 +275,13 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (ELEM(obedit->type, OB_CURVE, OB_SURF)) { /* OB_FONT has no cu->editnurb */ /* Curve Edit */ - Curve *cu = obedit->data; - Nurb *nu; + Curve *cu = static_cast<Curve *>(obedit->data); BezTriple *bezt; BPoint *bp; int a; ListBase *nurbs = BKE_curve_editNurbs_get(cu); - for (nu = nurbs->first; nu; nu = nu->next) { + LISTBASE_FOREACH (Nurb *, nu, nurbs) { if (nu->type == CU_BEZIER) { bezt = nu->bezt; a = nu->pntsu; @@ -314,10 +314,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_MBALL) { /* MetaBall Edit */ - MetaBall *mball = obedit->data; - MetaElem *ml; + MetaBall *mball = static_cast<MetaBall *>(obedit->data); - for (ml = mball->editelems->first; ml; ml = ml->next) { + LISTBASE_FOREACH (MetaElem *, ml, mball->editelems) { stats->totvert++; if (ml->flag & SELECT) { stats->totvertsel++; @@ -326,7 +325,7 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) } else if (obedit->type == OB_LATTICE) { /* Lattice Edit */ - Lattice *lt = obedit->data; + Lattice *lt = static_cast<Lattice *>(obedit->data); Lattice *editlatt = lt->editlatt->latt; BPoint *bp; int a; @@ -347,10 +346,9 @@ static void stats_object_edit(Object *obedit, SceneStats *stats) static void stats_object_pose(const Object *ob, SceneStats *stats) { if (ob->pose) { - bArmature *arm = ob->data; - bPoseChannel *pchan; + bArmature *arm = static_cast<bArmature *>(ob->data); - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { stats->totbone++; if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { if (pchan->bone->layer & arm->layer) { @@ -372,7 +370,7 @@ static void stats_object_sculpt(const Object *ob, SceneStats *stats) SculptSession *ss = ob->sculpt; - if (ss == NULL || ss->pbvh == NULL) { + if (ss == nullptr || ss->pbvh == nullptr) { return; } @@ -460,7 +458,7 @@ static void stats_update(Depsgraph *depsgraph, stats_object(ob_iter, v3d_local, stats, objects_gset); } DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; - BLI_gset_free(objects_gset, NULL); + BLI_gset_free(objects_gset, nullptr); } } @@ -476,7 +474,7 @@ void ED_info_stats_clear(wmWindowManager *wm, ViewLayer *view_layer) const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_VIEW3D) { - View3D *v3d = area->spacedata.first; + View3D *v3d = (View3D *)area->spacedata.first; if (v3d->localvd) { MEM_SAFE_FREE(v3d->runtime.local_stats); } @@ -490,14 +488,14 @@ static bool format_stats( { /* Create stats if they don't already exist. */ SceneStats **stats_p = (v3d_local) ? &v3d_local->runtime.local_stats : &view_layer->stats; - if (*stats_p == NULL) { + if (*stats_p == nullptr) { /* Don't access dependency graph if interface is marked as locked. */ - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = (wmWindowManager *)bmain->wm.first; if (wm->is_interface_locked) { return false; } Depsgraph *depsgraph = BKE_scene_ensure_depsgraph(bmain, scene, view_layer); - *stats_p = MEM_mallocN(sizeof(SceneStats), __func__); + *stats_p = (SceneStats *)MEM_mallocN(sizeof(SceneStats), __func__); stats_update(depsgraph, view_layer, v3d_local, *stats_p); } @@ -542,7 +540,7 @@ static void get_stats_string( { Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; LayerCollection *layer_collection = view_layer->active_collection; if (object_mode == OB_MODE_OBJECT) { @@ -646,7 +644,7 @@ static const char *info_statusbar_string(Main *bmain, /* Scene statistics. */ if (statusbar_flag & STATUSBAR_SHOW_STATS) { SceneStatsFmt stats_fmt; - if (format_stats(bmain, scene, view_layer, NULL, &stats_fmt)) { + if (format_stats(bmain, scene, view_layer, nullptr, &stats_fmt)) { get_stats_string(info + ofs, len, &ofs, view_layer, &stats_fmt); } } @@ -731,7 +729,7 @@ static void stats_row(int col1, void ED_info_draw_stats( Main *bmain, Scene *scene, ViewLayer *view_layer, View3D *v3d_local, int x, int *y, int height) { - BLI_assert(v3d_local == NULL || v3d_local->localvd != NULL); + BLI_assert(v3d_local == nullptr || v3d_local->localvd != nullptr); SceneStatsFmt stats_fmt; if (!format_stats(bmain, scene, view_layer, v3d_local, &stats_fmt)) { return; @@ -739,7 +737,7 @@ void ED_info_draw_stats( Object *ob = OBACT(view_layer); Object *obedit = OBEDIT_FROM_OBACT(ob); - eObjectMode object_mode = ob ? ob->mode : OB_MODE_OBJECT; + eObjectMode object_mode = ob ? (eObjectMode)ob->mode : OB_MODE_OBJECT; const int font_id = BLF_set_default(); UI_FontThemeColor(font_id, TH_TEXT_HI); @@ -801,7 +799,7 @@ void ED_info_draw_stats( stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); stats_row(col1, labels[EDGES], col2, stats_fmt.totedgesel, stats_fmt.totedge, y, height); stats_row(col1, labels[FACES], col2, stats_fmt.totfacesel, stats_fmt.totface, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else if (obedit->type == OB_ARMATURE) { stats_row(col1, labels[JOINTS], col2, stats_fmt.totvertsel, stats_fmt.totvert, y, height); @@ -816,15 +814,15 @@ void ED_info_draw_stats( stats_row(col1, labels[BONES], col2, stats_fmt.totbonesel, stats_fmt.totbone, y, height); } else if ((ob) && (ob->type == OB_GPENCIL)) { - stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, NULL, y, height); - stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, NULL, y, height); - stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, NULL, y, height); - stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, NULL, y, height); + stats_row(col1, labels[LAYERS], col2, stats_fmt.totgplayer, nullptr, y, height); + stats_row(col1, labels[FRAMES], col2, stats_fmt.totgpframe, nullptr, y, height); + stats_row(col1, labels[STROKES], col2, stats_fmt.totgpstroke, nullptr, y, height); + stats_row(col1, labels[POINTS], col2, stats_fmt.totgppoint, nullptr, y, height); } else if (ob && (object_mode & OB_MODE_SCULPT)) { if (stats_is_object_dynamic_topology_sculpt(ob)) { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } else { stats_row(col1, labels[VERTS], col2, stats_fmt.totvertsculpt, stats_fmt.totvert, y, height); @@ -835,10 +833,10 @@ void ED_info_draw_stats( stats_row(col1, labels[LIGHTS], col2, stats_fmt.totlampsel, stats_fmt.totlamp, y, height); } else { - stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, NULL, y, height); - stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, NULL, y, height); - stats_row(col1, labels[FACES], col2, stats_fmt.totface, NULL, y, height); - stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, NULL, y, height); + stats_row(col1, labels[VERTS], col2, stats_fmt.totvert, nullptr, y, height); + stats_row(col1, labels[EDGES], col2, stats_fmt.totedge, nullptr, y, height); + stats_row(col1, labels[FACES], col2, stats_fmt.totface, nullptr, y, height); + stats_row(col1, labels[TRIS], col2, stats_fmt.tottri, nullptr, y, height); } BLF_disable(font_id, BLF_SHADOW); diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index 600309c2c86..e88d61fe880 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -44,17 +44,17 @@ set(SRC node_draw.cc node_edit.cc node_geometry_attribute_search.cc - node_gizmo.c + node_gizmo.cc node_group.cc - node_ops.c + node_ops.cc node_relationships.cc node_select.cc node_templates.cc node_toolbar.cc node_view.cc - space_node.c + space_node.cc - node_intern.h + node_intern.hh ) set(LIB diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 57fecba76f7..97fa93ab0bc 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -77,7 +77,7 @@ #include "NOD_node_declaration.hh" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ #define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME @@ -152,7 +152,7 @@ static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *pt uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Sta"), ICON_NONE); + uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } @@ -337,12 +337,13 @@ static void node_draw_frame_prepare(const bContext *UNUSED(C), bNodeTree *ntree, node->totr = rect; } -static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float aspect) +static void node_draw_frame_label(bNodeTree *ntree, bNode *node, SpaceNode *snode) { + const float aspect = snode->runtime->aspect; /* XXX font id is crap design */ const int fontid = UI_style_get()->widgetlabel.uifont_id; NodeFrame *data = (NodeFrame *)node->storage; - const int font_size = data->label_size / aspect; + const float font_size = data->label_size / aspect; char label[MAX_NAME]; nodeLabel(ntree, node, label, sizeof(label)); @@ -350,7 +351,7 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp BLF_enable(fontid, BLF_ASPECT); BLF_aspect(fontid, aspect, aspect, 1.0f); /* clamp otherwise it can suck up a LOT of memory */ - BLF_size(fontid, MIN2(24, font_size), U.dpi); + BLF_size(fontid, MIN2(24.0f, font_size), U.dpi); /* title color */ int color_id = node_get_colorid(node); @@ -468,7 +469,9 @@ static void node_draw_frame(const bContext *C, } /* label and text */ - node_draw_frame_label(ntree, node, snode->runtime->aspect); + node_draw_frame_label(ntree, node, snode); + + node_draw_extra_info_panel(snode, node); UI_block_end(C, node->block); UI_block_draw(C, node->block); @@ -4399,7 +4402,10 @@ void node_draw_link_bezier(const bContext *C, } /* NOTE: this is used for fake links in groups too. */ -void node_draw_link(const bContext *C, View2D *v2d, SpaceNode *snode, bNodeLink *link) +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link) { int th_col1 = TH_WIRE_INNER, th_col2 = TH_WIRE_INNER, th_col3 = TH_WIRE; diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index f84de363430..2e3579caaa1 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -56,7 +56,7 @@ #include "UI_view2d.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Utilities diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc index a0ff7f3ce25..2f3855fd654 100644 --- a/source/blender/editors/space_node/node_context_path.cc +++ b/source/blender/editors/space_node/node_context_path.cc @@ -43,7 +43,7 @@ #include "UI_interface.hh" -#include "node_intern.h" +#include "node_intern.hh" struct Mesh; struct Curve; diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index b6c24a55a78..1aa6ec4e56c 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -85,7 +85,9 @@ #include "FN_field_cpp_type.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ + +#include <iomanip> #ifdef WITH_COMPOSITOR # include "COM_compositor.h" @@ -843,29 +845,43 @@ struct SocketTooltipData { bNodeSocket *socket; }; -static void create_inspection_string_for_generic_value(const geo_log::GenericValueLog &value_log, - std::stringstream &ss) +static void create_inspection_string_for_generic_value(const GPointer value, std::stringstream &ss) { auto id_to_inspection_string = [&](ID *id, short idcode) { ss << (id ? id->name + 2 : TIP_("None")) << " (" << BKE_idtype_idcode_to_name(idcode) << ")"; }; - const GPointer value = value_log.value(); const CPPType &type = *value.type(); + const void *buffer = value.get(); if (type.is<Object *>()) { - id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB); + id_to_inspection_string((ID *)buffer, ID_OB); } else if (type.is<Material *>()) { - id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA); + id_to_inspection_string((ID *)buffer, ID_MA); } else if (type.is<Tex *>()) { - id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE); + id_to_inspection_string((ID *)buffer, ID_TE); } else if (type.is<Image *>()) { - id_to_inspection_string((ID *)*value.get<Image *>(), ID_IM); + id_to_inspection_string((ID *)buffer, ID_IM); } else if (type.is<Collection *>()) { - id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR); + id_to_inspection_string((ID *)buffer, ID_GR); + } + else if (type.is<int>()) { + ss << *(int *)buffer << TIP_(" (Integer)"); + } + else if (type.is<float>()) { + ss << *(float *)buffer << TIP_(" (Float)"); + } + else if (type.is<blender::float3>()) { + ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); + } + else if (type.is<bool>()) { + ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); + } + else if (type.is<std::string>()) { + ss << *(std::string *)buffer << TIP_(" (String)"); } } @@ -880,21 +896,7 @@ static void create_inspection_string_for_gfield(const geo_log::GFieldValueLog &v if (field) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); blender::fn::evaluate_constant_field(field, buffer); - if (type.is<int>()) { - ss << *(int *)buffer << TIP_(" (Integer)"); - } - else if (type.is<float>()) { - ss << *(float *)buffer << TIP_(" (Float)"); - } - else if (type.is<blender::float3>()) { - ss << *(blender::float3 *)buffer << TIP_(" (Vector)"); - } - else if (type.is<bool>()) { - ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)"); - } - else if (type.is<std::string>()) { - ss << *(std::string *)buffer << TIP_(" (String)"); - } + create_inspection_string_for_generic_value({type, buffer}, ss); type.destruct(buffer); } else { @@ -1023,7 +1025,7 @@ static std::optional<std::string> create_socket_inspection_string(bContext *C, std::stringstream ss; if (const geo_log::GenericValueLog *generic_value_log = dynamic_cast<const geo_log::GenericValueLog *>(value_log)) { - create_inspection_string_for_generic_value(*generic_value_log, ss); + create_inspection_string_for_generic_value(generic_value_log->value(), ss); } if (const geo_log::GFieldValueLog *gfield_value_log = dynamic_cast<const geo_log::GFieldValueLog *>(value_log)) { @@ -1107,21 +1109,8 @@ static void node_socket_draw_nested(const bContext *C, C, *data->ntree, *data->node, *data->socket); std::stringstream output; - if (data->node->declaration != nullptr) { - ListBase *list; - Span<blender::nodes::SocketDeclarationPtr> decl_list; - - if (data->socket->in_out == SOCK_IN) { - list = &data->node->inputs; - decl_list = data->node->declaration->inputs(); - } - else { - list = &data->node->outputs; - decl_list = data->node->declaration->outputs(); - } - - const int socket_index = BLI_findindex(list, data->socket); - const blender::nodes::SocketDeclaration &socket_decl = *decl_list[socket_index]; + if (data->socket->declaration != nullptr) { + const blender::nodes::SocketDeclaration &socket_decl = *data->socket->declaration; blender::StringRef description = socket_decl.description(); if (!description.is_empty()) { output << TIP_(description.data()) << ".\n\n"; @@ -1590,6 +1579,237 @@ static void node_add_error_message_button( UI_block_emboss_set(node.block, UI_EMBOSS); } +static void get_exec_time_other_nodes(const bNode *node, + const SpaceNode *snode, + std::chrono::microseconds &exec_time, + int &node_count) +{ + if (node->type == NODE_GROUP) { + const geo_log::TreeLog *root_tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( + *snode); + if (root_tree_log == nullptr) { + return; + } + const geo_log::TreeLog *tree_log = root_tree_log->lookup_child_log(node->name); + if (tree_log == nullptr) { + return; + } + tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { + exec_time += node_log.execution_time(); + node_count++; + }); + } + else { + const geo_log::NodeLog *node_log = geo_log::ModifierLog::find_node_by_node_editor_context( + *snode, *node); + if (node_log) { + exec_time += node_log->execution_time(); + node_count++; + } + } +} + +static std::chrono::microseconds node_get_execution_time(const bNodeTree *ntree, + const bNode *node, + const SpaceNode *snode, + int &node_count) +{ + std::chrono::microseconds exec_time = std::chrono::microseconds::zero(); + if (node->type == NODE_GROUP_OUTPUT) { + const geo_log::TreeLog *tree_log = geo_log::ModifierLog::find_tree_by_node_editor_context( + *snode); + + if (tree_log == nullptr) { + return exec_time; + } + tree_log->foreach_node_log([&](const geo_log::NodeLog &node_log) { + exec_time += node_log.execution_time(); + node_count++; + }); + } + else if (node->type == NODE_FRAME) { + /* Could be cached in the future if this recursive code turns out to be slow. */ + LISTBASE_FOREACH (bNode *, tnode, &ntree->nodes) { + if (tnode->parent != node) { + continue; + } + + if (tnode->type == NODE_FRAME) { + exec_time += node_get_execution_time(ntree, tnode, snode, node_count); + } + else { + get_exec_time_other_nodes(tnode, snode, exec_time, node_count); + } + } + } + else { + get_exec_time_other_nodes(node, snode, exec_time, node_count); + } + return exec_time; +} + +static std::string node_get_execution_time_label(const SpaceNode *snode, const bNode *node) +{ + int node_count = 0; + std::chrono::microseconds exec_time = node_get_execution_time( + snode->nodetree, node, snode, node_count); + + if (node_count == 0) { + return std::string(""); + } + + uint64_t exec_time_us = exec_time.count(); + + /* Don't show time if execution time is 0 microseconds. */ + if (exec_time_us == 0) { + return std::string("-"); + } + else if (exec_time_us < 100) { + return std::string("< 0.1 ms"); + } + else { + short precision = 0; + /* Show decimal if value is below 1ms */ + if (exec_time_us < 1000) { + precision = 2; + } + else if (exec_time_us < 10000) { + precision = 1; + } + + std::stringstream stream; + stream << std::fixed << std::setprecision(precision) << (exec_time_us / 1000.0f); + return std::string(stream.str() + " ms"); + } + return std::string(""); +} + +struct NodeExtraInfoRow { + std::string text; + const char *tooltip; + int icon; +}; + +static Vector<NodeExtraInfoRow> node_get_extra_info(const SpaceNode *snode, const bNode *node) +{ + Vector<NodeExtraInfoRow> rows; + if (!(snode->overlay.flag & SN_OVERLAY_SHOW_OVERLAYS)) { + return rows; + } + + if (snode->overlay.flag & SN_OVERLAY_SHOW_TIMINGS && snode->edittree->type == NTREE_GEOMETRY && + (ELEM(node->typeinfo->nclass, NODE_CLASS_GEOMETRY, NODE_CLASS_GROUP, NODE_CLASS_ATTRIBUTE) || + ELEM(node->type, NODE_FRAME, NODE_GROUP_OUTPUT))) { + NodeExtraInfoRow row; + row.text = node_get_execution_time_label(snode, node); + if (!row.text.empty()) { + row.tooltip = TIP_( + "The execution time from the node tree's latest evaluation. For frame and group nodes, " + "the time for all sub-nodes"); + row.icon = ICON_PREVIEW_RANGE; + rows.append(std::move(row)); + } + } + return rows; +} + +static void node_draw_extra_info_row(const bNode *node, + const rctf *rect, + const int row, + const NodeExtraInfoRow &extra_info_row) +{ + uiBut *but_timing = uiDefBut(node->block, + UI_BTYPE_LABEL, + 0, + extra_info_row.text.c_str(), + (int)(rect->xmin + 4.0f * U.dpi_fac + NODE_MARGIN_X + 0.4f), + (int)(rect->ymin + row * (20.0f * U.dpi_fac)), + (short)(rect->xmax - rect->xmin), + (short)NODE_DY, + nullptr, + 0, + 0, + 0, + 0, + ""); + UI_block_emboss_set(node->block, UI_EMBOSS_NONE); + uiBut *but_icon = uiDefIconBut(node->block, + UI_BTYPE_BUT, + 0, + extra_info_row.icon, + (int)(rect->xmin + 6.0f * U.dpi_fac), + (int)(rect->ymin + row * (20.0f * U.dpi_fac)), + NODE_HEADER_ICON_SIZE * 0.8f, + UI_UNIT_Y, + nullptr, + 0, + 0, + 0, + 0, + extra_info_row.tooltip); + UI_block_emboss_set(node->block, UI_EMBOSS); + if (node->flag & NODE_MUTED) { + UI_but_flag_enable(but_timing, UI_BUT_INACTIVE); + UI_but_flag_enable(but_icon, UI_BUT_INACTIVE); + } +} + +void node_draw_extra_info_panel(const SpaceNode *snode, const bNode *node) +{ + Vector<NodeExtraInfoRow> extra_info_rows = node_get_extra_info(snode, node); + + if (extra_info_rows.size() == 0) { + return; + } + + const rctf *rct = &node->totr; + float color[4]; + rctf extra_info_rect; + + if (node->type == NODE_FRAME) { + extra_info_rect.xmin = rct->xmin; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; + extra_info_rect.ymin = rct->ymin + 2.0f * U.dpi_fac; + extra_info_rect.ymax = rct->ymin + 2.0f * U.dpi_fac; + } + else { + extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac; + extra_info_rect.ymin = rct->ymax; + extra_info_rect.ymax = rct->ymax + extra_info_rows.size() * (20.0f * U.dpi_fac); + + if (node->flag & NODE_MUTED) { + UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.2f, color); + } + else { + UI_GetThemeColorBlend4f(TH_BACK, TH_NODE, 0.75f, color); + } + color[3] -= 0.35f; + UI_draw_roundbox_corner_set( + UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & + ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); + UI_draw_roundbox_4fv(&extra_info_rect, true, BASIS_RAD, color); + + /* Draw outline. */ + const float outline_width = 1.0f; + extra_info_rect.xmin = rct->xmin + 3.0f * U.dpi_fac - outline_width; + extra_info_rect.xmax = rct->xmin + 95.0f * U.dpi_fac + outline_width; + extra_info_rect.ymin = rct->ymax - outline_width; + extra_info_rect.ymax = rct->ymax + outline_width + + extra_info_rows.size() * (20.0f * U.dpi_fac); + + UI_GetThemeColorBlendShade4fv(TH_BACK, TH_NODE, 0.4f, -20, color); + UI_draw_roundbox_corner_set( + UI_CNR_ALL & ~UI_CNR_BOTTOM_LEFT & + ((rct->xmax) > extra_info_rect.xmax ? ~UI_CNR_BOTTOM_RIGHT : UI_CNR_ALL)); + UI_draw_roundbox_4fv(&extra_info_rect, false, BASIS_RAD, color); + } + + for (int row : extra_info_rows.index_range()) { + node_draw_extra_info_row(node, &extra_info_rect, row, extra_info_rows[row]); + } +} + static void node_draw_basis(const bContext *C, const View2D *v2d, const SpaceNode *snode, @@ -1615,6 +1835,8 @@ static void node_draw_basis(const bContext *C, GPU_line_width(1.0f); + node_draw_extra_info_panel(snode, node); + /* Header. */ { const rctf rect = { @@ -1855,7 +2077,13 @@ static void node_draw_basis(const bContext *C, UI_draw_roundbox_4fv(&rect, false, BASIS_RAD, color_outline); } - node_draw_sockets(v2d, C, ntree, node, true, false); + float scale; + UI_view2d_scale_get(v2d, &scale, nullptr); + + /* Skip slow socket drawing if zoom is small. */ + if (scale > 0.2f) { + node_draw_sockets(v2d, C, ntree, node, true, false); + } /* Preview. */ bNodeInstanceHash *previews = (bNodeInstanceHash *)CTX_data_pointer_get(C, "node_previews").data; @@ -2123,15 +2351,15 @@ static void count_multi_input_socket_links(bNodeTree *ntree, SpaceNode *snode) } } /* Count temporary links going into this socket. */ - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { if (link->tosock && (link->tosock->flag & SOCK_MULTI_INPUT)) { int &count = counts.lookup_or_add(link->tosock, 0); count++; } } } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { if (socket->flag & SOCK_MULTI_INPUT) { @@ -2390,9 +2618,9 @@ void node_draw_space(const bContext *C, ARegion *region) /* Temporary links. */ GPU_blend(GPU_BLEND_ALPHA); GPU_line_smooth(true); - LISTBASE_FOREACH (bNodeLinkDrag *, nldrag, &snode->runtime->linkdrag) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - node_draw_link(C, v2d, snode, (bNodeLink *)linkdata->data); + if (snode->runtime->linkdrag) { + for (const bNodeLink *link : snode->runtime->linkdrag->links) { + node_draw_link(C, v2d, snode, link); } } GPU_line_smooth(false); diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index 030d1672a08..30c9f7ea56b 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -76,7 +76,7 @@ #include "NOD_geometry.h" #include "NOD_shader.h" #include "NOD_texture.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ #define USE_ESC_COMPO @@ -1192,7 +1192,7 @@ static bool cursor_isect_multi_input_socket(const float cursor[2], const bNodeSo } /* type is SOCK_IN and/or SOCK_OUT */ -int node_find_indicated_socket( +bool node_find_indicated_socket( SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out) { rctf rect; @@ -1224,7 +1224,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1232,7 +1232,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1245,7 +1245,7 @@ int node_find_indicated_socket( if (node == visible_node(snode, &rect)) { *nodep = node; *sockp = sock; - return 1; + return true; } } } @@ -1253,7 +1253,7 @@ int node_find_indicated_socket( } } - return 0; + return false; } /* ****************** Link Dimming *********************** */ @@ -1775,8 +1775,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { - /* Only allow muting of nodes having a mute func! */ - if ((node->flag & SELECT) && node->typeinfo->update_internal_links) { + if ((node->flag & SELECT) && !node->typeinfo->no_muting) { node->flag ^= NODE_MUTED; snode_update(snode, node); do_tag_update |= (do_tag_update || node_connected_to_output(bmain, snode->edittree, node)); diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 063e6348123..79ba9b8d2d9 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -44,7 +44,7 @@ #include "NOD_geometry_nodes_eval_log.hh" -#include "node_intern.h" +#include "node_intern.hh" using blender::IndexRange; using blender::Map; diff --git a/source/blender/editors/space_node/node_gizmo.c b/source/blender/editors/space_node/node_gizmo.cc index e1deca54890..717f4d2f4f9 100644 --- a/source/blender/editors/space_node/node_gizmo.c +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -18,7 +18,7 @@ * \ingroup spnode */ -#include <math.h> +#include <cmath> #include "BLI_math_matrix.h" #include "BLI_math_vector.h" @@ -41,7 +41,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" +#include "node_intern.hh" /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -80,9 +80,9 @@ static void gizmo_node_backdrop_prop_matrix_get(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - const SpaceNode *snode = gz_prop->custom_func.user_data; + const SpaceNode *snode = (const SpaceNode *)gz_prop->custom_func.user_data; matrix[0][0] = snode->zoom; matrix[1][1] = snode->zoom; matrix[3][0] = snode->xof; @@ -93,9 +93,9 @@ static void gizmo_node_backdrop_prop_matrix_set(const wmGizmo *UNUSED(gz), wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - SpaceNode *snode = gz_prop->custom_func.user_data; + SpaceNode *snode = (SpaceNode *)gz_prop->custom_func.user_data; snode->zoom = matrix[0][0]; snode->xof = matrix[3][0]; snode->yof = matrix[3][1]; @@ -122,9 +122,9 @@ static bool WIDGETGROUP_node_transform_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_transform_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - wmGizmoWrapper *wwrapper = MEM_mallocN(sizeof(wmGizmoWrapper), __func__); + wmGizmoWrapper *wwrapper = (wmGizmoWrapper *)MEM_mallocN(sizeof(wmGizmoWrapper), __func__); - wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + wwrapper->gizmo = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(wwrapper->gizmo->ptr, "transform", @@ -139,11 +139,11 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * wmGizmo *cage = ((wmGizmoWrapper *)gzgroup->customdata)->gizmo; const ARegion *region = CTX_wm_region(C); /* center is always at the origin */ - const float origin[3] = {region->winx / 2, region->winy / 2}; + const float origin[3] = {float(region->winx / 2), float(region->winy / 2), 0.0f}; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { const float dims[2] = { @@ -164,14 +164,12 @@ static void WIDGETGROUP_node_transform_refresh(const bContext *C, wmGizmoGroup * WM_gizmo_target_property_def_rna(cage, "scale", &nodeptr, "backdrop_zoom", -1); #endif - WM_gizmo_target_property_def_func(cage, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_backdrop_prop_matrix_get, - .value_set_fn = gizmo_node_backdrop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = snode, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_backdrop_prop_matrix_get; + params.value_set_fn = gizmo_node_backdrop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(cage, "matrix", ¶ms); } else { WM_gizmo_set_flag(cage, WM_GIZMO_HIDDEN, true); @@ -262,12 +260,12 @@ static void gizmo_node_crop_prop_matrix_get(const wmGizmo *gz, wmGizmoProperty *gz_prop, void *value_p) { - float(*matrix)[4] = value_p; + float(*matrix)[4] = (float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - const bNode *node = gz_prop->custom_func.user_data; - const NodeTwoXYs *nxy = node->storage; + const bNode *node = (const bNode *)gz_prop->custom_func.user_data; + const NodeTwoXYs *nxy = (const NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -281,12 +279,12 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, wmGizmoProperty *gz_prop, const void *value_p) { - const float(*matrix)[4] = value_p; + const float(*matrix)[4] = (const float(*)[4])value_p; BLI_assert(gz_prop->type->array_length == 16); - struct NodeCropWidgetGroup *crop_group = gz->parent_gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gz->parent_gzgroup->customdata; const float *dims = crop_group->state.dims; - bNode *node = gz_prop->custom_func.user_data; - NodeTwoXYs *nxy = node->storage; + bNode *node = (bNode *)gz_prop->custom_func.user_data; + NodeTwoXYs *nxy = (NodeTwoXYs *)node->storage; bool is_relative = (bool)node->custom2; rctf rct; two_xy_to_rect(nxy, &rct, dims, is_relative); @@ -294,15 +292,8 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, const bool ny = rct.ymin > rct.ymax; BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1])); BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); - BLI_rctf_isect( - &(rctf){ - .xmin = 0, - .ymin = 0, - .xmax = 1, - .ymax = 1, - }, - &rct, - &rct); + const rctf rct_isect{0, 0, 1, 1}; + BLI_rctf_isect(&rct_isect, &rct, &rct); if (nx) { SWAP(float, rct.xmin, rct.xmax); } @@ -337,10 +328,10 @@ static bool WIDGETGROUP_node_crop_poll(const bContext *C, wmGizmoGroupType *UNUS static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCropWidgetGroup *crop_group = MEM_mallocN(sizeof(struct NodeCropWidgetGroup), - __func__); + struct NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)MEM_mallocN( + sizeof(struct NodeCropWidgetGroup), __func__); - crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, NULL); + crop_group->border = WM_gizmo_new("GIZMO_GT_cage_2d", gzgroup, nullptr); RNA_enum_set(crop_group->border->ptr, "transform", @@ -352,7 +343,7 @@ static void WIDGETGROUP_node_crop_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -362,12 +353,12 @@ static void WIDGETGROUP_node_crop_draw_prepare(const bContext *C, wmGizmoGroup * static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCropWidgetGroup *crop_group = gzgroup->customdata; + NodeCropWidgetGroup *crop_group = (NodeCropWidgetGroup *)gzgroup->customdata; wmGizmo *gz = crop_group->border; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { crop_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -385,14 +376,12 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro crop_group->update_data.prop = RNA_struct_find_property(&crop_group->update_data.ptr, "relative"); - WM_gizmo_target_property_def_func(gz, - "matrix", - &(const struct wmGizmoPropertyFnParams){ - .value_get_fn = gizmo_node_crop_prop_matrix_get, - .value_set_fn = gizmo_node_crop_prop_matrix_set, - .range_get_fn = NULL, - .user_data = node, - }); + wmGizmoPropertyFnParams params{}; + params.value_get_fn = gizmo_node_crop_prop_matrix_get; + params.value_set_fn = gizmo_node_crop_prop_matrix_set; + params.range_get_fn = nullptr; + params.user_data = snode; + WM_gizmo_target_property_def_func(gz, "matrix", ¶ms); } else { WM_gizmo_set_flag(gz, WM_GIZMO_HIDDEN, true); @@ -450,10 +439,10 @@ static bool WIDGETGROUP_node_sbeam_poll(const bContext *C, wmGizmoGroupType *UNU static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = MEM_mallocN(sizeof(struct NodeSunBeamsWidgetGroup), - __func__); + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)MEM_mallocN( + sizeof(NodeSunBeamsWidgetGroup), __func__); - sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, NULL); + sbeam_group->gizmo = WM_gizmo_new("GIZMO_GT_move_3d", gzgroup, nullptr); wmGizmo *gz = sbeam_group->gizmo; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -465,9 +454,9 @@ static void WIDGETGROUP_node_sbeam_setup(const bContext *UNUSED(C), wmGizmoGroup static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); - wmGizmo *gz = gzgroup->gizmos.first; + wmGizmo *gz = (wmGizmo *)gzgroup->gizmos.first; SpaceNode *snode = CTX_wm_space_node(C); @@ -478,12 +467,12 @@ static void WIDGETGROUP_node_sbeam_draw_prepare(const bContext *C, wmGizmoGroup static void WIDGETGROUP_node_sbeam_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeSunBeamsWidgetGroup *sbeam_group = gzgroup->customdata; + NodeSunBeamsWidgetGroup *sbeam_group = (NodeSunBeamsWidgetGroup *)gzgroup->customdata; wmGizmo *gz = sbeam_group->gizmo; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { sbeam_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -555,12 +544,12 @@ static bool WIDGETGROUP_node_corner_pin_poll(const bContext *C, wmGizmoGroupType static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = MEM_mallocN( - sizeof(struct NodeCornerPinWidgetGroup), __func__); + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)MEM_mallocN( + sizeof(NodeCornerPinWidgetGroup), __func__); const wmGizmoType *gzt_move_3d = WM_gizmotype_find("GIZMO_GT_move_3d", false); for (int i = 0; i < 4; i++) { - cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, NULL); + cpin_group->gizmos[i] = WM_gizmo_new_ptr(gzt_move_3d, gzgroup, nullptr); wmGizmo *gz = cpin_group->gizmos[i]; RNA_enum_set(gz->ptr, "draw_style", ED_GIZMO_MOVE_STYLE_CROSS_2D); @@ -573,7 +562,7 @@ static void WIDGETGROUP_node_corner_pin_setup(const bContext *UNUSED(C), wmGizmo static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoGroup *gzgroup) { - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; ARegion *region = CTX_wm_region(C); SpaceNode *snode = CTX_wm_space_node(C); @@ -591,11 +580,11 @@ static void WIDGETGROUP_node_corner_pin_draw_prepare(const bContext *C, wmGizmoG static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup *gzgroup) { Main *bmain = CTX_data_main(C); - struct NodeCornerPinWidgetGroup *cpin_group = gzgroup->customdata; + NodeCornerPinWidgetGroup *cpin_group = (NodeCornerPinWidgetGroup *)gzgroup->customdata; void *lock; Image *ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_COMPOSITE, "Viewer Node"); - ImBuf *ibuf = BKE_image_acquire_ibuf(ima, NULL, &lock); + ImBuf *ibuf = BKE_image_acquire_ibuf(ima, nullptr, &lock); if (ibuf) { cpin_group->state.dims[0] = (ibuf->x > 0) ? ibuf->x : 64.0f; @@ -606,7 +595,7 @@ static void WIDGETGROUP_node_corner_pin_refresh(const bContext *C, wmGizmoGroup /* need to set property here for undo. TODO: would prefer to do this in _init. */ int i = 0; - for (bNodeSocket *sock = node->inputs.first; sock && i < 4; sock = sock->next) { + for (bNodeSocket *sock = (bNodeSocket *)node->inputs.first; sock && i < 4; sock = sock->next) { if (sock->type == SOCK_VECTOR) { wmGizmo *gz = cpin_group->gizmos[i++]; diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index d7541d8f512..d9fbbc81a8f 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -58,7 +58,7 @@ #include "NOD_common.h" #include "NOD_socket.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Local Utilities diff --git a/source/blender/editors/space_node/node_intern.h b/source/blender/editors/space_node/node_intern.h deleted file mode 100644 index 383fe5afdf9..00000000000 --- a/source/blender/editors/space_node/node_intern.h +++ /dev/null @@ -1,355 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2008 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup spnode - */ - -#pragma once - -#include "BKE_node.h" -#include "UI_interface.h" -#include "UI_view2d.h" -#include <stddef.h> /* for size_t */ - -/* internal exports only */ - -struct ARegion; -struct ARegionType; -struct Main; -struct NodeInsertOfsData; -struct View2D; -struct bContext; -struct bNode; -struct bNodeLink; -struct bNodeSocket; -struct wmGizmoGroupType; -struct wmKeyConfig; -struct wmWindow; - -#ifdef __cplusplus -extern "C" { -#endif - -/* temp data to pass on to modal */ -typedef struct bNodeLinkDrag { - struct bNodeLinkDrag *next, *prev; - - /* List of links dragged by the operator. - * NOTE: This is a list of LinkData structs on top of the actual bNodeLinks. - * This way the links can be added to the node tree while being stored in this list. - */ - ListBase links; - bool from_multi_input_socket; - int in_out; - - /** Temporarily stores the last picked link from multi-input socket operator. */ - struct bNodeLink *last_picked_multi_input_socket_link; - - /** Temporarily stores the last hovered socket for multi-input socket operator. - * Store it to recalculate sorting after it is no longer hovered. */ - struct bNode *last_node_hovered_while_dragging_a_link; - - /* Data for edge panning */ - View2DEdgePanData pan_data; -} bNodeLinkDrag; - -typedef struct SpaceNode_Runtime { - float aspect; - - /** Mouse position for drawing socket-less links and adding nodes. */ - float cursor[2]; - - /** For auto compositing. */ - bool recalc; - - /** Temporary data for modal linking operator. */ - struct ListBase linkdrag; - - /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ - /** Temporary data for node insert offset (in UI called Auto-offset). */ - struct NodeInsertOfsData *iofsd; -} SpaceNode_Runtime; - -/* space_node.c */ - -/* transform between View2Ds in the tree path */ -void space_node_group_offset(struct SpaceNode *snode, float *x, float *y); - -/* node_draw.cc */ -float node_socket_calculate_height(const bNodeSocket *socket); -void node_link_calculate_multi_input_position(const float socket_x, - const float socket_y, - const int index, - const int total_inputs, - float r[2]); - -int node_get_colorid(struct bNode *node); -int node_get_resize_cursor(int directions); -void node_draw_shadow(const struct SpaceNode *snode, - const struct bNode *node, - float radius, - float alpha); -void node_draw_default(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - struct bNode *node, - bNodeInstanceKey key); -void node_draw_sockets(const struct View2D *v2d, - const struct bContext *C, - struct bNodeTree *ntree, - struct bNode *node, - bool draw_outputs, - bool select_all); -void node_update_default(const struct bContext *C, struct bNodeTree *ntree, struct bNode *node); -int node_select_area_default(struct bNode *node, int x, int y); -int node_tweak_area_default(struct bNode *node, int x, int y); -void node_socket_color_get(const struct bContext *C, - struct bNodeTree *ntree, - struct PointerRNA *node_ptr, - struct bNodeSocket *sock, - float r_color[4]); -void node_update_nodetree(const struct bContext *C, struct bNodeTree *ntree); -void node_draw_nodetree(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - struct bNodeTree *ntree, - bNodeInstanceKey parent_key); -void node_draw_space(const bContext *C, ARegion *region); - -void node_set_cursor(struct wmWindow *win, struct SpaceNode *snode, float cursor[2]); -/* DPI scaled coords */ -void node_to_view(const struct bNode *node, float x, float y, float *rx, float *ry); -void node_to_updated_rect(const struct bNode *node, rctf *r_rect); -void node_from_view(const struct bNode *node, float x, float y, float *rx, float *ry); - -/* node_toolbar.c */ -void node_toolbar_register(struct ARegionType *art); - -/* node_ops.c */ -void node_operatortypes(void); -void node_keymap(struct wmKeyConfig *keyconf); - -/* node_select.c */ -void node_deselect_all(struct SpaceNode *snode); -void node_socket_select(struct bNode *node, struct bNodeSocket *sock); -void node_socket_deselect(struct bNode *node, struct bNodeSocket *sock, const bool deselect_node); -void node_deselect_all_input_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_deselect_all_output_sockets(struct SpaceNode *snode, const bool deselect_nodes); -void node_select_single(struct bContext *C, struct bNode *node); - -void NODE_OT_select(struct wmOperatorType *ot); -void NODE_OT_select_all(struct wmOperatorType *ot); -void NODE_OT_select_linked_to(struct wmOperatorType *ot); -void NODE_OT_select_linked_from(struct wmOperatorType *ot); -void NODE_OT_select_box(struct wmOperatorType *ot); -void NODE_OT_select_circle(struct wmOperatorType *ot); -void NODE_OT_select_lasso(struct wmOperatorType *ot); -void NODE_OT_select_grouped(struct wmOperatorType *ot); -void NODE_OT_select_same_type_step(struct wmOperatorType *ot); -void NODE_OT_find_node(struct wmOperatorType *ot); - -/* node_view.c */ -int space_node_view_flag(struct bContext *C, - struct SpaceNode *snode, - ARegion *region, - const int node_flag, - const int smooth_viewtx); - -void NODE_OT_view_all(struct wmOperatorType *ot); -void NODE_OT_view_selected(struct wmOperatorType *ot); -void NODE_OT_geometry_node_view_legacy(struct wmOperatorType *ot); - -void NODE_OT_backimage_move(struct wmOperatorType *ot); -void NODE_OT_backimage_zoom(struct wmOperatorType *ot); -void NODE_OT_backimage_fit(struct wmOperatorType *ot); -void NODE_OT_backimage_sample(struct wmOperatorType *ot); - -/* drawnode.c */ -void nodelink_batch_start(struct SpaceNode *snode); -void nodelink_batch_end(struct SpaceNode *snode); - -void node_draw_link(const struct bContext *C, - struct View2D *v2d, - struct SpaceNode *snode, - struct bNodeLink *link); -void node_draw_link_bezier(const struct bContext *C, - const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - int th_col1, - int th_col2, - int th_col3); -bool node_link_bezier_points(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float coord_array[][2], - const int resol); -bool node_link_bezier_handles(const struct View2D *v2d, - const struct SpaceNode *snode, - const struct bNodeLink *link, - float vec[4][2]); -void draw_nodespace_back_pix(const struct bContext *C, - struct ARegion *region, - struct SpaceNode *snode, - bNodeInstanceKey parent_key); - -/* node_add.c */ -bNode *node_add_node( - const struct bContext *C, const char *idname, int type, float locx, float locy); -void NODE_OT_add_reroute(struct wmOperatorType *ot); -void NODE_OT_add_group(struct wmOperatorType *ot); -void NODE_OT_add_object(struct wmOperatorType *ot); -void NODE_OT_add_collection(struct wmOperatorType *ot); -void NODE_OT_add_texture(struct wmOperatorType *ot); -void NODE_OT_add_file(struct wmOperatorType *ot); -void NODE_OT_add_mask(struct wmOperatorType *ot); -void NODE_OT_new_node_tree(struct wmOperatorType *ot); - -/* node_group.c */ -const char *node_group_idname(struct bContext *C); -void NODE_OT_group_make(struct wmOperatorType *ot); -void NODE_OT_group_insert(struct wmOperatorType *ot); -void NODE_OT_group_ungroup(struct wmOperatorType *ot); -void NODE_OT_group_separate(struct wmOperatorType *ot); -void NODE_OT_group_edit(struct wmOperatorType *ot); - -/* node_relationships.c */ -void sort_multi_input_socket_links(struct SpaceNode *snode, - struct bNode *node, - struct bNodeLink *drag_link, - float cursor[2]); -bool node_connected_to_output(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); - -void NODE_OT_link(struct wmOperatorType *ot); -void NODE_OT_link_make(struct wmOperatorType *ot); -void NODE_OT_links_cut(struct wmOperatorType *ot); -void NODE_OT_links_detach(struct wmOperatorType *ot); -void NODE_OT_links_mute(struct wmOperatorType *ot); - -void NODE_OT_parent_set(struct wmOperatorType *ot); -void NODE_OT_join(struct wmOperatorType *ot); -void NODE_OT_attach(struct wmOperatorType *ot); -void NODE_OT_detach(struct wmOperatorType *ot); - -void NODE_OT_link_viewer(struct wmOperatorType *ot); - -void NODE_OT_insert_offset(struct wmOperatorType *ot); - -/* node_edit.c */ -void snode_notify(struct bContext *C, struct SpaceNode *snode); -void snode_dag_update(struct bContext *C, struct SpaceNode *snode); -void snode_set_context(const struct bContext *C); - -void snode_update(struct SpaceNode *snode, struct bNode *node); -bool composite_node_active(struct bContext *C); -bool composite_node_editable(struct bContext *C); - -bool node_has_hidden_sockets(struct bNode *node); -void node_set_hidden_sockets(struct SpaceNode *snode, bNode *node, int set); -int node_render_changed_exec(bContext *, struct wmOperator *); -int node_find_indicated_socket(struct SpaceNode *snode, - struct bNode **nodep, - struct bNodeSocket **sockp, - const float cursor[2], - int in_out); -float node_link_dim_factor(const struct View2D *v2d, const struct bNodeLink *link); -bool node_link_is_hidden_or_dimmed(const struct View2D *v2d, const struct bNodeLink *link); - -void NODE_OT_duplicate(struct wmOperatorType *ot); -void NODE_OT_delete(struct wmOperatorType *ot); -void NODE_OT_delete_reconnect(struct wmOperatorType *ot); -void NODE_OT_resize(struct wmOperatorType *ot); - -void NODE_OT_mute_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_toggle(struct wmOperatorType *ot); -void NODE_OT_hide_socket_toggle(struct wmOperatorType *ot); -void NODE_OT_preview_toggle(struct wmOperatorType *ot); -void NODE_OT_options_toggle(struct wmOperatorType *ot); -void NODE_OT_node_copy_color(struct wmOperatorType *ot); - -void NODE_OT_read_viewlayers(struct wmOperatorType *ot); -void NODE_OT_render_changed(struct wmOperatorType *ot); - -void NODE_OT_output_file_add_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_remove_active_socket(struct wmOperatorType *ot); -void NODE_OT_output_file_move_active_socket(struct wmOperatorType *ot); - -void NODE_OT_switch_view_update(struct wmOperatorType *ot); - -/* NOTE: clipboard_cut is a simple macro of copy + delete. */ -void NODE_OT_clipboard_copy(struct wmOperatorType *ot); -void NODE_OT_clipboard_paste(struct wmOperatorType *ot); - -void NODE_OT_tree_socket_add(struct wmOperatorType *ot); -void NODE_OT_tree_socket_remove(struct wmOperatorType *ot); -void NODE_OT_tree_socket_change_type(struct wmOperatorType *ot); -void NODE_OT_tree_socket_move(struct wmOperatorType *ot); - -void NODE_OT_shader_script_update(struct wmOperatorType *ot); - -void NODE_OT_viewer_border(struct wmOperatorType *ot); -void NODE_OT_clear_viewer_border(struct wmOperatorType *ot); - -/* node_widgets.c */ -void NODE_GGT_backdrop_transform(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_crop(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_sun_beams(struct wmGizmoGroupType *gzgt); -void NODE_GGT_backdrop_corner_pin(struct wmGizmoGroupType *gzgt); - -void NODE_OT_cryptomatte_layer_add(struct wmOperatorType *ot); -void NODE_OT_cryptomatte_layer_remove(struct wmOperatorType *ot); - -/* node_geometry_attribute_search.cc */ -void node_geometry_add_attribute_search_button(const struct bContext *C, - const struct bNodeTree *node_tree, - const struct bNode *node, - struct PointerRNA *socket_ptr, - struct uiLayout *layout); - -extern const char *node_context_dir[]; - -/* XXXXXX */ - -/* Nodes draw without dpi - the view zoom is flexible. */ -#define HIDDEN_RAD (0.75f * U.widget_unit) -#define BASIS_RAD (0.2f * U.widget_unit) -#define NODE_DYS (U.widget_unit / 2) -#define NODE_DY U.widget_unit -#define NODE_SOCKDY (0.1f * U.widget_unit) -#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) -#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) -#define NODE_MARGIN_X (1.2f * U.widget_unit) -#define NODE_SOCKSIZE (0.25f * U.widget_unit) -#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) -#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) -#define NODE_LINK_RESOL 12 - -#ifdef __cplusplus -} -#endif - -#ifdef __cplusplus -# include "BLI_vector.hh" -# include "UI_interface.hh" -namespace blender::ed::space_node { -Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); -} -#endif diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh new file mode 100644 index 00000000000..6dc57c1fb79 --- /dev/null +++ b/source/blender/editors/space_node/node_intern.hh @@ -0,0 +1,333 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2008 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup spnode + */ + +#pragma once + +#include "BKE_node.h" +#include "UI_interface.h" +#include "UI_view2d.h" + +#include "BLI_vector.hh" +#include "UI_interface.hh" + +#include <stddef.h> /* for size_t */ + +/* internal exports only */ + +struct ARegion; +struct ARegionType; +struct Main; +struct NodeInsertOfsData; +struct View2D; +struct bContext; +struct bNode; +struct bNodeLink; +struct bNodeSocket; +struct wmGizmoGroupType; +struct wmKeyConfig; +struct wmWindow; + +/* temp data to pass on to modal */ +struct bNodeLinkDrag { + /** Links dragged by the operator. */ + blender::Vector<bNodeLink *> links; + bool from_multi_input_socket; + int in_out; + + /** Temporarily stores the last picked link from multi-input socket operator. */ + struct bNodeLink *last_picked_multi_input_socket_link; + + /** Temporarily stores the last hovered socket for multi-input socket operator. + * Store it to recalculate sorting after it is no longer hovered. */ + struct bNode *last_node_hovered_while_dragging_a_link; + + /* Data for edge panning */ + View2DEdgePanData pan_data; +}; + +struct SpaceNode_Runtime { + float aspect; + + /** Mouse position for drawing socket-less links and adding nodes. */ + float cursor[2]; + + /** For auto compositing. */ + bool recalc; + + /** Temporary data for modal linking operator. */ + std::unique_ptr<bNodeLinkDrag> linkdrag; + + /* XXX hack for translate_attach op-macros to pass data from transform op to insert_offset op */ + /** Temporary data for node insert offset (in UI called Auto-offset). */ + struct NodeInsertOfsData *iofsd; +}; + +/* space_node.c */ + +/* transform between View2Ds in the tree path */ +void space_node_group_offset(SpaceNode *snode, float *x, float *y); + +/* node_draw.cc */ +float node_socket_calculate_height(const bNodeSocket *socket); +void node_link_calculate_multi_input_position(const float socket_x, + const float socket_y, + const int index, + const int total_inputs, + float r[2]); + +int node_get_colorid(bNode *node); +void node_draw_extra_info_panel(const SpaceNode *snode, const bNode *node); +int node_get_resize_cursor(int directions); +void node_draw_shadow(const SpaceNode *snode, const bNode *node, float radius, float alpha); +void node_draw_default(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNode *node, + bNodeInstanceKey key); +void node_draw_sockets(const View2D *v2d, + const bContext *C, + bNodeTree *ntree, + bNode *node, + bool draw_outputs, + bool select_all); +void node_update_default(const bContext *C, bNodeTree *ntree, bNode *node); +int node_select_area_default(bNode *node, int x, int y); +int node_tweak_area_default(bNode *node, int x, int y); +void node_socket_color_get(const bContext *C, + bNodeTree *ntree, + PointerRNA *node_ptr, + bNodeSocket *sock, + float r_color[4]); +void node_update_nodetree(const bContext *C, bNodeTree *ntree); +void node_draw_nodetree(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeTree *ntree, + bNodeInstanceKey parent_key); +void node_draw_space(const bContext *C, ARegion *region); + +void node_set_cursor(wmWindow *win, SpaceNode *snode, float cursor[2]); +/* DPI scaled coords */ +void node_to_view(const bNode *node, float x, float y, float *rx, float *ry); +void node_to_updated_rect(const bNode *node, rctf *r_rect); +void node_from_view(const bNode *node, float x, float y, float *rx, float *ry); + +/* node_toolbar.c */ +void node_toolbar_register(ARegionType *art); + +/* node_ops.c */ +void node_operatortypes(void); +void node_keymap(wmKeyConfig *keyconf); + +/* node_select.c */ +void node_deselect_all(SpaceNode *snode); +void node_socket_select(bNode *node, bNodeSocket *sock); +void node_socket_deselect(bNode *node, bNodeSocket *sock, const bool deselect_node); +void node_deselect_all_input_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_deselect_all_output_sockets(SpaceNode *snode, const bool deselect_nodes); +void node_select_single(bContext *C, bNode *node); + +void NODE_OT_select(wmOperatorType *ot); +void NODE_OT_select_all(wmOperatorType *ot); +void NODE_OT_select_linked_to(wmOperatorType *ot); +void NODE_OT_select_linked_from(wmOperatorType *ot); +void NODE_OT_select_box(wmOperatorType *ot); +void NODE_OT_select_circle(wmOperatorType *ot); +void NODE_OT_select_lasso(wmOperatorType *ot); +void NODE_OT_select_grouped(wmOperatorType *ot); +void NODE_OT_select_same_type_step(wmOperatorType *ot); +void NODE_OT_find_node(wmOperatorType *ot); + +/* node_view.c */ +int space_node_view_flag( + bContext *C, SpaceNode *snode, ARegion *region, const int node_flag, const int smooth_viewtx); + +void NODE_OT_view_all(wmOperatorType *ot); +void NODE_OT_view_selected(wmOperatorType *ot); +void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot); + +void NODE_OT_backimage_move(wmOperatorType *ot); +void NODE_OT_backimage_zoom(wmOperatorType *ot); +void NODE_OT_backimage_fit(wmOperatorType *ot); +void NODE_OT_backimage_sample(wmOperatorType *ot); + +/* drawnode.c */ +void nodelink_batch_start(SpaceNode *snode); +void nodelink_batch_end(SpaceNode *snode); + +void node_draw_link(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link); +void node_draw_link_bezier(const bContext *C, + const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + int th_col1, + int th_col2, + int th_col3); +bool node_link_bezier_points(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float coord_array[][2], + const int resol); +bool node_link_bezier_handles(const View2D *v2d, + const SpaceNode *snode, + const bNodeLink *link, + float vec[4][2]); +void draw_nodespace_back_pix(const bContext *C, + ARegion *region, + SpaceNode *snode, + bNodeInstanceKey parent_key); + +/* node_add.c */ +bNode *node_add_node(const bContext *C, const char *idname, int type, float locx, float locy); +void NODE_OT_add_reroute(wmOperatorType *ot); +void NODE_OT_add_group(wmOperatorType *ot); +void NODE_OT_add_object(wmOperatorType *ot); +void NODE_OT_add_collection(wmOperatorType *ot); +void NODE_OT_add_texture(wmOperatorType *ot); +void NODE_OT_add_file(wmOperatorType *ot); +void NODE_OT_add_mask(wmOperatorType *ot); +void NODE_OT_new_node_tree(wmOperatorType *ot); + +/* node_group.c */ +const char *node_group_idname(bContext *C); +void NODE_OT_group_make(wmOperatorType *ot); +void NODE_OT_group_insert(wmOperatorType *ot); +void NODE_OT_group_ungroup(wmOperatorType *ot); +void NODE_OT_group_separate(wmOperatorType *ot); +void NODE_OT_group_edit(wmOperatorType *ot); + +/* node_relationships.c */ +void sort_multi_input_socket_links(SpaceNode *snode, + bNode *node, + bNodeLink *drag_link, + float cursor[2]); +bool node_connected_to_output(Main *bmain, bNodeTree *ntree, bNode *node); + +void NODE_OT_link(wmOperatorType *ot); +void NODE_OT_link_make(wmOperatorType *ot); +void NODE_OT_links_cut(wmOperatorType *ot); +void NODE_OT_links_detach(wmOperatorType *ot); +void NODE_OT_links_mute(wmOperatorType *ot); + +void NODE_OT_parent_set(wmOperatorType *ot); +void NODE_OT_join(wmOperatorType *ot); +void NODE_OT_attach(wmOperatorType *ot); +void NODE_OT_detach(wmOperatorType *ot); + +void NODE_OT_link_viewer(wmOperatorType *ot); + +void NODE_OT_insert_offset(wmOperatorType *ot); + +/* node_edit.c */ +void snode_notify(bContext *C, SpaceNode *snode); +void snode_dag_update(bContext *C, SpaceNode *snode); +void snode_set_context(const bContext *C); + +void snode_update(SpaceNode *snode, bNode *node); +bool composite_node_active(bContext *C); +bool composite_node_editable(bContext *C); + +bool node_has_hidden_sockets(bNode *node); +void node_set_hidden_sockets(SpaceNode *snode, bNode *node, int set); +int node_render_changed_exec(bContext *, wmOperator *); +bool node_find_indicated_socket( + SpaceNode *snode, bNode **nodep, bNodeSocket **sockp, const float cursor[2], int in_out); +float node_link_dim_factor(const View2D *v2d, const bNodeLink *link); +bool node_link_is_hidden_or_dimmed(const View2D *v2d, const bNodeLink *link); + +void NODE_OT_duplicate(wmOperatorType *ot); +void NODE_OT_delete(wmOperatorType *ot); +void NODE_OT_delete_reconnect(wmOperatorType *ot); +void NODE_OT_resize(wmOperatorType *ot); + +void NODE_OT_mute_toggle(wmOperatorType *ot); +void NODE_OT_hide_toggle(wmOperatorType *ot); +void NODE_OT_hide_socket_toggle(wmOperatorType *ot); +void NODE_OT_preview_toggle(wmOperatorType *ot); +void NODE_OT_options_toggle(wmOperatorType *ot); +void NODE_OT_node_copy_color(wmOperatorType *ot); + +void NODE_OT_read_viewlayers(wmOperatorType *ot); +void NODE_OT_render_changed(wmOperatorType *ot); + +void NODE_OT_output_file_add_socket(wmOperatorType *ot); +void NODE_OT_output_file_remove_active_socket(wmOperatorType *ot); +void NODE_OT_output_file_move_active_socket(wmOperatorType *ot); + +void NODE_OT_switch_view_update(wmOperatorType *ot); + +/* NOTE: clipboard_cut is a simple macro of copy + delete. */ +void NODE_OT_clipboard_copy(wmOperatorType *ot); +void NODE_OT_clipboard_paste(wmOperatorType *ot); + +void NODE_OT_tree_socket_add(wmOperatorType *ot); +void NODE_OT_tree_socket_remove(wmOperatorType *ot); +void NODE_OT_tree_socket_change_type(wmOperatorType *ot); +void NODE_OT_tree_socket_move(wmOperatorType *ot); + +void NODE_OT_shader_script_update(wmOperatorType *ot); + +void NODE_OT_viewer_border(wmOperatorType *ot); +void NODE_OT_clear_viewer_border(wmOperatorType *ot); + +/* node_widgets.c */ +void NODE_GGT_backdrop_transform(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_crop(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_sun_beams(wmGizmoGroupType *gzgt); +void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt); + +void NODE_OT_cryptomatte_layer_add(wmOperatorType *ot); +void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot); + +/* node_geometry_attribute_search.cc */ +void node_geometry_add_attribute_search_button(const bContext *C, + const bNodeTree *node_tree, + const bNode *node, + PointerRNA *socket_ptr, + uiLayout *layout); + +extern const char *node_context_dir[]; + +/* XXXXXX */ + +/* Nodes draw without dpi - the view zoom is flexible. */ +#define HIDDEN_RAD (0.75f * U.widget_unit) +#define BASIS_RAD (0.2f * U.widget_unit) +#define NODE_DYS (U.widget_unit / 2) +#define NODE_DY U.widget_unit +#define NODE_SOCKDY (0.1f * U.widget_unit) +#define NODE_WIDTH(node) (node->width * UI_DPI_FAC) +#define NODE_HEIGHT(node) (node->height * UI_DPI_FAC) +#define NODE_MARGIN_X (1.2f * U.widget_unit) +#define NODE_SOCKSIZE (0.25f * U.widget_unit) +#define NODE_MULTI_INPUT_LINK_GAP (0.25f * U.widget_unit) +#define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) +#define NODE_LINK_RESOL 12 + +namespace blender::ed::space_node { +Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); +} diff --git a/source/blender/editors/space_node/node_ops.c b/source/blender/editors/space_node/node_ops.cc index 0c54da65e9c..4c08f4d7b47 100644 --- a/source/blender/editors/space_node/node_ops.c +++ b/source/blender/editors/space_node/node_ops.cc @@ -33,9 +33,9 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ -void node_operatortypes(void) +void node_operatortypes() { WM_operatortype_append(NODE_OT_select); WM_operatortype_append(NODE_OT_select_all); diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index 55b547d3195..aee749edbc4 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -60,9 +60,10 @@ #include "NOD_node_declaration.hh" #include "NOD_node_tree_ref.hh" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using namespace blender::nodes::node_tree_ref_types; +using blender::Vector; /* -------------------------------------------------------------------- */ /** \name Relations Helpers @@ -207,11 +208,9 @@ static void clear_picking_highlight(ListBase *links) } } -static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) +static bNodeLink *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bNodeSocket *sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; if (sock->in_out == SOCK_OUT) { oplink->fromnode = node; oplink->fromsock = sock; @@ -226,7 +225,7 @@ static LinkData *create_drag_link(Main *bmain, SpaceNode *snode, bNode *node, bN oplink->flag |= NODE_LINK_TEST; } oplink->flag |= NODE_LINK_DRAGGED; - return linkdata; + return oplink; } static void pick_link(const bContext *C, @@ -240,10 +239,9 @@ static void pick_link(const bContext *C, RNA_boolean_set(op->ptr, "has_link_picked", true); Main *bmain = CTX_data_main(C); - LinkData *linkdata = create_drag_link( - bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); + bNodeLink *link = create_drag_link(bmain, snode, link_to_pick->fromnode, link_to_pick->fromsock); - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(link); nodeRemLink(snode->edittree, link_to_pick); BLI_assert(nldrag->last_node_hovered_while_dragging_a_link != nullptr); @@ -324,19 +322,6 @@ static void pick_input_link_by_link_intersect(const bContext *C, } } -static int sort_nodes_locx(const void *a, const void *b) -{ - const bNodeListItem *nli1 = (const bNodeListItem *)a; - const bNodeListItem *nli2 = (const bNodeListItem *)b; - const bNode *node1 = nli1->node; - const bNode *node2 = nli2->node; - - if (node1->locx > node2->locx) { - return 1; - } - return 0; -} - static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, const bool allow_used) { if (nodeSocketIsHidden(sock)) { @@ -527,30 +512,25 @@ static void snode_autoconnect(Main *bmain, const bool replace) { bNodeTree *ntree = snode->edittree; - ListBase *nodelist = (ListBase *)MEM_callocN(sizeof(ListBase), "items_list"); + Vector<bNode *> sorted_nodes; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & NODE_SELECT) { - bNodeListItem *nli = (bNodeListItem *)MEM_mallocN(sizeof(bNodeListItem), - "temporary node list item"); - nli->node = node; - BLI_addtail(nodelist, nli); + sorted_nodes.append(node); } } - /* sort nodes left to right */ - BLI_listbase_sort(nodelist, sort_nodes_locx); + /* Sort nodes left to right. */ + std::sort(sorted_nodes.begin(), sorted_nodes.end(), [](const bNode *a, const bNode *b) { + return a->locx < b->locx; + }); int numlinks = 0; - LISTBASE_FOREACH (bNodeListItem *, nli, nodelist) { + for (const int i : sorted_nodes.as_mutable_span().drop_back(1).index_range()) { bool has_selected_inputs = false; - if (nli->next == nullptr) { - break; - } - - bNode *node_fr = nli->node; - bNode *node_to = nli->next->node; + bNode *node_fr = sorted_nodes[i]; + bNode *node_to = sorted_nodes[i + 1]; /* corner case: input/output node aligned the wrong way around (T47729) */ if (BLI_listbase_is_empty(&node_to->inputs) || BLI_listbase_is_empty(&node_fr->outputs)) { SWAP(bNode *, node_fr, node_to); @@ -606,9 +586,6 @@ static void snode_autoconnect(Main *bmain, if (numlinks > 0) { ntreeUpdateTree(bmain, ntree); } - - BLI_freelistN(nodelist); - MEM_freeN(nodelist); } /** \} */ @@ -1013,9 +990,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) /* avoid updates while applying links */ ntree->is_updating = true; - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* See note below, but basically TEST flag means that the link * was connected to output (or to a node which affects the * output). @@ -1068,10 +1043,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links) UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); } - BLI_remlink(&snode->runtime->linkdrag, nldrag); - /* links->data pointers are either held by the tree or freed already */ - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); } static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) @@ -1083,9 +1055,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_IN)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if socket is on the same node as the fromsock */ if (tnode && link->fromnode == tnode) { continue; @@ -1115,8 +1085,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; + for (bNodeLink *link : nldrag->links) { if (nldrag->last_node_hovered_while_dragging_a_link) { sort_multi_input_socket_links( snode, nldrag->last_node_hovered_while_dragging_a_link, nullptr, cursor); @@ -1130,9 +1099,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) bNode *tnode; bNodeSocket *tsock = nullptr; if (node_find_indicated_socket(snode, &tnode, &tsock, cursor, SOCK_OUT)) { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { /* skip if this is already the target socket */ if (link->fromsock == tsock) { continue; @@ -1148,9 +1115,7 @@ static void node_link_find_socket(bContext *C, wmOperator *op, float cursor[2]) } } else { - LISTBASE_FOREACH (LinkData *, linkdata, &nldrag->links) { - bNodeLink *link = (bNodeLink *)linkdata->data; - + for (bNodeLink *link : nldrag->links) { link->fromnode = nullptr; link->fromsock = nullptr; } @@ -1202,16 +1167,16 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_RUNNING_MODAL; } -/* return 1 when socket clicked */ -static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor[2], bool detach) +static std::unique_ptr<bNodeLinkDrag> node_link_init(Main *bmain, + SpaceNode *snode, + float cursor[2], + bool detach) { - bNodeLinkDrag *nldrag = nullptr; - /* output indicated? */ bNode *node; bNodeSocket *sock; if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); const int num_links = nodeCountSocketLinks(snode->edittree, sock); int link_limit = nodeSocketLinkLimit(sock); @@ -1221,9 +1186,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* detach current links and store them in the operator data */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode->edittree->links) { if (link->fromsock == sock) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1240,7 +1203,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link); } } @@ -1249,14 +1212,14 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } + /* or an input? */ - else if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { - nldrag = (bNodeLinkDrag *)MEM_callocN(sizeof(bNodeLinkDrag), "drag link op customdata"); + if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { + std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); nldrag->last_node_hovered_while_dragging_a_link = node; const int num_links = nodeCountSocketLinks(snode->edittree, sock); @@ -1275,9 +1238,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor } if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { - LinkData *linkdata = (LinkData *)MEM_callocN(sizeof(LinkData), "drag link op link data"); bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); - linkdata->data = oplink; *oplink = *link_to_pick; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; @@ -1287,7 +1248,7 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor oplink->flag |= NODE_LINK_TEST; } - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(oplink); nodeRemLink(snode->edittree, link_to_pick); /* send changed event to original link->tonode */ @@ -1300,13 +1261,12 @@ static bNodeLinkDrag *node_link_init(Main *bmain, SpaceNode *snode, float cursor /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* create a new link */ - LinkData *linkdata = create_drag_link(bmain, snode, node, sock); - - BLI_addtail(&nldrag->links, linkdata); + nldrag->links.append(create_drag_link(bmain, snode, node, sock)); } + return nldrag; } - return nldrag; + return {}; } static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) @@ -1324,13 +1284,13 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_preview_kill_jobs(CTX_wm_manager(C), bmain); - bNodeLinkDrag *nldrag = node_link_init(bmain, snode, cursor, detach); + std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); if (nldrag) { UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); - op->customdata = nldrag; - BLI_addtail(&snode->runtime->linkdrag, nldrag); + snode->runtime->linkdrag = std::move(nldrag); + op->customdata = snode->runtime->linkdrag.get(); /* add modal handler */ WM_event_add_modal_handler(C, op); @@ -1345,12 +1305,10 @@ static void node_link_cancel(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; - BLI_remlink(&snode->runtime->linkdrag, nldrag); - UI_view2d_edge_pan_cancel(C, &nldrag->pan_data); - BLI_freelistN(&nldrag->links); - MEM_freeN(nldrag); + snode->runtime->linkdrag.reset(); + clear_picking_highlight(&snode->edittree->links); } @@ -2369,8 +2327,8 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, /* NODE_TEST will be used later, so disable for all nodes */ ntreeNodeFlagSet(ntree, NODE_TEST, false); - /* insert->totr isn't updated yet, - * so totr_insert is used to get the correct worldspace coords */ + /* `insert->totr` isn't updated yet, + * so `totr_insert` is used to get the correct world-space coords. */ rctf totr_insert; node_to_updated_rect(insert, &totr_insert); diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 29b8372d043..3c7b404547b 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -61,7 +61,7 @@ #include "MEM_guardedalloc.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /** * Function to detect if there is a visible view3d that uses workbench in texture mode. diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index f68d8589624..b2a7c1753fb 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -48,7 +48,7 @@ #include "UI_interface.h" #include "ED_node.h" /* own include */ -#include "node_intern.h" +#include "node_intern.hh" #include "ED_undo.h" diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_node/node_toolbar.cc index 2e7d6ab6cd5..c32dcbef91b 100644 --- a/source/blender/editors/space_node/node_toolbar.cc +++ b/source/blender/editors/space_node/node_toolbar.cc @@ -30,7 +30,7 @@ #include "WM_api.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************* node toolbar registration ************** */ diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index 762b4b36a39..36b84bec7eb 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -54,7 +54,7 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ using blender::StringRef; diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.cc index 888aeb08334..ac64503cfc9 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.cc @@ -52,21 +52,19 @@ #include "WM_api.h" #include "WM_types.h" -#include "node_intern.h" /* own include */ +#include "node_intern.hh" /* own include */ /* ******************** tree path ********************* */ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) { - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; + LISTBASE_FOREACH_MUTABLE (bNodeTreePath *, path, &snode->treepath) { MEM_freeN(path); } BLI_listbase_clear(&snode->treepath); if (ntree) { - path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); path->nodetree = ntree; path->parent_key = NODE_INSTANCE_KEY_BASE; @@ -94,13 +92,13 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) { - bNodeTreePath *path = MEM_callocN(sizeof(bNodeTreePath), "node tree path"); - bNodeTreePath *prev_path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last; path->nodetree = ntree; if (gnode) { if (prev_path) { @@ -129,12 +127,12 @@ void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) ED_node_set_active_viewer_key(snode); - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } void ED_node_tree_pop(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* don't remove root */ if (path == snode->treepath.first) { @@ -145,13 +143,13 @@ void ED_node_tree_pop(SpaceNode *snode) MEM_freeN(path); /* update current tree */ - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; ED_node_set_active_viewer_key(snode); /* listener updates the View2D center from edittree */ - WM_main_add_notifier(NC_SCENE | ND_NODES, NULL); + WM_main_add_notifier(NC_SCENE | ND_NODES, nullptr); } int ED_node_tree_depth(SpaceNode *snode) @@ -163,12 +161,12 @@ bNodeTree *ED_node_tree_get(SpaceNode *snode, int level) { bNodeTreePath *path; int i; - for (path = snode->treepath.last, i = 0; path; path = path->prev, i++) { + for (path = (bNodeTreePath *)snode->treepath.last, i = 0; path; path = path->prev, i++) { if (i == level) { return path->nodetree; } } - return NULL; + return nullptr; } int ED_node_tree_path_length(SpaceNode *snode) @@ -203,7 +201,7 @@ void ED_node_tree_path_get(SpaceNode *snode, char *value) void ED_node_set_active_viewer_key(SpaceNode *snode) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (snode->nodetree && path) { snode->nodetree->active_viewer_key = path->parent_key; } @@ -211,7 +209,7 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) void space_node_group_offset(SpaceNode *snode, float *x, float *y) { - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; if (path && path->prev) { float dcenter[2]; @@ -228,10 +226,7 @@ void space_node_group_offset(SpaceNode *snode, float *x, float *y) static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - ARegion *region; - SpaceNode *snode; - - snode = MEM_callocN(sizeof(SpaceNode), "initnode"); + SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode"); snode->spacetype = SPACE_NODE; snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA; @@ -249,21 +244,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s NODE_TREE_TYPES_END; /* header */ - region = MEM_callocN(sizeof(ARegion), "header for node"); + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* buttons/list view */ - region = MEM_callocN(sizeof(ARegion), "buttons for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; /* toolbar */ - region = MEM_callocN(sizeof(ARegion), "node tools"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_TOOLS; @@ -272,7 +267,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->flag = RGN_FLAG_HIDDEN; /* main region */ - region = MEM_callocN(sizeof(ARegion), "main region for node"); + region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -290,7 +285,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->v2d.max[0] = 32000.0f; region->v2d.max[1] = 32000.0f; - region->v2d.minzoom = 0.09f; + region->v2d.minzoom = 0.05f; region->v2d.maxzoom = 2.31f; region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); @@ -308,7 +303,10 @@ static void node_free(SpaceLink *sl) MEM_freeN(path); } - MEM_SAFE_FREE(snode->runtime); + if (snode->runtime) { + snode->runtime->linkdrag.reset(); + MEM_freeN(snode->runtime); + } } /* spacetype; init callback */ @@ -316,8 +314,8 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; - if (snode->runtime == NULL) { - snode->runtime = MEM_callocN(sizeof(SpaceNode_Runtime), __func__); + if (snode->runtime == nullptr) { + snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__); } } @@ -327,7 +325,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) wmNotifier *wmn = params->notifier; /* NOTE: #ED_area_tag_refresh will re-execute compositor. */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* shaderfrom is only used for new shading nodes, otherwise all shaders are from objects */ short shader_type = snode->shaderfrom; @@ -337,7 +335,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) switch (wmn->data) { case ND_NODES: { ARegion *region = BKE_area_find_region_type(area, RGN_TYPE_WINDOW); - bNodeTreePath *path = snode->treepath.last; + bNodeTreePath *path = (bNodeTreePath *)snode->treepath.last; /* shift view to node tree center */ if (region && path) { UI_view2d_center_set(®ion->v2d, path->view_center[0], path->view_center[1]); @@ -379,7 +377,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) ED_area_tag_refresh(area); } else if (wmn->action == NA_ADDED && snode->edittree) { - nodeSetActiveID(snode->edittree, ID_MA, wmn->reference); + nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference); } } break; @@ -404,7 +402,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) else if (ED_node_is_geometry(snode)) { /* Rather strict check: only redraw when the reference matches the current editor's ID. */ if (wmn->data == ND_MODIFIER) { - if (wmn->reference == snode->id || snode->id == NULL) { + if (wmn->reference == snode->id || snode->id == nullptr) { ED_area_tag_refresh(area); } } @@ -447,7 +445,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) /* note that nodeUpdateID is already called by BKE_image_signal() on all * scenes so really this is just to know if the images is used in the compo else * painting on images could become very slow when the compositor is open. */ - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -457,7 +455,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - if (nodeUpdateID(snode->nodetree, wmn->reference)) { + if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -485,7 +483,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) static void node_area_refresh(const struct bContext *C, ScrArea *area) { /* default now: refresh node is starting preview */ - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; snode_set_context(C); @@ -494,19 +492,19 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) if (GS(snode->id->name) == ID_MA) { Material *ma = (Material *)snode->id; if (ma->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_LA) { Light *la = (Light *)snode->id; if (la->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } else if (GS(snode->id->name) == ID_WO) { World *wo = (World *)snode->id; if (wo->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -516,7 +514,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) /* recalc is set on 3d view changes for auto compo */ if (snode->runtime->recalc) { snode->runtime->recalc = false; - node_render_changed_exec((struct bContext *)C, NULL); + node_render_changed_exec((struct bContext *)C, nullptr); } else { ED_node_composite_job(C, snode->nodetree, scene); @@ -526,7 +524,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) else if (snode->nodetree->type == NTREE_TEXTURE) { Tex *tex = (Tex *)snode->id; if (tex->use_nodes) { - ED_preview_shader_job(C, area, snode->id, NULL, NULL, 100, 100, PR_NODE_RENDER); + ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); } } } @@ -535,14 +533,11 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) static SpaceLink *node_duplicate(SpaceLink *sl) { SpaceNode *snode = (SpaceNode *)sl; - SpaceNode *snoden = MEM_dupallocN(snode); + SpaceNode *snoden = (SpaceNode *)MEM_dupallocN(snode); BLI_duplicatelist(&snoden->treepath, &snode->treepath); - if (snode->runtime != NULL) { - snoden->runtime = MEM_dupallocN(snode->runtime); - BLI_listbase_clear(&snoden->runtime->linkdrag); - } + snoden->runtime = nullptr; /* NOTE: no need to set node tree user counts, * the editor only keeps at least 1 (id_us_ensure_real), @@ -596,7 +591,7 @@ void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; /* convert mouse coordinates to v2d space */ UI_view2d_region_to_view(®ion->v2d, @@ -710,7 +705,7 @@ static void node_id_path_drop_copy(wmDrag *drag, wmDropBox *drop) } /* this region dropbox definition */ -static void node_dropboxes(void) +static void node_dropboxes() { ListBase *lb = WM_dropboxmap_find("Node Editor", SPACE_NODE, RGN_TYPE_WINDOW); @@ -719,37 +714,37 @@ static void node_dropboxes(void) node_object_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_collection", node_collection_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_texture", node_texture_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_group", node_group_drop_poll, node_group_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_file", node_ima_drop_poll, node_id_path_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); WM_dropbox_add(lb, "NODE_OT_add_mask", node_mask_drop_poll, node_id_drop_copy, WM_drag_free_imported_drag_ID, - NULL); + nullptr); } /* ************* end drop *********** */ @@ -843,7 +838,7 @@ static void node_region_listener(const wmRegionListenerParams *params) } const char *node_context_dir[] = { - "selected_nodes", "active_node", "light", "material", "world", NULL}; + "selected_nodes", "active_node", "light", "material", "world", nullptr}; static int /*eContextResult*/ node_context(const bContext *C, const char *member, bContextDataResult *result) @@ -855,10 +850,8 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_OK; } if (CTX_data_equals(member, "selected_nodes")) { - bNode *node; - if (snode->edittree) { - for (node = snode->edittree->nodes.last; node; node = node->prev) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &snode->edittree->nodes) { if (node->flag & NODE_SELECT) { CTX_data_list_add(result, &snode->edittree->id, &RNA_Node, node); } @@ -907,11 +900,11 @@ static int /*eContextResult*/ node_context(const bContext *C, return CTX_RESULT_MEMBER_NOT_FOUND; } -static void node_widgets(void) +static void node_widgets() { - /* create the widgetmap for the area here */ - wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure( - &(const struct wmGizmoMapType_Params){SPACE_NODE, RGN_TYPE_WINDOW}); + /* Create the widget-map for the area here. */ + wmGizmoMapType_Params params{SPACE_NODE, RGN_TYPE_WINDOW}; + wmGizmoMapType *gzmap_type = WM_gizmomaptype_ensure(¶ms); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_transform); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_crop); WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_sun_beams); @@ -928,15 +921,15 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I */ BLI_freelistN(&snode->treepath); - /* XXX Untested in case new_id != NULL... */ + /* XXX Untested in case new_id != nullptr... */ snode->id = new_id; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; + snode->from = nullptr; + snode->nodetree = nullptr; + snode->edittree = nullptr; } else if (GS(old_id->name) == ID_OB) { if (snode->from == old_id) { - if (new_id == NULL) { + if (new_id == nullptr) { snode->flag &= ~SNODE_PIN; } snode->from = new_id; @@ -952,7 +945,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I else if (GS(old_id->name) == ID_NT) { bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path->next) { + for (path = (bNodeTreePath *)snode->treepath.first; path; path = path->next) { if ((ID *)path->nodetree == old_id) { path->nodetree = (bNodeTree *)new_id; id_us_ensure_real(new_id); @@ -961,7 +954,7 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* first nodetree in path is same as snode->nodetree */ snode->nodetree = path->nodetree; } - if (path->nodetree == NULL) { + if (path->nodetree == nullptr) { break; } } @@ -977,24 +970,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I /* edittree is just the last in the path, * set this directly since the path may have been shortened above */ if (snode->treepath.last) { - path = snode->treepath.last; + path = (bNodeTreePath *)snode->treepath.last; snode->edittree = path->nodetree; } else { - snode->edittree = NULL; + snode->edittree = nullptr; } } } static int node_space_subtype_get(ScrArea *area) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; return rna_node_tree_idname_to_enum(snode->tree_idname); } static void node_space_subtype_set(ScrArea *area, int value) { - SpaceNode *snode = area->spacedata.first; + SpaceNode *snode = (SpaceNode *)area->spacedata.first; ED_node_set_tree_type(snode, rna_node_tree_type_from_enum(value)); } @@ -1011,7 +1004,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype node"); + SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node"); ARegionType *art; st->spaceid = SPACE_NODE; @@ -1034,7 +1027,7 @@ void ED_spacetype_node(void) st->space_subtype_set = node_space_subtype_set; /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; @@ -1048,7 +1041,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; @@ -1059,7 +1052,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ - art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -1070,7 +1063,7 @@ void ED_spacetype_node(void) BLI_addhead(&st->regiontypes, art); /* regions: toolbar */ - art = MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 738db28a2b6..e449e4a609b 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -763,7 +763,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { - BKE_copybuffer_tag_ID(tselem->id); + BKE_copybuffer_copy_tag_ID(tselem->id); num_ids++; } } @@ -781,7 +781,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); char str[FILE_MAX]; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); const int num_ids = outliner_id_copy_tag(space_outliner, &space_outliner->tree); if (num_ids == 0) { @@ -790,7 +790,7 @@ static int outliner_id_copy_exec(bContext *C, wmOperator *op) } BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected data-block(s)", num_ids); diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index 4b6c5e29d77..f6f8e45590f 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -28,6 +28,7 @@ #include "DNA_gpencil_types.h" #include "DNA_mask_types.h" #include "DNA_scene_types.h" +#include "DNA_sound_types.h" #include "MEM_guardedalloc.h" @@ -400,7 +401,7 @@ static bool image_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } - return 0; + return WM_drag_is_ID_type(drag, ID_IM); } static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -416,7 +417,8 @@ static bool movie_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_MC); } static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) @@ -432,35 +434,61 @@ static bool sound_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) } } } - return 0; + + return WM_drag_is_ID_type(drag, ID_SO); } static void sequencer_drop_copy(wmDrag *drag, wmDropBox *drop) { - /* Copy drag path to properties. */ - if (RNA_struct_find_property(drop->ptr, "filepath")) { - RNA_string_set(drop->ptr, "filepath", drag->path); + ID *id = WM_drag_get_local_ID_or_import_from_asset(drag, 0); + /* ID dropped. */ + if (id != NULL) { + const ID_Type id_type = GS(id->name); + if (id_type == ID_IM) { + Image *ima = (Image *)id; + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; + BLI_split_dirfile(ima->filepath, dir, file, sizeof(dir), sizeof(file)); + RNA_string_set(drop->ptr, "directory", dir); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } + else if (id_type == ID_MC) { + MovieClip *clip = (MovieClip *)id; + RNA_string_set(drop->ptr, "filepath", clip->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } + else if (id_type == ID_SO) { + bSound *sound = (bSound *)id; + RNA_string_set(drop->ptr, "filepath", sound->filepath); + RNA_struct_property_unset(drop->ptr, "name"); + } } + /* Path dropped. */ + else if (drag->path[0]) { + if (RNA_struct_find_property(drop->ptr, "filepath")) { + RNA_string_set(drop->ptr, "filepath", drag->path); + } + if (RNA_struct_find_property(drop->ptr, "directory")) { + PointerRNA itemptr; + char dir[FILE_MAX], file[FILE_MAX]; - if (RNA_struct_find_property(drop->ptr, "directory")) { - PointerRNA itemptr; - char dir[FILE_MAX], file[FILE_MAX]; - - BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); + BLI_split_dirfile(drag->path, dir, file, sizeof(dir), sizeof(file)); - RNA_string_set(drop->ptr, "directory", dir); + RNA_string_set(drop->ptr, "directory", dir); - RNA_collection_clear(drop->ptr, "files"); - RNA_collection_add(drop->ptr, "files", &itemptr); - RNA_string_set(&itemptr, "name", file); + RNA_collection_clear(drop->ptr, "files"); + RNA_collection_add(drop->ptr, "files", &itemptr); + RNA_string_set(&itemptr, "name", file); + } } } /* This region dropbox definition. */ -static void sequencer_dropboxes(void) -{ - ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); +static void sequencer_dropboxes_add_to_lb(ListBase *lb) +{ WM_dropbox_add( lb, "SEQUENCER_OT_image_strip_add", image_drop_poll, sequencer_drop_copy, NULL, NULL); WM_dropbox_add( @@ -469,6 +497,14 @@ static void sequencer_dropboxes(void) lb, "SEQUENCER_OT_sound_strip_add", sound_drop_poll, sequencer_drop_copy, NULL, NULL); } +static void sequencer_dropboxes(void) +{ + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_WINDOW); + sequencer_dropboxes_add_to_lb(lb); + lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + sequencer_dropboxes_add_to_lb(lb); +} + /* ************* end drop *********** */ /* DO NOT make this static, this hides the symbol and breaks API generation script. */ @@ -757,6 +793,9 @@ static void sequencer_preview_region_init(wmWindowManager *wm, ARegion *region) /* Own keymap. */ keymap = WM_keymap_ensure(wm->defaultconf, "SequencerPreview", SPACE_SEQ, 0); WM_event_add_keymap_handler_v2d_mask(®ion->handlers, keymap); + + ListBase *lb = WM_dropboxmap_find("Sequencer", SPACE_SEQ, RGN_TYPE_PREVIEW); + WM_event_add_dropbox_handler(®ion->handlers, lb); } static void sequencer_preview_region_layout(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 91fe1bc01b7..27446fe1a94 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -41,10 +41,10 @@ set(SRC spreadsheet_data_source.cc spreadsheet_data_source_geometry.cc spreadsheet_dataset_draw.cc - spreadsheet_dataset_layout.cc spreadsheet_draw.cc spreadsheet_layout.cc spreadsheet_ops.cc + spreadsheet_panels.cc spreadsheet_row_filter.cc spreadsheet_row_filter_ui.cc @@ -56,7 +56,6 @@ set(SRC spreadsheet_data_source.hh spreadsheet_data_source_geometry.hh spreadsheet_dataset_draw.hh - spreadsheet_dataset_layout.hh spreadsheet_draw.hh spreadsheet_intern.hh spreadsheet_layout.hh @@ -67,4 +66,14 @@ set(SRC set(LIB ) +if(WITH_OPENVDB) + list(APPEND INC_SYS + ${OPENVDB_INCLUDE_DIRS} + ) + list(APPEND LIB + ${OPENVDB_LIBRARIES} + ) + add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) +endif() + blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index d54af7ffe2c..b37706e02e8 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -41,6 +41,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "BLT_translation.h" + #include "BLF_api.h" #include "spreadsheet_intern.hh" @@ -319,6 +321,8 @@ static float get_default_column_width(const ColumnValues &values) return 4.0f * float_width; case SPREADSHEET_VALUE_TYPE_INSTANCES: return 8.0f; + case SPREADSHEET_VALUE_TYPE_STRING: + return 5.0f; } return float_width; } @@ -589,35 +593,10 @@ static void spreadsheet_dataset_region_listener(const wmRegionListenerParams *pa spreadsheet_header_region_listener(params); } -static void spreadsheet_dataset_region_init(wmWindowManager *wm, ARegion *region) -{ - region->v2d.scroll |= V2D_SCROLL_RIGHT; - region->v2d.scroll &= ~(V2D_SCROLL_LEFT | V2D_SCROLL_TOP | V2D_SCROLL_BOTTOM); - region->v2d.scroll |= V2D_SCROLL_HORIZONTAL_HIDE; - region->v2d.scroll |= V2D_SCROLL_VERTICAL_HIDE; - - UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); - - wmKeyMap *keymap = WM_keymap_ensure( - wm->defaultconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0); - WM_event_add_keymap_handler(®ion->handlers, keymap); -} - static void spreadsheet_dataset_region_draw(const bContext *C, ARegion *region) { spreadsheet_update_context_path(C); - - View2D *v2d = ®ion->v2d; - UI_view2d_view_ortho(v2d); - UI_ThemeClearColor(TH_BACK); - - draw_dataset_in_region(C, region); - - /* reset view matrix */ - UI_view2d_view_restore(C); - - /* scrollers */ - UI_view2d_scrollers_draw(v2d, nullptr); + ED_region_panels(C, region); } static void spreadsheet_sidebar_init(wmWindowManager *wm, ARegion *region) @@ -708,11 +687,12 @@ void ED_spacetype_spreadsheet(void) /* regions: channels */ art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region"); art->regionid = RGN_TYPE_CHANNELS; - art->prefsizex = 200 + V2D_SCROLL_WIDTH; + art->prefsizex = 150 + V2D_SCROLL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; - art->init = spreadsheet_dataset_region_init; + art->init = ED_region_panels_init; art->draw = spreadsheet_dataset_region_draw; art->listener = spreadsheet_dataset_region_listener; + blender::ed::spreadsheet::spreadsheet_data_set_region_panels_register(*art); BLI_addhead(&st->regiontypes, art); BKE_spacetype_register(st); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh index 97170693cb3..c11b4a2b23d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh @@ -58,6 +58,7 @@ class CellValue { std::optional<ObjectCellValue> value_object; std::optional<CollectionCellValue> value_collection; std::optional<GeometrySetCellValue> value_geometry_set; + std::optional<std::string> value_string; }; } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index c1d345d1861..8cdb462718d 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -20,6 +20,7 @@ #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" #include "BKE_modifier.h" +#include "BKE_volume.h" #include "DNA_ID.h" #include "DNA_mesh_types.h" @@ -33,6 +34,11 @@ #include "NOD_geometry_nodes_eval_log.hh" +#include "BLT_translation.h" + +#include "RNA_access.h" +#include "RNA_enum_types.h" + #include "FN_field_cpp_type.hh" #include "bmesh.h" @@ -72,7 +78,7 @@ static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type( void ExtraColumns::foreach_default_column_ids( FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const { - for (const auto &item : columns_.items()) { + for (const auto item : columns_.items()) { SpreadsheetColumnID column_id; column_id.name = (char *)item.key.c_str(); fn(column_id, true); @@ -112,6 +118,9 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values( r_cell_value.value_color = *( const ColorGeometry4f *)value; break; + case SPREADSHEET_VALUE_TYPE_STRING: + r_cell_value.value_string = *(const std::string *)value; + break; case SPREADSHEET_VALUE_TYPE_INSTANCES: break; } @@ -159,12 +168,12 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( if (!attribute) { return {}; } - const fn::GVArray *varray = scope_.add(std::move(attribute.varray)); + fn::GVArray varray = std::move(attribute.varray); if (attribute.domain != domain_) { return {}; } - int domain_size = varray->size(); - const CustomDataType type = bke::cpp_type_to_custom_data_type(varray->type()); + int domain_size = varray.size(); + const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type()); switch (type) { case CD_PROP_FLOAT: return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT, @@ -172,7 +181,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float = value; }); case CD_PROP_INT32: @@ -182,7 +191,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { int value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_int = value; }, STREQ(column_id.name, "id") ? 5.5f : 0.0f); @@ -192,7 +201,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { bool value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_bool = value; }); case CD_PROP_FLOAT2: { @@ -201,7 +210,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float2 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float2 = value; }); } @@ -211,7 +220,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { float3 value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_float3 = value; }); } @@ -221,7 +230,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( domain_size, [varray](int index, CellValue &r_cell_value) { ColorGeometry4f value; - varray->get(index, &value); + varray.get(index, &value); r_cell_value.value_color = value; }); } @@ -487,9 +496,93 @@ int InstancesDataSource::tot_rows() const return component_->instances_amount(); } +void VolumeDataSource::foreach_default_column_ids( + FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const +{ + if (component_->is_empty()) { + return; + } + + for (const char *name : {"Grid Name", "Data Type", "Class"}) { + SpreadsheetColumnID column_id{(char *)name}; + fn(column_id, false); + } +} + +std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values( + const SpreadsheetColumnID &column_id) const +{ + const Volume *volume = component_->get_for_read(); + if (volume == nullptr) { + return {}; + } + +#ifdef WITH_OPENVDB + const int size = this->tot_rows(); + if (STREQ(column_id.name, "Grid Name")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Grid Name"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + r_cell_value.value_string = BKE_volume_grid_name(volume_grid); + }, + 6.0f); + } + if (STREQ(column_id.name, "Data Type")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Type"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + const VolumeGridType type = BKE_volume_grid_type(volume_grid); + const char *name = nullptr; + RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name); + r_cell_value.value_string = IFACE_(name); + }, + 5.0f); + } + if (STREQ(column_id.name, "Class")) { + return column_values_from_function( + SPREADSHEET_VALUE_TYPE_STRING, + IFACE_("Class"), + size, + [volume](int index, CellValue &r_cell_value) { + const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); + openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); + openvdb::GridClass grid_class = grid->getGridClass(); + if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) { + r_cell_value.value_string = IFACE_("Fog Volume"); + } + else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { + r_cell_value.value_string = IFACE_("Level Set"); + } + else { + r_cell_value.value_string = IFACE_("Unkown"); + } + }, + 5.0f); + } +#else + UNUSED_VARS(column_id); +#endif + + return {}; +} + +int VolumeDataSource::tot_rows() const +{ + const Volume *volume = component_->get_for_read(); + if (volume == nullptr) { + return 0; + } + return BKE_volume_num_grids(volume); +} + GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type) + Object *object_eval) { GeometrySet geometry_set; if (sspreadsheet->object_eval_state == SPREADSHEET_OBJECT_EVAL_STATE_ORIGINAL) { @@ -521,7 +614,7 @@ GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspread } } else { - if (used_component_type == GEO_COMPONENT_TYPE_MESH && object_eval->mode == OB_MODE_EDIT) { + if (object_eval->mode == OB_MODE_EDIT && object_eval->type == OB_MESH) { Mesh *mesh = BKE_modifier_get_evaluated_mesh_from_evaluated_object(object_eval, false); if (mesh == nullptr) { return geometry_set; @@ -644,7 +737,7 @@ static void add_fields_as_extra_columns(SpaceSpreadsheet *sspreadsheet, const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const int domain_size = component.attribute_domain_size(domain); - for (const auto &item : fields_to_show.items()) { + for (const auto item : fields_to_show.items()) { StringRef name = item.key; const GField &field = item.value; @@ -668,8 +761,7 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); const AttributeDomain domain = (AttributeDomain)sspreadsheet->attribute_domain; const GeometryComponentType component_type = get_display_component_type(C, object_eval); - GeometrySet geometry_set = spreadsheet_get_display_geometry_set( - sspreadsheet, object_eval, component_type); + GeometrySet geometry_set = spreadsheet_get_display_geometry_set(sspreadsheet, object_eval); if (!geometry_set.has(component_type)) { return {}; @@ -682,6 +774,9 @@ std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object if (component_type == GEO_COMPONENT_TYPE_INSTANCES) { return std::make_unique<InstancesDataSource>(geometry_set, std::move(extra_columns)); } + if (component_type == GEO_COMPONENT_TYPE_VOLUME) { + return std::make_unique<VolumeDataSource>(geometry_set); + } return std::make_unique<GeometryDataSource>( object_eval, geometry_set, component_type, domain, std::move(extra_columns)); } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 6c88a94f585..a4114dd1f6a 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -116,6 +116,26 @@ class InstancesDataSource : public DataSource { int tot_rows() const override; }; +class VolumeDataSource : public DataSource { + const GeometrySet geometry_set_; + const VolumeComponent *component_; + + public: + VolumeDataSource(GeometrySet geometry_set) + : geometry_set_(std::move(geometry_set)), + component_(geometry_set_.get_component_for_read<VolumeComponent>()) + { + } + + void foreach_default_column_ids( + FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override; + + std::unique_ptr<ColumnValues> get_column_values( + const SpreadsheetColumnID &column_id) const override; + + int tot_rows() const override; +}; + std::unique_ptr<DataSource> data_source_from_geometry(const bContext *C, Object *object_eval); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc index 4cf6d14cbda..2a81b56d129 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.cc @@ -14,275 +14,226 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include <array> - #include "DNA_space_types.h" #include "DNA_windowmanager_types.h" #include "BKE_context.h" - -#include "BLF_api.h" - -#include "BLI_rect.h" +#include "BKE_volume.h" #include "RNA_access.h" #include "UI_interface.h" -#include "UI_view2d.h" +#include "UI_interface.hh" +#include "UI_tree_view.hh" #include "WM_types.h" +#include "BLT_translation.h" + #include "spreadsheet_dataset_draw.hh" #include "spreadsheet_draw.hh" #include "spreadsheet_intern.hh" -static int is_component_row_selected(struct uiBut *but, const void *arg) -{ - SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)arg; +namespace blender::ed::spreadsheet { - GeometryComponentType component = (GeometryComponentType)UI_but_datasetrow_component_get(but); - AttributeDomain domain = (AttributeDomain)UI_but_datasetrow_domain_get(but); +class GeometryDataSetTreeView; - const bool is_component_selected = (GeometryComponentType) - sspreadsheet->geometry_component_type == component; - const bool is_domain_selected = (AttributeDomain)sspreadsheet->attribute_domain == domain; - bool is_selected = is_component_selected && is_domain_selected; +class GeometryDataSetTreeViewItem : public ui::AbstractTreeViewItem { + GeometryComponentType component_type_; + std::optional<AttributeDomain> domain_; + BIFIconID icon_; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { - is_selected = is_component_selected; - } + public: + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon); + GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon); - return is_selected; -} + void on_activate() override; -namespace blender::ed::spreadsheet { + void build_row(uiLayout &row) override; -/* -------------------------------------------------------------------- */ -/* Draw Context */ + protected: + std::optional<bool> should_be_active() const override; + bool supports_collapsing() const override; -class DatasetDrawContext { - std::array<int, 2> mval_; + private: + GeometryDataSetTreeView &get_tree() const; + std::optional<int> count() const; +}; - public: - const SpaceSpreadsheet *sspreadsheet; - Object *object_eval; - /* Current geometry set, changes per component. */ - GeometrySet current_geometry_set; +class GeometryDataSetTreeView : public ui::AbstractTreeView { + GeometrySet geometry_set_; + const bContext &C_; + SpaceSpreadsheet &sspreadsheet_; + bScreen &screen_; - DatasetDrawContext(const bContext *C); + friend class GeometryDataSetTreeViewItem; - GeometrySet geometry_set_from_component(GeometryComponentType component); - const std::array<int, 2> &cursor_mval() const; -}; - -DatasetDrawContext::DatasetDrawContext(const bContext *C) - : sspreadsheet(CTX_wm_space_spreadsheet(C)), - object_eval(spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C))) -{ - const wmWindow *win = CTX_wm_window(C); - const ARegion *region = CTX_wm_region(C); - mval_ = {win->eventstate->xy[0] - region->winrct.xmin, - win->eventstate->xy[1] - region->winrct.ymin}; -} + public: + GeometryDataSetTreeView(GeometrySet geometry_set, const bContext &C) + : geometry_set_(std::move(geometry_set)), + C_(C), + sspreadsheet_(*CTX_wm_space_spreadsheet(&C)), + screen_(*CTX_wm_screen(&C)) + { + } -GeometrySet DatasetDrawContext::geometry_set_from_component(GeometryComponentType component) -{ - return spreadsheet_get_display_geometry_set(sspreadsheet, object_eval, component); -} + void build_tree() override + { + GeometryDataSetTreeViewItem &mesh = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, IFACE_("Mesh"), ICON_MESH_DATA); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_POINT, IFACE_("Vertex"), ICON_VERTEXSEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_EDGE, IFACE_("Edge"), ICON_EDGESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_FACE, IFACE_("Face"), ICON_FACESEL); + mesh.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_MESH, ATTR_DOMAIN_CORNER, IFACE_("Face Corner"), ICON_NODE_CORNER); + + GeometryDataSetTreeViewItem &curve = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, IFACE_("Curve"), ICON_CURVE_DATA); + curve.add_tree_item<GeometryDataSetTreeViewItem>(GEO_COMPONENT_TYPE_CURVE, + ATTR_DOMAIN_POINT, + IFACE_("Control Point"), + ICON_CURVE_BEZCIRCLE); + curve.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_CURVE, ATTR_DOMAIN_CURVE, IFACE_("Spline"), ICON_CURVE_PATH); + + GeometryDataSetTreeViewItem &pointcloud = this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, IFACE_("Point Cloud"), ICON_POINTCLOUD_DATA); + pointcloud.add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_POINT_CLOUD, ATTR_DOMAIN_POINT, IFACE_("Point"), ICON_PARTICLE_POINT); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_VOLUME, IFACE_("Volume Grids"), ICON_VOLUME_DATA); + + this->add_tree_item<GeometryDataSetTreeViewItem>( + GEO_COMPONENT_TYPE_INSTANCES, ATTR_DOMAIN_INSTANCE, IFACE_("Instances"), ICON_EMPTY_AXIS); + } +}; -const std::array<int, 2> &DatasetDrawContext::cursor_mval() const +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(std::nullopt), icon_(icon) { - return mval_; + label_ = label; + this->set_collapsed(false); } - -/* -------------------------------------------------------------------- */ -/* Drawer */ - -DatasetRegionDrawer::DatasetRegionDrawer(const ARegion *region, - uiBlock &block, - DatasetDrawContext &draw_context) - : row_height(UI_UNIT_Y), - xmin(region->v2d.cur.xmin), - xmax(region->v2d.cur.xmax), - block(block), - v2d(region->v2d), - draw_context(draw_context) +GeometryDataSetTreeViewItem::GeometryDataSetTreeViewItem(GeometryComponentType component_type, + AttributeDomain domain, + StringRef label, + BIFIconID icon) + : component_type_(component_type), domain_(domain), icon_(icon) { + label_ = label; } -void DatasetRegionDrawer::draw_hierarchy(const DatasetLayoutHierarchy &layout) +void GeometryDataSetTreeViewItem::on_activate() { - for (const DatasetComponentLayoutInfo &component : layout.components) { - draw_context.current_geometry_set = draw_context.geometry_set_from_component(component.type); - - draw_component_row(component); - - /* Iterate attribute domains, skip unset ones (storage has to be in a enum-based, fixed size - * array so uses optionals to support skipping enum values that shouldn't be displayed for a - * component). */ - for (const auto &optional_domain : component.attr_domains) { - if (!optional_domain) { - continue; - } - - const DatasetAttrDomainLayoutInfo &domain_info = *optional_domain; - draw_attribute_domain_row(component, domain_info); - } + GeometryDataSetTreeView &tree_view = this->get_tree(); + bContext &C = const_cast<bContext &>(tree_view.C_); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; + tree_view.sspreadsheet_.geometry_component_type = component_type_; + if (domain_) { + tree_view.sspreadsheet_.attribute_domain = *domain_; } + PointerRNA ptr; + RNA_pointer_create(&tree_view.screen_.id, &RNA_SpaceSpreadsheet, &sspreadsheet, &ptr); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "attribute_domain")); + RNA_property_update(&C, &ptr, RNA_struct_find_property(&ptr, "geometry_component_type")); } -static int element_count_from_instances(const GeometrySet &geometry_set) +void GeometryDataSetTreeViewItem::build_row(uiLayout &row) { - if (geometry_set.has_instances()) { - const InstancesComponent *instances_component = - geometry_set.get_component_for_read<InstancesComponent>(); - return instances_component->instances_amount(); + uiItemL(&row, label_.c_str(), icon_); + + if (const std::optional<int> count = this->count()) { + /* Using the tree row button instead of a separate right aligned button gives padding + * to the right side of the number, which it didn't have with the button. */ + char element_count[7]; + BLI_str_format_attribute_domain_size(element_count, *count); + UI_but_hint_drawstr_set((uiBut *)this->tree_row_button(), element_count); } - return 0; } -static int element_count_from_component_domain(const GeometrySet &geometry_set, - GeometryComponentType component, - AttributeDomain domain) +std::optional<bool> GeometryDataSetTreeViewItem::should_be_active() const { - if (geometry_set.has_mesh() && component == GEO_COMPONENT_TYPE_MESH) { - const MeshComponent *mesh_component = geometry_set.get_component_for_read<MeshComponent>(); - return mesh_component->attribute_domain_size(domain); - } + GeometryDataSetTreeView &tree_view = this->get_tree(); + SpaceSpreadsheet &sspreadsheet = tree_view.sspreadsheet_; - if (geometry_set.has_pointcloud() && component == GEO_COMPONENT_TYPE_POINT_CLOUD) { - const PointCloudComponent *point_cloud_component = - geometry_set.get_component_for_read<PointCloudComponent>(); - return point_cloud_component->attribute_domain_size(domain); + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + return sspreadsheet.geometry_component_type == component_type_; } - if (geometry_set.has_volume() && component == GEO_COMPONENT_TYPE_VOLUME) { - const VolumeComponent *volume_component = - geometry_set.get_component_for_read<VolumeComponent>(); - return volume_component->attribute_domain_size(domain); + if (!domain_) { + return false; } - if (geometry_set.has_curve() && component == GEO_COMPONENT_TYPE_CURVE) { - const CurveComponent *curve_component = geometry_set.get_component_for_read<CurveComponent>(); - return curve_component->attribute_domain_size(domain); - } - - return 0; + return sspreadsheet.geometry_component_type == component_type_ && + sspreadsheet.attribute_domain == *domain_; } -void DatasetRegionDrawer::draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - BIFIconID icon, - const char *label, - const bool is_active) +bool GeometryDataSetTreeViewItem::supports_collapsing() const { + return false; +} - const float row_height = UI_UNIT_Y; - const float padding_x = UI_UNIT_X * 0.25f; - - const rctf rect = {float(xmin) + padding_x, - float(xmax) - V2D_SCROLL_HANDLE_WIDTH, - ymin_offset - row_height, - ymin_offset}; - - char element_count[7]; - if (component == GEO_COMPONENT_TYPE_INSTANCES) { - BLI_str_format_attribute_domain_size( - element_count, element_count_from_instances(draw_context.current_geometry_set)); - } - else { - BLI_str_format_attribute_domain_size( - element_count, - domain ? element_count_from_component_domain( - draw_context.current_geometry_set, component, *domain) : - 0); - } +GeometryDataSetTreeView &GeometryDataSetTreeViewItem::get_tree() const +{ + return static_cast<GeometryDataSetTreeView &>(this->get_tree_view()); +} - std::string label_and_element_count = label; - label_and_element_count += UI_SEP_CHAR; - label_and_element_count += element_count; - - uiBut *bt = uiDefIconTextButO(&block, - UI_BTYPE_DATASETROW, - "SPREADSHEET_OT_change_spreadsheet_data_source", - 0, - icon, - label, - rect.xmin, - rect.ymin, - BLI_rctf_size_x(&rect), - BLI_rctf_size_y(&rect), - nullptr); - - UI_but_datasetrow_indentation_set(bt, indentation); - - if (is_active) { - UI_but_hint_drawstr_set(bt, element_count); - UI_but_datasetrow_component_set(bt, component); - if (domain) { - UI_but_datasetrow_domain_set(bt, *domain); - } - UI_but_func_pushed_state_set(bt, &is_component_row_selected, draw_context.sspreadsheet); +std::optional<int> GeometryDataSetTreeViewItem::count() const +{ + GeometryDataSetTreeView &tree_view = this->get_tree(); + GeometrySet &geometry = tree_view.geometry_set_; - PointerRNA *but_ptr = UI_but_operator_ptr_get((uiBut *)bt); - RNA_int_set(but_ptr, "component_type", component); - if (domain) { - RNA_int_set(but_ptr, "attribute_domain_type", *domain); + /* Special case for volumes since there is no grid domain. */ + if (component_type_ == GEO_COMPONENT_TYPE_VOLUME) { + if (const Volume *volume = geometry.get_volume_for_read()) { + return BKE_volume_num_grids(volume); } + return 0; } - ymin_offset -= row_height; -} - -void DatasetRegionDrawer::draw_component_row(const DatasetComponentLayoutInfo &component_info) -{ - if (component_info.type == GEO_COMPONENT_TYPE_INSTANCES) { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, true); + if (!domain_) { + return std::nullopt; } - else { - draw_dataset_row( - 0, component_info.type, std::nullopt, component_info.icon, component_info.label, false); + + if (const GeometryComponent *component = geometry.get_component_for_read(component_type_)) { + return component->attribute_domain_size(*domain_); } -} -void DatasetRegionDrawer::draw_attribute_domain_row( - const DatasetComponentLayoutInfo &component_info, - const DatasetAttrDomainLayoutInfo &domain_info) -{ - draw_dataset_row( - 1, component_info.type, domain_info.type, domain_info.icon, domain_info.label, true); + return 0; } -/* -------------------------------------------------------------------- */ -/* Drawer */ - -void draw_dataset_in_region(const bContext *C, ARegion *region) +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel) { - DatasetDrawContext draw_context{C}; - if (!draw_context.object_eval) { - /* No object means nothing to display. Keep the region empty. */ + const SpaceSpreadsheet *sspreadsheet = CTX_wm_space_spreadsheet(C); + Object *object = spreadsheet_get_object_eval(sspreadsheet, CTX_data_depsgraph_pointer(C)); + if (!object) { return; } + uiLayout *layout = panel->layout; - uiBlock *block = UI_block_begin(C, region, __func__, UI_EMBOSS); - - DatasetRegionDrawer drawer{region, *block, draw_context}; + uiBlock *block = uiLayoutGetBlock(layout); - /* Start with an offset to align buttons to spreadsheet rows. Use spreadsheet drawing info for - * that. */ - drawer.ymin_offset = -SpreadsheetDrawer().top_row_height + drawer.row_height; + UI_block_layout_set_current(block, layout); - const DatasetLayoutHierarchy hierarchy = dataset_layout_hierarchy(); - drawer.draw_hierarchy(hierarchy); -#ifndef NDEBUG - dataset_layout_hierarchy_sanity_check(hierarchy); -#endif + ui::AbstractTreeView *tree_view = UI_block_add_view( + *block, + "Data Set Tree View", + std::make_unique<GeometryDataSetTreeView>( + spreadsheet_get_display_geometry_set(sspreadsheet, object), *C)); - UI_block_end(C, block); - UI_view2d_totRect_set(®ion->v2d, region->winx, abs(drawer.ymin_offset)); - UI_block_draw(C, block); + ui::TreeViewBuilder builder(*block); + builder.build_tree_view(*tree_view); } } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh index 19906d73e7f..4a604533f11 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_draw.hh @@ -16,49 +16,11 @@ #pragma once -#include <array> - -#include "BKE_geometry_set.hh" -#include "UI_interface.h" -#include "spreadsheet_dataset_layout.hh" - -struct ARegion; -struct View2D; +struct Panel; struct bContext; -struct uiBlock; namespace blender::ed::spreadsheet { -class DatasetDrawContext; - -class DatasetRegionDrawer { - public: - const int row_height; - float ymin_offset = 0; - - int xmin; - int xmax; - uiBlock █ - const View2D &v2d; - DatasetDrawContext &draw_context; - - DatasetRegionDrawer(const ARegion *region, uiBlock &block, DatasetDrawContext &draw_context); - - void draw_hierarchy(const DatasetLayoutHierarchy &layout); - - void draw_attribute_domain_row(const DatasetComponentLayoutInfo &component, - const DatasetAttrDomainLayoutInfo &domain_info); - void draw_component_row(const DatasetComponentLayoutInfo &component_info); - - private: - void draw_dataset_row(const int indentation, - const GeometryComponentType component, - const std::optional<AttributeDomain> domain, - const BIFIconID icon, - const char *label, - const bool is_active); -}; - -void draw_dataset_in_region(const bContext *C, ARegion *region); +void spreadsheet_data_set_panel_draw(const bContext *C, Panel *panel); } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc deleted file mode 100644 index abbad8c7088..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.cc +++ /dev/null @@ -1,112 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include <optional> - -#include "BLI_span.hh" - -#include "BLT_translation.h" - -#include "spreadsheet_dataset_layout.hh" - -namespace blender::ed::spreadsheet { - -#define ATTR_INFO(type, label, icon) \ - std::optional<DatasetAttrDomainLayoutInfo> \ - { \ - std::in_place, type, label, icon \ - } -#define ATTR_INFO_NONE(type) \ - { \ - std::nullopt \ - } - -/** - * Definition for the component->attribute-domain hierarchy. - * Constructed at compile time. - * - * \warning Order of attribute-domains matters! It __must__ match the #AttributeDomain - * definition and fill gaps with unset optionals (i.e. `std::nullopt`). Would be nice to use - * array designators for this (which C++ doesn't support). - */ -constexpr DatasetComponentLayoutInfo DATASET_layout_hierarchy[] = { - { - GEO_COMPONENT_TYPE_MESH, - N_("Mesh"), - ICON_MESH_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Vertex"), ICON_VERTEXSEL), - ATTR_INFO(ATTR_DOMAIN_EDGE, N_("Edge"), ICON_EDGESEL), - ATTR_INFO(ATTR_DOMAIN_FACE, N_("Face"), ICON_FACESEL), - ATTR_INFO(ATTR_DOMAIN_CORNER, N_("Face Corner"), ICON_NODE_CORNER), - }, - }, - { - GEO_COMPONENT_TYPE_CURVE, - N_("Curves"), - ICON_CURVE_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Control Point"), ICON_CURVE_BEZCIRCLE), - ATTR_INFO_NONE(ATTR_DOMAIN_EDGE), - ATTR_INFO_NONE(ATTR_DOMAIN_CORNER), - ATTR_INFO_NONE(ATTR_DOMAIN_FACE), - ATTR_INFO(ATTR_DOMAIN_CURVE, N_("Spline"), ICON_CURVE_PATH), - }, - }, - { - GEO_COMPONENT_TYPE_POINT_CLOUD, - N_("Point Cloud"), - ICON_POINTCLOUD_DATA, - { - ATTR_INFO(ATTR_DOMAIN_POINT, N_("Point"), ICON_PARTICLE_POINT), - }, - }, - { - GEO_COMPONENT_TYPE_INSTANCES, - N_("Instances"), - ICON_EMPTY_AXIS, - {}, - }, -}; - -#undef ATTR_INFO -#undef ATTR_INFO_LABEL - -DatasetLayoutHierarchy dataset_layout_hierarchy() -{ - return DatasetLayoutHierarchy{ - Span{DATASET_layout_hierarchy, ARRAY_SIZE(DATASET_layout_hierarchy)}}; -} - -#ifndef NDEBUG -/** - * Debug-only sanity check for correct attribute domain initialization (order/indices must - * match AttributeDomain). This doesn't check for all possible missuses, but should catch the most - * likely mistakes. - */ -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy) -{ - for (const DatasetComponentLayoutInfo &component : hierarchy.components) { - for (uint i = 0; i < component.attr_domains.size(); i++) { - if (component.attr_domains[i]) { - BLI_assert(component.attr_domains[i]->type == static_cast<AttributeDomain>(i)); - } - } - } -} -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh deleted file mode 100644 index d463739a0fa..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_dataset_layout.hh +++ /dev/null @@ -1,68 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include <array> -#include <optional> - -/* Enum definitions... */ -#include "BKE_attribute.h" -#include "BKE_geometry_set.h" - -#include "BLI_span.hh" - -/* More enum definitions... */ -#include "UI_resources.h" - -#pragma once - -namespace blender::ed::spreadsheet { - -struct DatasetAttrDomainLayoutInfo { - AttributeDomain type; - const char *label; - BIFIconID icon; - - constexpr DatasetAttrDomainLayoutInfo(AttributeDomain type, const char *label, BIFIconID icon) - : type(type), label(label), icon(icon) - { - } -}; - -struct DatasetComponentLayoutInfo { - GeometryComponentType type; - const char *label; - BIFIconID icon; - /** Array of attribute-domains. Has to be fixed size based on #AttributeDomain enum, but not all - * values need displaying for all parent components. Hence the optional use. */ - using AttrDomainArray = std::array<std::optional<DatasetAttrDomainLayoutInfo>, ATTR_DOMAIN_NUM>; - const AttrDomainArray attr_domains; -}; - -struct DatasetLayoutHierarchy { - /** The components for display (with layout info like icon and label). Each component stores - * the attribute domains it wants to display (also with layout info like icon and label). */ - const Span<DatasetComponentLayoutInfo> components; -}; - -DatasetLayoutHierarchy dataset_layout_hierarchy(); - -#ifndef NDEBUG -void dataset_layout_hierarchy_sanity_check(const DatasetLayoutHierarchy &hierarchy); -#endif - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh index 8b050c2e69b..e62835d5792 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -37,6 +37,7 @@ struct SpaceSpreadsheet_Runtime { }; struct bContext; +struct ARegionType; void spreadsheet_operatortypes(void); void spreadsheet_update_context_path(const bContext *C); @@ -45,6 +46,8 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, namespace blender::ed::spreadsheet { GeometrySet spreadsheet_get_display_geometry_set(const SpaceSpreadsheet *sspreadsheet, - Object *object_eval, - const GeometryComponentType used_component_type); -} + Object *object_eval); + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type); + +} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 355899be279..202523c0e64 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -228,6 +228,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { 0, nullptr); } + else if (cell_value.value_string.has_value()) { + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_NONE, + cell_value.value_string->c_str(), + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + } } void draw_float_vector(const CellDrawParams ¶ms, const Span<float> values) const diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc new file mode 100644 index 00000000000..8f923ea4a63 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc @@ -0,0 +1,37 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BKE_screen.h" + +#include "BLT_translation.h" + +#include "spreadsheet_dataset_draw.hh" +#include "spreadsheet_intern.hh" + +namespace blender::ed::spreadsheet { + +void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type) +{ + PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); + strcpy(panel_type->label, N_("Data Set")); + strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + panel_type->flag = PANEL_TYPE_NO_HEADER; + panel_type->draw = spreadsheet_data_set_panel_draw; + BLI_addtail(®ion_type.paneltypes, panel_type); +} + +} // namespace blender::ed::spreadsheet
\ No newline at end of file diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index d56049990b4..a07abac4474 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -105,12 +105,15 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, return row_filter.value_string; } return ""; - case SPREADSHEET_VALUE_TYPE_COLOR: + case SPREADSHEET_VALUE_TYPE_COLOR: { std::ostringstream result; result.precision(3); result << std::fixed << "(" << row_filter.value_color[0] << ", " << row_filter.value_color[1] << ", " << row_filter.value_color[2] << ", " << row_filter.value_color[3] << ")"; return result.str(); + } + case SPREADSHEET_VALUE_TYPE_STRING: + return row_filter.value_string; } BLI_assert_unreachable(); return ""; @@ -234,6 +237,8 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "value_color", 0, IFACE_("Value"), ICON_NONE); uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); break; + case SPREADSHEET_VALUE_TYPE_STRING: + break; } } diff --git a/source/blender/editors/space_text/text_draw.c b/source/blender/editors/space_text/text_draw.c index b541b65d676..f8d16e396d4 100644 --- a/source/blender/editors/space_text/text_draw.c +++ b/source/blender/editors/space_text/text_draw.c @@ -70,7 +70,7 @@ static void text_draw_context_init(const SpaceText *st, TextDrawContext *tdc) static void text_font_begin(const TextDrawContext *tdc) { - BLF_size(tdc->font_id, tdc->lheight_px, 72); + BLF_size(tdc->font_id, (float)tdc->lheight_px, 72); } static void text_font_end(const TextDrawContext *UNUSED(tdc)) diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 458a1be0308..3c0ffa29bbd 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -86,6 +86,30 @@ static void test_line_start(char c, bool *r_last_state) } /** + * This function receives a character and returns its closing pair if it exists. + * \param character: Character to find the closing pair. + * \return The closing pair of the character if it exists. + */ +static char text_closing_character_pair_get(const char character) +{ + + switch (character) { + case '(': + return ')'; + case '[': + return ']'; + case '{': + return '}'; + case '"': + return '"'; + case '\'': + return '\''; + default: + return 0; + } +} + +/** * This function converts the indentation tabs from a buffer to spaces. * \param in_buf: A pointer to a cstring. * \param tab_size: The size, in spaces, of the tab character. @@ -2403,7 +2427,17 @@ static int text_delete_exec(bContext *C, wmOperator *op) } } } - + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + const char *curr = text->curl->line + text->curc; + if (*curr != '\0') { + const char *prev = BLI_str_find_prev_char_utf8(curr, text->curl->line); + if ((curr != prev) && /* When back-spacing from the start of the line. */ + (*curr == text_closing_character_pair_get(*prev))) { + txt_move_right(text, false); + txt_backspace_char(text); + } + } + } txt_backspace_char(text); } else if (type == DEL_NEXT_WORD) { @@ -3443,6 +3477,12 @@ static int text_insert_exec(bContext *C, wmOperator *op) while (str[i]) { code = BLI_str_utf8_as_unicode_step(str, str_len, &i); done |= txt_add_char(text, code); + if (U.text_flag & USER_TEXT_EDIT_AUTO_CLOSE) { + if (text_closing_character_pair_get(code)) { + done |= txt_add_char(text, text_closing_character_pair_get(code)); + txt_move_left(text, false); + } + } } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 6b9da431510..48f39f835c5 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -48,58 +48,6 @@ #include "view3d_intern.h" /* bad level include */ -/* OpenGL Circle Drawing - Tables for Optimized Drawing Speed */ -/* 32 values of sin function (still same result!) */ -#define CIRCLE_RESOL 32 - -static const float sinval[CIRCLE_RESOL] = { - 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, - 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, - 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, - -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, - -0.57126821, -0.39435585, -0.20129852, 0.00000000, -}; - -/* 32 values of cos function (still same result!) */ -static const float cosval[CIRCLE_RESOL] = { - 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, - 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, - -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, - -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, - 0.82076344, 0.91895781, 0.97952994, 1.00000000, -}; - -static void circball_array_fill(const float verts[CIRCLE_RESOL][3], - const float cent[3], - float rad, - const float tmat[4][4]) -{ - float vx[3], vy[3]; - float *viter = (float *)verts; - - mul_v3_v3fl(vx, tmat[0], rad); - mul_v3_v3fl(vy, tmat[1], rad); - - for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { - viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; - viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; - viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; - } -} - -void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) -{ - float verts[CIRCLE_RESOL][3]; - - circball_array_fill(verts, cent, rad, tmat); - - immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); - for (int i = 0; i < CIRCLE_RESOL; i++) { - immVertex3fv(pos, verts[i]); - } - immEnd(); -} - #ifdef VIEW3D_CAMERA_BORDER_HACK uchar view3d_camera_border_hack_col[3]; bool view3d_camera_border_hack_test = false; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index bf16dfb469c..e54ef3c931a 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -853,7 +853,6 @@ static void view3d_dropboxes(void) drop->draw = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; - drop->opcontext = WM_OP_EXEC_DEFAULT; /* Not really needed. */ drop = WM_dropbox_add(lb, "OBJECT_OT_transform_to_mouse", @@ -865,7 +864,6 @@ static void view3d_dropboxes(void) drop->draw = WM_drag_draw_item_name_fn; drop->draw_activate = view3d_ob_drop_draw_activate; drop->draw_deactivate = view3d_ob_drop_draw_deactivate; - drop->opcontext = WM_OP_INVOKE_DEFAULT; WM_dropbox_add(lb, "OBJECT_OT_drop_named_material", diff --git a/source/blender/editors/space_view3d/view3d_cursor_snap.c b/source/blender/editors/space_view3d/view3d_cursor_snap.c index 1213614704d..ac80a70011a 100644 --- a/source/blender/editors/space_view3d/view3d_cursor_snap.c +++ b/source/blender/editors/space_view3d/view3d_cursor_snap.c @@ -95,9 +95,7 @@ typedef struct SnapCursorDataIntern { static SnapCursorDataIntern g_data_intern = { .state_default = {.prevpoint = NULL, - .snap_elem_force = (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | - SCE_SNAP_MODE_FACE | SCE_SNAP_MODE_EDGE_PERPENDICULAR | - SCE_SNAP_MODE_EDGE_MIDPOINT), + .snap_elem_force = SCE_SNAP_MODE_GEOM, .plane_axis = 2, .color_point = {255, 255, 255, 255}, .color_line = {255, 255, 255, 128}, diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index fceb6553cab..6f6fa8b7576 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1318,10 +1318,9 @@ static void draw_viewport_name(ARegion *region, View3D *v3d, int xoffset, int *y } /** - * Draw info beside axes in bottom left-corner: + * Draw info beside axes in top-left corner: * frame-number, collection, object name, bone name (if available), marker name (if available). */ - static void draw_selected_name( Scene *scene, ViewLayer *view_layer, Object *ob, int xoffset, int *yoffset) { @@ -1344,14 +1343,13 @@ static void draw_selected_name( (ob == NULL) ? "" : " |"); } - /* - * info can contain: - * - a frame (7 + 2) - * - a collection name (MAX_NAME + 3) - * - 3 object names (MAX_NAME) - * - 2 BREAD_CRUMB_SEPARATORs (6) - * - a SHAPE_KEY_PINNED marker and a trailing '\0' (9+1) - translated, so give some room! - * - a marker name (MAX_NAME + 3) + /* Info can contain: + * - A frame `(7 + 2)`. + * - A collection name `(MAX_NAME + 3)`. + * - 3 object names `(MAX_NAME)`. + * - 2 BREAD_CRUMB_SEPARATOR(s) `(6)`. + * - A SHAPE_KEY_PINNED marker and a trailing '\0' `(9+1)` - translated, so give some room! + * - A marker name `(MAX_NAME + 3)`. */ /* get name of marker on current frame (if available) */ diff --git a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c index 34e3b808b50..1082483dcd7 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_ruler.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_ruler.c @@ -115,8 +115,10 @@ enum { CONSTRAIN_AXIS_Z = 2, }; -/* Constraining modes. - Off / Scene orientation / Global (or Local if Scene orientation is Global) */ +/** + * Constraining modes. + * Off / Scene orientation / Global (or Local if Scene orientation is Global). + */ enum { CONSTRAIN_MODE_OFF = 0, CONSTRAIN_MODE_1 = 1, @@ -163,7 +165,7 @@ typedef struct RulerInfo { typedef struct RulerItem { wmGizmo gz; - /* worldspace coords, middle being optional */ + /** World-space coords, middle being optional. */ float co[3][3]; int flag; @@ -643,7 +645,7 @@ static void gizmo_ruler_draw(const bContext *C, wmGizmo *gz) GPU_line_width(1.0f); BLF_enable(blf_mono_font, BLF_ROTATION); - BLF_size(blf_mono_font, 14 * U.pixelsize, U.dpi); + BLF_size(blf_mono_font, 14.0f * U.pixelsize, U.dpi); BLF_rotation(blf_mono_font, 0.0f); UI_GetThemeColor3ubv(TH_TEXT, color_text); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index eb8c043319c..823aa3b6643 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -63,19 +63,19 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) char str[FILE_MAX]; int num_copied = 0; - BKE_copybuffer_begin(bmain); + BKE_copybuffer_copy_begin(bmain); /* context, selection, could be generalized */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if ((ob->id.tag & LIB_TAG_DOIT) == 0) { - BKE_copybuffer_tag_ID(&ob->id); + BKE_copybuffer_copy_tag_ID(&ob->id); num_copied++; } } CTX_DATA_END; BLI_join_dirfile(str, sizeof(str), BKE_tempdir_base(), "copybuffer.blend"); - BKE_copybuffer_save(bmain, str, op->reports); + BKE_copybuffer_copy_end(bmain, str, op->reports); BKE_reportf(op->reports, RPT_INFO, "Copied %d selected object(s)", num_copied); diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index cecd1765a17..8c1cab6bf14 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -45,10 +45,6 @@ #include "view3d_intern.h" -#define SNAP_MODE_GEOM \ - (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ - SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) - static const char *view3d_gzgt_placement_id = "VIEW3D_GGT_placement"; /** @@ -1308,7 +1304,7 @@ static int idp_rna_snap_target_get_fn(struct PointerRNA *UNUSED(ptr), } /* Make sure you keep a consistent #snap_mode. */ - snap_state->snap_elem_force = SNAP_MODE_GEOM; + snap_state->snap_elem_force = SCE_SNAP_MODE_GEOM; return PLACE_SNAP_TO_GEOMETRY; } @@ -1319,7 +1315,7 @@ static void idp_rna_snap_target_set_fn(struct PointerRNA *UNUSED(ptr), short snap_mode = 0; /* #toolsettings->snap_mode. */ const enum ePlace_SnapTo snap_to = value; if (snap_to == PLACE_SNAP_TO_GEOMETRY) { - snap_mode = SNAP_MODE_GEOM; + snap_mode = SCE_SNAP_MODE_GEOM; } V3DSnapCursorState *snap_state = ED_view3d_cursor_snap_state_get(); diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index e09453b9957..d6a1cd930fc 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -1094,17 +1094,10 @@ bool ED_view3d_autodist_simple(ARegion *region, return ED_view3d_unproject_v3(region, centx, centy, depth, mouse_worldloc); } -bool ED_view3d_autodist_depth(ARegion *region, const int mval[2], int margin, float *depth) -{ - *depth = view_autodist_depth_margin(region, mval, margin); - - return (*depth != FLT_MAX); -} - static bool depth_segment_cb(int x, int y, void *userData) { struct { - ARegion *region; + const ViewDepths *vd; int margin; float depth; } *data = userData; @@ -1114,27 +1107,25 @@ static bool depth_segment_cb(int x, int y, void *userData) mval[0] = x; mval[1] = y; - depth = view_autodist_depth_margin(data->region, mval, data->margin); - - if (depth != FLT_MAX) { + if (ED_view3d_depth_read_cached(data->vd, mval, data->margin, &depth)) { data->depth = depth; return false; } return true; } -bool ED_view3d_autodist_depth_seg( - ARegion *region, const int mval_sta[2], const int mval_end[2], int margin, float *depth) +bool ED_view3d_depth_read_cached_seg( + const ViewDepths *vd, const int mval_sta[2], const int mval_end[2], int margin, float *depth) { struct { - ARegion *region; + const ViewDepths *vd; int margin; float depth; } data = {NULL}; int p1[2]; int p2[2]; - data.region = region; + data.vd = vd; data.margin = margin; data.depth = FLT_MAX; @@ -1691,6 +1682,9 @@ bool ED_view3d_depth_read_cached(const ViewDepths *vd, return true; } + /* Grease-pencil and annotations also need the returned depth value to be high + * so the caller can detect it's invalid. */ + *r_depth = FLT_MAX; return false; } diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index 46a664f10fa..6f0ce6c9326 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -1731,9 +1731,9 @@ void ED_view3d_xr_shading_update(wmWindowManager *wm, const View3D *v3d, const S View3DShading *xr_shading = &wm->xr.session_settings.shading; /* Flags that shouldn't be overridden by the 3D View shading. */ int flag_copy = 0; - if (v3d->shading.type != - OB_SOLID) { /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results - in distorted lighting when the view matrix has a scale factor. */ + if (v3d->shading.type != OB_SOLID) { + /* Don't set V3D_SHADING_WORLD_ORIENTATION for solid shading since it results in distorted + * lighting when the view matrix has a scale factor. */ flag_copy |= V3D_SHADING_WORLD_ORIENTATION; } diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index e13e7c3f93a..d78cd13f8b8 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -317,9 +317,9 @@ typedef struct TransSnap { /* Snapped Element Type (currently for objects only). */ char snapElem; /** snapping from this point (in global-space). */ - float snapPoint[3]; - /** to this point (in global-space). */ float snapTarget[3]; + /** to this point (in global-space). */ + float snapPoint[3]; float snapTargetGrid[3]; float snapNormal[3]; char snapNodeBorder; diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c index a6658ae00a3..24d84bc2de8 100644 --- a/source/blender/editors/transform/transform_convert_action.c +++ b/source/blender/editors/transform/transform_convert_action.c @@ -159,8 +159,11 @@ static void TimeToTransData( copy_v2_v2(td2d->ih2, td2d->h2); /* Setup #TransData. */ - td->loc = time; /* Usually #td2d->loc is used here. But this is for when the original location is - not float[3]. */ + + /* Usually #td2d->loc is used here. + * But this is for when the original location is not float[3]. */ + td->loc = time; + copy_v3_v3(td->iloc, td->loc); td->val = time; td->ival = *(time); diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 87cc7a27829..c911331404f 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -144,7 +144,6 @@ static void *t_view_get(TransInfo *t) View3D *v3d = t->area->spacedata.first; return (void *)v3d; } - if (t->region) { return (void *)&t->region->v2d; } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 82574cffb82..233e32c0e48 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -403,7 +403,7 @@ static void applyTranslationValue(TransInfo *t, const float vec[3]) * since re-applying translation without rotation removes rotation. */ } else { - /* When transforming data that it's self stores rotation (objects, bones etc), + /* When transforming data that itself stores rotation (objects, bones etc), * apply rotation if it was applied (with the snap normal) previously. * This is needed because failing to rotate will leave the rotation at the last * value used before snapping was disabled. */ diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 7f27d5fb180..71f26ef0594 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -200,7 +200,7 @@ void drawSnapping(const struct bContext *C, TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { bool draw_target = (t->tsnap.status & TARGET_INIT) && - (t->scene->toolsettings->snap_mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); + (t->tsnap.mode & SCE_SNAP_MODE_EDGE_PERPENDICULAR); if (draw_target || validSnap(t)) { const float *loc_cur = NULL; @@ -483,7 +483,7 @@ void applySnapping(TransInfo *t, float *vec) } if (t->tsnap.project && t->tsnap.mode == SCE_SNAP_MODE_FACE) { - /* The snap has already been resolved for each transdata. */ + /* A similar snap will be applied to each transdata in `applyProject`. */ return; } @@ -574,70 +574,61 @@ static bool bm_face_is_snap_target(BMFace *f, void *UNUSED(user_data)) return true; } -static void initSnappingMode(TransInfo *t) +static short snap_mode_from_scene(TransInfo *t) { ToolSettings *ts = t->settings; - /* All obedit types will match. */ - const int obedit_type = t->obedit_type; - ViewLayer *view_layer = t->view_layer; - Base *base_act = view_layer->basact; + short r_snap_mode = SCE_SNAP_MODE_INCREMENT; if (t->spacetype == SPACE_NODE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_node_mode; + r_snap_mode = ts->snap_node_mode; } else if (t->spacetype == SPACE_IMAGE) { - /* force project off when not supported */ - t->tsnap.project = 0; - - t->tsnap.mode = ts->snap_uv_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && + r_snap_mode = ts->snap_uv_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_uv_flag & SCE_SNAP_ABS_GRID) && (t->mode == TFM_TRANSLATION)) { - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; } } else if (t->spacetype == SPACE_SEQ) { - t->tsnap.mode = SEQ_tool_settings_snap_mode_get(t->scene); + r_snap_mode = SEQ_tool_settings_snap_mode_get(t->scene); } else if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* force project off when not supported */ - if ((ts->snap_mode & SCE_SNAP_MODE_FACE) == 0) { - t->tsnap.project = 0; - } - - t->tsnap.mode = ts->snap_mode; - if ((t->tsnap.mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && - (t->mode == TFM_TRANSLATION)) { - /* Special case in which snap to increments is transformed to snap to grid. */ - t->tsnap.mode &= ~SCE_SNAP_MODE_INCREMENT; - t->tsnap.mode |= SCE_SNAP_MODE_GRID; + /* All obedit types will match. */ + const int obedit_type = t->obedit_type; + if ((t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) || + ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL, -1)) { + r_snap_mode = ts->snap_mode; + if ((r_snap_mode & SCE_SNAP_MODE_INCREMENT) && (ts->snap_flag & SCE_SNAP_ABS_GRID) && + (t->mode == TFM_TRANSLATION)) { + /* Special case in which snap to increments is transformed to snap to grid. */ + r_snap_mode &= ~SCE_SNAP_MODE_INCREMENT; + r_snap_mode |= SCE_SNAP_MODE_GRID; + } } } else if (ELEM(t->spacetype, SPACE_ACTION, SPACE_NLA)) { /* No incremental snapping. */ - t->tsnap.mode = 0; - } - else { - /* Fallback. */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_mode = 0; } - if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { - /* Only 3D view or UV. */ - /* Not with camera selected in camera view. */ + return r_snap_mode; +} - setSnappingCallback(t); +static short snap_select_type_get(TransInfo *t) +{ + short r_snap_select = SNAP_ALL; + ViewLayer *view_layer = t->view_layer; + Base *base_act = view_layer->basact; + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE) && !(t->options & CTX_CAMERA)) { + const int obedit_type = t->obedit_type; if (t->options & (CTX_GPENCIL_STROKES | CTX_CURSOR | CTX_OBMODE_XFORM_OBDATA)) { /* In "Edit Strokes" mode, * snap tool can perform snap to selected or active objects (see T49632) * TODO: perform self snap in gpencil_strokes. * * When we're moving the origins, allow snapping onto our own geometry (see T69132). */ - t->tsnap.modeSelect = SNAP_ALL; } else if ((obedit_type != -1) && ELEM(obedit_type, OB_MESH, OB_ARMATURE, OB_CURVE, OB_LATTICE, OB_MBALL)) { @@ -646,29 +637,44 @@ static void initSnappingMode(TransInfo *t) if ((obedit_type == OB_MESH) && (t->flag & T_PROP_EDIT)) { /* Exclude editmesh if using proportional edit */ - t->tsnap.modeSelect = SNAP_NOT_ACTIVE; + r_snap_select = SNAP_NOT_ACTIVE; } - else { - t->tsnap.modeSelect = t->tsnap.snap_self ? SNAP_ALL : SNAP_NOT_ACTIVE; + else if (!t->tsnap.snap_self) { + r_snap_select = SNAP_NOT_ACTIVE; } } else if ((obedit_type == -1) && base_act && base_act->object && (base_act->object->mode & OB_MODE_PARTICLE_EDIT)) { /* Particles edit mode. */ - t->tsnap.modeSelect = SNAP_ALL; } else if (obedit_type == -1) { /* Object mode */ - t->tsnap.modeSelect = SNAP_NOT_SELECTED; - } - else { - /* Increment if snap is not possible */ - t->tsnap.mode = SCE_SNAP_MODE_INCREMENT; + r_snap_select = SNAP_NOT_SELECTED; } } else if (ELEM(t->spacetype, SPACE_NODE, SPACE_SEQ)) { - setSnappingCallback(t); - t->tsnap.modeSelect = SNAP_NOT_SELECTED; + r_snap_select = SNAP_NOT_SELECTED; + } + + return r_snap_select; +} + +static void initSnappingMode(TransInfo *t) +{ + ToolSettings *ts = t->settings; + t->tsnap.mode = snap_mode_from_scene(t); + t->tsnap.modeSelect = snap_select_type_get(t); + + if ((t->spacetype != SPACE_VIEW3D) || !(ts->snap_mode & SCE_SNAP_MODE_FACE)) { + /* Force project off when not supported. */ + t->tsnap.project = 0; + } + + if (ELEM(t->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_NODE, SPACE_SEQ)) { + /* Not with camera selected in camera view. */ + if (!(t->options & CTX_CAMERA)) { + setSnappingCallback(t); + } } if (t->spacetype == SPACE_VIEW3D) { @@ -918,8 +924,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) mval[0] = t->mval[0]; mval[1] = t->mval[1]; - if (t->tsnap.mode & (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | - SCE_SNAP_MODE_EDGE_MIDPOINT | SCE_SNAP_MODE_EDGE_PERPENDICULAR)) { + if (t->tsnap.mode & SCE_SNAP_MODE_GEOM) { zero_v3(no); /* objects won't set this */ snap_elem = snapObjectsTransform(t, mval, &dist_px, loc, no); found = snap_elem != 0; @@ -1249,7 +1254,7 @@ short snapObjectsTransform( t->depsgraph, t->region, t->view, - t->settings->snap_mode, + t->tsnap.mode, &(const struct SnapObjectParams){ .snap_select = t->tsnap.modeSelect, .edit_mode_type = (t->flag & T_EDIT) != 0 ? SNAP_GEOM_EDIT : SNAP_GEOM_FINAL, diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 4a2ac806b2c..4b981e763f1 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -581,15 +581,15 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH struct RayCastAll_Data *data = userdata; data->raycast_callback(data->bvhdata, index, ray, hit); if (hit->index != -1) { - /* get all values in worldspace */ + /* Get all values in world-space. */ float location[3], normal[3]; float depth; - /* worldspace location */ + /* World-space location. */ mul_v3_m4v3(location, (float(*)[4])data->obmat, hit->co); depth = (hit->dist + data->len_diff) / data->local_scale; - /* worldspace normal */ + /* World-space normal. */ copy_v3_v3(normal, hit->no); mul_m3_v3((float(*)[3])data->timat, normal); normalize_v3(normal); @@ -783,7 +783,7 @@ static bool raycastMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { @@ -953,7 +953,7 @@ static bool raycastEditMesh(SnapObjectContext *sctx, *ray_depth = hit.dist; copy_v3_v3(r_loc, hit.co); - /* back to worldspace */ + /* Back to world-space. */ mul_m4_v3(obmat, r_loc); if (r_no) { diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index 9bf00ed7092..de7fcb7a728 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -190,7 +190,7 @@ void FEdgeXDetector::computeCurvatures(WXVertex *vertex) } // CURVATURE LAYER - // store all the curvature datas for each vertex + // store all the curvature data for each vertex // soc unused - real K1, K2 real cos2theta, sin2theta; diff --git a/source/blender/functions/FN_field.hh b/source/blender/functions/FN_field.hh index 5e0302130af..28bb120bb17 100644 --- a/source/blender/functions/FN_field.hh +++ b/source/blender/functions/FN_field.hh @@ -178,11 +178,19 @@ class GFieldRef : public GFieldBase<const FieldNode *> { } }; +namespace detail { +/* Utility class to make #is_field_v work. */ +struct TypedFieldBase { +}; +} // namespace detail + /** * A typed version of #GField. It has the same memory layout as #GField. */ -template<typename T> class Field : public GField { +template<typename T> class Field : public GField, detail::TypedFieldBase { public: + using base_type = T; + Field() = default; Field(GField field) : GField(std::move(field)) @@ -196,6 +204,11 @@ template<typename T> class Field : public GField { } }; +/** True when T is any Field<...> type. */ +template<typename T> +static constexpr bool is_field_v = std::is_base_of_v<detail::TypedFieldBase, T> && + !std::is_same_v<detail::TypedFieldBase, T>; + /** * A #FieldNode that allows composing existing fields into new fields. */ @@ -248,9 +261,9 @@ class FieldInput : public FieldNode { * Get the value of this specific input based on the given context. The returned virtual array, * should live at least as long as the passed in #scope. May return null. */ - virtual const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const = 0; + virtual GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const = 0; virtual std::string socket_inspection_name() const; blender::StringRef debug_name() const; @@ -268,9 +281,9 @@ class FieldContext { public: ~FieldContext() = default; - virtual const GVArray *get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const; + virtual GVArray get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const; }; /** @@ -289,8 +302,8 @@ class FieldEvaluator : NonMovable, NonCopyable { const FieldContext &context_; const IndexMask mask_; Vector<GField> fields_to_evaluate_; - Vector<GVMutableArray *> dst_varrays_; - Vector<const GVArray *> evaluated_varrays_; + Vector<GVMutableArray> dst_varrays_; + Vector<GVArray> evaluated_varrays_; Vector<OutputPointerInfo> output_pointer_infos_; bool is_evaluated_ = false; @@ -317,13 +330,12 @@ class FieldEvaluator : NonMovable, NonCopyable { * \param field: Field to add to the evaluator. * \param dst: Mutable virtual array that the evaluated result for this field is be written into. */ - int add_with_destination(GField field, GVMutableArray &dst); + int add_with_destination(GField field, GVMutableArray dst); /** Same as #add_with_destination but typed. */ - template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> &dst) + template<typename T> int add_with_destination(Field<T> field, VMutableArray<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_VMutableArray<T>>(dst); - return this->add_with_destination(GField(std::move(field)), varray); + return this->add_with_destination(GField(std::move(field)), GVMutableArray(std::move(dst))); } /** @@ -342,11 +354,10 @@ class FieldEvaluator : NonMovable, NonCopyable { */ template<typename T> int add_with_destination(Field<T> field, MutableSpan<T> dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_MutableSpan<T>>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), VMutableArray<T>::ForSpan(dst)); } - int add(GField field, const GVArray **varray_ptr); + int add(GField field, GVArray *varray_ptr); /** * \param field: Field to add to the evaluator. @@ -354,14 +365,14 @@ class FieldEvaluator : NonMovable, NonCopyable { * assigned to the given position. * \return Index of the field in the evaluator which can be used in the #get_evaluated methods. */ - template<typename T> int add(Field<T> field, const VArray<T> **varray_ptr) + template<typename T> int add(Field<T> field, VArray<T> *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(nullptr); - output_pointer_infos_.append( - OutputPointerInfo{varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &scope) { - *(const VArray<T> **)dst = &*scope.construct<GVArray_Typed<T>>(varray); - }}); + dst_varrays_.append({}); + output_pointer_infos_.append(OutputPointerInfo{ + varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { + *(VArray<T> *)dst = varray.typed<T>(); + }}); return field_index; } @@ -378,14 +389,12 @@ class FieldEvaluator : NonMovable, NonCopyable { const GVArray &get_evaluated(const int field_index) const { BLI_assert(is_evaluated_); - return *evaluated_varrays_[field_index]; + return evaluated_varrays_[field_index]; } - template<typename T> const VArray<T> &get_evaluated(const int field_index) + template<typename T> VArray<T> get_evaluated(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<T> &typed_varray = scope_.construct<GVArray_Typed<T>>(varray); - return *typed_varray; + return this->get_evaluated(field_index).typed<T>(); } /** @@ -396,11 +405,11 @@ class FieldEvaluator : NonMovable, NonCopyable { IndexMask get_evaluated_as_mask(const int field_index); }; -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays = {}); +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays = {}); /* -------------------------------------------------------------------- */ /** \name Utility functions for simple field creation and evaluation @@ -423,17 +432,19 @@ template<typename T> Field<T> make_constant_field(T value) return Field<T>{GField{std::move(operation), 0}}; } +GField make_constant_field(const CPPType &type, const void *value); + GField make_field_constant_if_possible(GField field); class IndexFieldInput final : public FieldInput { public: IndexFieldInput(); - static GVArray *get_index_varray(IndexMask mask, ResourceScope &scope); + static GVArray get_index_varray(IndexMask mask, ResourceScope &scope); - const GVArray *get_varray_for_context(const FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final; + GVArray get_varray_for_context(const FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final; uint64_t hash() const override; bool is_equal_to(const fn::FieldNode &other) const override; @@ -442,6 +453,52 @@ class IndexFieldInput final : public FieldInput { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Value or Field Class + * + * Utility class that wraps a single value and a field, to simplify accessing both of the types. + * \{ */ + +template<typename T> struct ValueOrField { + /** Value that is used when the field is empty. */ + T value{}; + Field<T> field; + + ValueOrField() = default; + + ValueOrField(T value) : value(std::move(value)) + { + } + + ValueOrField(Field<T> field) : field(std::move(field)) + { + } + + bool is_field() const + { + return (bool)this->field; + } + + Field<T> as_field() const + { + if (this->field) { + return this->field; + } + return make_constant_field(this->value); + } + + T as_value() const + { + if (this->field) { + /* This returns a default value when the field is not constant. */ + return evaluate_constant_field(this->field); + } + return this->value; + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name #FieldNode Inline Methods * \{ */ diff --git a/source/blender/functions/FN_field_cpp_type.hh b/source/blender/functions/FN_field_cpp_type.hh index 5e6f1b5a585..940faba6d70 100644 --- a/source/blender/functions/FN_field_cpp_type.hh +++ b/source/blender/functions/FN_field_cpp_type.hh @@ -30,19 +30,19 @@ template<typename T> struct FieldCPPTypeParam { class FieldCPPType : public CPPType { private: - const CPPType &field_type_; + const CPPType &base_type_; public: template<typename T> FieldCPPType(FieldCPPTypeParam<Field<T>> /* unused */, StringRef debug_name) : CPPType(CPPTypeParam<Field<T>, CPPTypeFlags::None>(), debug_name), - field_type_(CPPType::get<T>()) + base_type_(CPPType::get<T>()) { } - const CPPType &field_type() const + const CPPType &base_type() const { - return field_type_; + return base_type_; } /* Ensure that #GField and #Field<T> have the same layout, to enable casting between the two. */ @@ -60,6 +60,84 @@ class FieldCPPType : public CPPType { } }; +class ValueOrFieldCPPType : public CPPType { + private: + const CPPType &base_type_; + void (*construct_from_value_)(void *dst, const void *value); + void (*construct_from_field_)(void *dst, GField field); + const void *(*get_value_ptr_)(const void *value_or_field); + const GField *(*get_field_ptr_)(const void *value_or_field); + bool (*is_field_)(const void *value_or_field); + GField (*as_field_)(const void *value_or_field); + + public: + template<typename T> + ValueOrFieldCPPType(FieldCPPTypeParam<ValueOrField<T>> /* unused */, StringRef debug_name) + : CPPType(CPPTypeParam<ValueOrField<T>, CPPTypeFlags::None>(), debug_name), + base_type_(CPPType::get<T>()) + { + construct_from_value_ = [](void *dst, const void *value_or_field) { + new (dst) ValueOrField<T>(*(const T *)value_or_field); + }; + construct_from_field_ = [](void *dst, GField field) { + new (dst) ValueOrField<T>(Field<T>(std::move(field))); + }; + get_value_ptr_ = [](const void *value_or_field) { + return (const void *)&((ValueOrField<T> *)value_or_field)->value; + }; + get_field_ptr_ = [](const void *value_or_field) -> const GField * { + return &((ValueOrField<T> *)value_or_field)->field; + }; + is_field_ = [](const void *value_or_field) { + return ((ValueOrField<T> *)value_or_field)->is_field(); + }; + as_field_ = [](const void *value_or_field) -> GField { + return ((ValueOrField<T> *)value_or_field)->as_field(); + }; + } + + const CPPType &base_type() const + { + return base_type_; + } + + void construct_from_value(void *dst, const void *value) const + { + construct_from_value_(dst, value); + } + + void construct_from_field(void *dst, GField field) const + { + construct_from_field_(dst, field); + } + + const void *get_value_ptr(const void *value_or_field) const + { + return get_value_ptr_(value_or_field); + } + + void *get_value_ptr(void *value_or_field) const + { + /* Use `const_cast` to avoid duplicating the callback for the non-const case. */ + return const_cast<void *>(get_value_ptr_(value_or_field)); + } + + const GField *get_field_ptr(const void *value_or_field) const + { + return get_field_ptr_(value_or_field); + } + + bool is_field(const void *value_or_field) const + { + return is_field_(value_or_field); + } + + GField as_field(const void *value_or_field) const + { + return as_field_(value_or_field); + } +}; + } // namespace blender::fn #define MAKE_FIELD_CPP_TYPE(DEBUG_NAME, FIELD_TYPE) \ @@ -69,4 +147,13 @@ class FieldCPPType : public CPPType { static blender::fn::FieldCPPType cpp_type{ \ blender::fn::FieldCPPTypeParam<blender::fn::Field<FIELD_TYPE>>(), STRINGIFY(DEBUG_NAME)}; \ return cpp_type; \ + } \ + template<> \ + const blender::fn::CPPType & \ + blender::fn::CPPType::get_impl<blender::fn::ValueOrField<FIELD_TYPE>>() \ + { \ + static blender::fn::ValueOrFieldCPPType cpp_type{ \ + blender::fn::FieldCPPTypeParam<blender::fn::ValueOrField<FIELD_TYPE>>(), \ + STRINGIFY(DEBUG_NAME##OrValue)}; \ + return cpp_type; \ } diff --git a/source/blender/functions/FN_generic_vector_array.hh b/source/blender/functions/FN_generic_vector_array.hh index 179e85671f8..57efa1b5ba9 100644 --- a/source/blender/functions/FN_generic_vector_array.hh +++ b/source/blender/functions/FN_generic_vector_array.hh @@ -125,8 +125,7 @@ template<typename T> class GVectorArray_TypedMutableRef { void extend(const int64_t index, const VArray<T> &values) { - GVArray_For_VArray<T> array{values}; - this->extend(index, array); + vector_array_->extend(index, values); } MutableSpan<T> operator[](const int64_t index) diff --git a/source/blender/functions/FN_generic_virtual_array.hh b/source/blender/functions/FN_generic_virtual_array.hh index 8aad017e68b..b822f3a7c33 100644 --- a/source/blender/functions/FN_generic_virtual_array.hh +++ b/source/blender/functions/FN_generic_virtual_array.hh @@ -23,8 +23,7 @@ * the data type is only known at runtime. */ -#include <optional> - +#include "BLI_timeit.hh" #include "BLI_virtual_array.hh" #include "FN_generic_array.hh" @@ -32,940 +31,845 @@ namespace blender::fn { -template<typename T> class GVArray_Typed; -template<typename T> class GVMutableArray_Typed; +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl and #GVMutableArrayImpl. + * \{ */ class GVArray; +class GVArrayImpl; class GVMutableArray; +class GVMutableArrayImpl; -using GVArrayPtr = std::unique_ptr<GVArray>; -using GVMutableArrayPtr = std::unique_ptr<GVMutableArray>; - -/* A generically typed version of `VArray<T>`. */ -class GVArray { +/* A generically typed version of #VArrayImpl. */ +class GVArrayImpl { protected: const CPPType *type_; int64_t size_; public: - GVArray(const CPPType &type, const int64_t size) : type_(&type), size_(size) - { - BLI_assert(size_ >= 0); - } + GVArrayImpl(const CPPType &type, const int64_t size); + virtual ~GVArrayImpl() = default; - virtual ~GVArray() = default; + const CPPType &type() const; - const CPPType &type() const - { - return *type_; - } + int64_t size() const; - int64_t size() const - { - return size_; - } + virtual void get(const int64_t index, void *r_value) const; + virtual void get_to_uninitialized(const int64_t index, void *r_value) const = 0; - bool is_empty() const - { - return size_ == 0; - } + virtual bool is_span() const; + virtual GSpan get_internal_span() const; - /* Copies the value at the given index into the provided storage. The `r_value` pointer is - * expected to point to initialized memory. */ - void get(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_impl(index, r_value); - } + virtual bool is_single() const; + virtual void get_internal_single(void *UNUSED(r_value)) const; - /* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ - void get_to_uninitialized(const int64_t index, void *r_value) const - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->get_to_uninitialized_impl(index, r_value); - } + virtual void materialize(const IndexMask mask, void *dst) const; + virtual void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - /* Returns true when the virtual array is stored as a span internally. */ - bool is_span() const - { - if (size_ == 0) { - return true; - } - return this->is_span_impl(); - } + virtual bool try_assign_VArray(void *varray) const; + virtual bool may_have_ownership() const; +}; - /* Returns the internally used span of the virtual array. This invokes undefined behavior is the - * virtual array is not stored as a span internally. */ - GSpan get_internal_span() const - { - BLI_assert(this->is_span()); - if (size_ == 0) { - return GSpan(*type_); - } - return this->get_internal_span_impl(); - } +/* A generic version of #VMutableArrayImpl. */ +class GVMutableArrayImpl : public GVArrayImpl { + public: + GVMutableArrayImpl(const CPPType &type, const int64_t size); - /* Returns true when the virtual array returns the same value for every index. */ - bool is_single() const - { - if (size_ == 1) { - return true; - } - return this->is_single_impl(); - } + virtual void set_by_copy(const int64_t index, const void *value); + virtual void set_by_relocate(const int64_t index, void *value); + virtual void set_by_move(const int64_t index, void *value) = 0; - /* Copies the value that is used for every element into `r_value`, which is expected to point to - * initialized memory. This invokes undefined behavior if the virtual array would not return the - * same value for every index. */ - void get_internal_single(void *r_value) const - { - BLI_assert(this->is_single()); - if (size_ == 1) { - this->get(0, r_value); - return; - } - this->get_internal_single_impl(r_value); - } + virtual void set_all(const void *src); - /* Same as `get_internal_single`, but `r_value` points to initialized memory. */ - void get_internal_single_to_uninitialized(void *r_value) const - { - type_->default_construct(r_value); - this->get_internal_single(r_value); - } + virtual bool try_assign_VMutableArray(void *varray) const; +}; - void materialize(void *dst) const; - void materialize(const IndexMask mask, void *dst) const; +/** \} */ - void materialize_to_uninitialized(void *dst) const; - void materialize_to_uninitialized(const IndexMask mask, void *dst) const; +/* -------------------------------------------------------------------- */ +/** \name #GVArray and #GVMutableArray + * \{ */ - template<typename T> const VArray<T> *try_get_internal_varray() const - { - BLI_assert(type_->is<T>()); - return (const VArray<T> *)this->try_get_internal_varray_impl(); - } +namespace detail { +struct GVArrayAnyExtraInfo { + const GVArrayImpl *(*get_varray)(const void *buffer) = + [](const void *UNUSED(buffer)) -> const GVArrayImpl * { return nullptr; }; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVArray_Typed<T> typed() const - { - return GVArray_Typed<T>(*this); - } + template<typename StorageT> static GVArrayAnyExtraInfo get(); +}; +} // namespace detail - GVArrayPtr shallow_copy() const; +class GVMutableArray; +/** + * Utility class to reduce code duplication between #GVArray and #GVMutableArray. + * It pretty much follows #VArrayCommon. Don't use this class outside of this header. + */ +class GVArrayCommon { protected: - virtual void get_impl(const int64_t index, void *r_value) const; - virtual void get_to_uninitialized_impl(const int64_t index, void *r_value) const = 0; + /** + * See #VArrayCommon for more information. The inline buffer is a bit larger here, because + * generic virtual array implementations often require a bit more space than typed ones. + */ + using Storage = Any<detail::GVArrayAnyExtraInfo, 40, 8>; - virtual bool is_span_impl() const; - virtual GSpan get_internal_span_impl() const; + const GVArrayImpl *impl_ = nullptr; + Storage storage_; - virtual bool is_single_impl() const; - virtual void get_internal_single_impl(void *UNUSED(r_value)) const; + protected: + GVArrayCommon(); + GVArrayCommon(const GVArrayCommon &other); + GVArrayCommon(GVArrayCommon &&other) noexcept; + GVArrayCommon(const GVArrayImpl *impl); + GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl); + ~GVArrayCommon(); - virtual void materialize_impl(const IndexMask mask, void *dst) const; - virtual void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const; + template<typename ImplT, typename... Args> void emplace(Args &&...args); - virtual const void *try_get_internal_varray_impl() const; -}; + void copy_from(const GVArrayCommon &other); + void move_from(GVArrayCommon &&other) noexcept; + + const GVArrayImpl *impl_from_storage() const; -/* Similar to GVArray, but supports changing the elements in the virtual array. */ -class GVMutableArray : public GVArray { public: - GVMutableArray(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + const CPPType &type() const; + operator bool() const; - void set_by_copy(const int64_t index, const void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_copy_impl(index, value); - } + int64_t size() const; + bool is_empty() const; + IndexRange index_range() const; - void set_by_move(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_move_impl(index, value); - } + template<typename T> bool try_assign_VArray(VArray<T> &varray) const; + bool may_have_ownership() const; - void set_by_relocate(const int64_t index, void *value) - { - BLI_assert(index >= 0); - BLI_assert(index < size_); - this->set_by_relocate_impl(index, value); - } + void materialize(void *dst) const; + void materialize(const IndexMask mask, void *dst) const; - GMutableSpan get_internal_span() - { - BLI_assert(this->is_span()); - GSpan span = static_cast<const GVArray *>(this)->get_internal_span(); - return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); - } + void materialize_to_uninitialized(void *dst) const; + void materialize_to_uninitialized(const IndexMask mask, void *dst) const; - template<typename T> VMutableArray<T> *try_get_internal_mutable_varray() - { - BLI_assert(type_->is<T>()); - return (VMutableArray<T> *)this->try_get_internal_mutable_varray_impl(); - } + bool is_span() const; + GSpan get_internal_span() const; - /* Create a typed virtual array for this generic virtual array. */ - template<typename T> GVMutableArray_Typed<T> typed() - { - return GVMutableArray_Typed<T>(*this); - } + bool is_single() const; + void get_internal_single(void *r_value) const; + void get_internal_single_to_uninitialized(void *r_value) const; - void fill(const void *value); + void get(const int64_t index, void *r_value) const; + void get_to_uninitialized(const int64_t index, void *r_value) const; +}; - /* Copy the values from the source buffer to all elements in the virtual array. */ - void set_all(const void *src) - { - this->set_all_impl(src); - } +/** Generic version of #VArray. */ +class GVArray : public GVArrayCommon { + private: + friend GVMutableArray; - protected: - virtual void set_by_copy_impl(const int64_t index, const void *value); - virtual void set_by_relocate_impl(const int64_t index, void *value); - virtual void set_by_move_impl(const int64_t index, void *value) = 0; + public: + GVArray() = default; - virtual void set_all_impl(const void *src); + GVArray(const GVArray &other); + GVArray(GVArray &&other) noexcept; + GVArray(const GVArrayImpl *impl); + GVArray(std::shared_ptr<const GVArrayImpl> impl); - virtual void *try_get_internal_mutable_varray_impl(); -}; + template<typename T> GVArray(const VArray<T> &varray); + template<typename T> VArray<T> typed() const; -class GVArray_For_GSpan : public GVArray { - protected: - const void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVArray For(Args &&...args); - public: - GVArray_For_GSpan(const GSpan span) - : GVArray(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) - { - } + static GVArray ForSingle(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleRef(const CPPType &type, const int64_t size, const void *value); + static GVArray ForSingleDefault(const CPPType &type, const int64_t size); + static GVArray ForSpan(GSpan span); + static GVArray ForGArray(GArray<> array); + static GVArray ForEmpty(const CPPType &type); - protected: - GVArray_For_GSpan(const CPPType &type, const int64_t size) - : GVArray(type, size), element_size_(type.size()) - { - } + GVArray slice(IndexRange slice) const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVArray &operator=(const GVArray &other); + GVArray &operator=(GVArray &&other) noexcept; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; + const GVArrayImpl *get_implementation() const + { + return impl_; + } }; -class GVArray_For_Empty : public GVArray { +/** Generic version of #VMutableArray. */ +class GVMutableArray : public GVArrayCommon { public: - GVArray_For_Empty(const CPPType &type) : GVArray(type, 0) - { - } + GVMutableArray() = default; + GVMutableArray(const GVMutableArray &other); + GVMutableArray(GVMutableArray &&other) noexcept; + GVMutableArray(GVMutableArrayImpl *impl); + GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl); - protected: - void get_to_uninitialized_impl(const int64_t UNUSED(index), void *UNUSED(r_value)) const override - { - BLI_assert(false); - } -}; + template<typename T> GVMutableArray(const VMutableArray<T> &varray); + template<typename T> VMutableArray<T> typed() const; -class GVMutableArray_For_GMutableSpan : public GVMutableArray { - protected: - void *data_ = nullptr; - const int64_t element_size_; + template<typename ImplT, typename... Args> static GVMutableArray For(Args &&...args); - public: - GVMutableArray_For_GMutableSpan(const GMutableSpan span) - : GVMutableArray(span.type(), span.size()), - data_(span.data()), - element_size_(span.type().size()) - { - } + static GVMutableArray ForSpan(GMutableSpan span); - protected: - GVMutableArray_For_GMutableSpan(const CPPType &type, const int64_t size) - : GVMutableArray(type, size), element_size_(type.size()) - { - } + operator GVArray() const &; + operator GVArray() &&noexcept; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + GVMutableArray &operator=(const GVMutableArray &other); + GVMutableArray &operator=(GVMutableArray &&other) noexcept; - void set_by_copy_impl(const int64_t index, const void *value) override; - void set_by_move_impl(const int64_t index, void *value) override; - void set_by_relocate_impl(const int64_t index, void *value) override; + GMutableSpan get_internal_span() const; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; -}; + template<typename T> bool try_assign_VMutableArray(VMutableArray<T> &varray) const; -/* Generic virtual array where each element has the same value. The value is not owned. */ -class GVArray_For_SingleValueRef : public GVArray { - protected: - const void *value_ = nullptr; + void set_by_copy(const int64_t index, const void *value); + void set_by_move(const int64_t index, void *value); + void set_by_relocate(const int64_t index, void *value); - public: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) - : GVArray(type, size), value_(value) - { - } + void fill(const void *value); + void set_all(const void *src); - protected: - GVArray_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArray(type, size) - { - } + GVMutableArrayImpl *get_implementation() const; - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; + private: + GVMutableArrayImpl *get_impl() const; +}; - bool is_span_impl() const override; - GSpan get_internal_span_impl() const override; +/** \} */ - bool is_single_impl() const override; - void get_internal_single_impl(void *r_value) const override; +/* -------------------------------------------------------------------- */ +/** \name #GVArray_GSpan and #GVMutableArray_GSpan. + * \{ */ + +/* A generic version of VArray_Span. */ +class GVArray_GSpan : public GSpan { + private: + GVArray varray_; + void *owned_data_ = nullptr; + + public: + GVArray_GSpan(GVArray varray); + ~GVArray_GSpan(); }; -/* Same as GVArray_For_SingleValueRef, but the value is owned. */ -class GVArray_For_SingleValue : public GVArray_For_SingleValueRef { +/* A generic version of VMutableArray_Span. */ +class GVMutableArray_GSpan : public GMutableSpan { + private: + GVMutableArray varray_; + void *owned_data_ = nullptr; + bool save_has_been_called_ = false; + bool show_not_saved_warning_ = true; + public: - GVArray_For_SingleValue(const CPPType &type, const int64_t size, const void *value); - ~GVArray_For_SingleValue(); + GVMutableArray_GSpan(GVMutableArray varray, bool copy_values_to_span = true); + ~GVMutableArray_GSpan(); + + void save(); + void disable_not_applied_warning(); }; +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Conversions between generic and typed virtual arrays. + * \{ */ + /* Used to convert a typed virtual array into a generic one. */ -template<typename T> class GVArray_For_VArray : public GVArray { +template<typename T> class GVArrayImpl_For_VArray : public GVArrayImpl { protected: - const VArray<T> *varray_ = nullptr; + VArray<T> varray_; public: - GVArray_For_VArray(const VArray<T> &varray) - : GVArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVArrayImpl_For_VArray(VArray<T> varray) + : GVArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVArray_For_VArray(const int64_t size) : GVArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); + return GSpan(varray_.get_internal_span()); } - GSpan get_internal_span_impl() const override + bool is_single() const override { - return GSpan(varray_->get_internal_span()); + return varray_.is_single(); } - bool is_single_impl() const override + void get_internal_single(void *r_value) const override { - return varray_->is_single(); + *(T *)r_value = varray_.get_internal_single(); } - void get_internal_single_impl(void *r_value) const override + void materialize(const IndexMask mask, void *dst) const override { - *(T *)r_value = varray_->get_internal_single(); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + bool try_assign_VArray(void *varray) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + *(VArray<T> *)varray = varray_; + return true; } - const void *try_get_internal_varray_impl() const override - { - return varray_; - } -}; - -class GVArray_For_GArray : public GVArray_For_GSpan { - protected: - GArray<> array_; - - public: - GVArray_For_GArray(GArray<> array) : GVArray_For_GSpan(array.as_span()), array_(std::move(array)) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; /* Used to convert any generic virtual array into a typed one. */ -template<typename T> class VArray_For_GVArray : public VArray<T> { +template<typename T> class VArrayImpl_For_GVArray : public VArrayImpl<T> { protected: - const GVArray *varray_ = nullptr; + GVArray varray_; public: - VArray_For_GVArray(const GVArray &varray) : VArray<T>(varray.size()), varray_(&varray) + VArrayImpl_For_GVArray(GVArray varray) : VArrayImpl<T>(varray.size()), varray_(std::move(varray)) { - BLI_assert(varray_->type().template is<T>()); + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } protected: - VArray_For_GVArray(const int64_t size) : VArray<T>(size) - { - } - - T get_impl(const int64_t index) const override + T get(const int64_t index) const override { T value; - varray_->get(index, &value); + varray_.get(index, &value); return value; } - bool is_span_impl() const override + bool is_span() const override { - return varray_->is_span(); + return varray_.is_span(); } - Span<T> get_internal_span_impl() const override + Span<T> get_internal_span() const override { - return varray_->get_internal_span().template typed<T>(); + return varray_.get_internal_span().template typed<T>(); } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - T get_internal_single_impl() const override + T get_internal_single() const override { T value; - varray_->get_internal_single(&value); + varray_.get_internal_single(&value); return value; } -}; - -/* Used to convert an generic mutable virtual array into a typed one. */ -template<typename T> class VMutableArray_For_GVMutableArray : public VMutableArray<T> { - protected: - GVMutableArray *varray_ = nullptr; - - public: - VMutableArray_For_GVMutableArray(GVMutableArray &varray) - : VMutableArray<T>(varray.size()), varray_(&varray) - { - BLI_assert(varray.type().template is<T>()); - } - - VMutableArray_For_GVMutableArray(const int64_t size) : VMutableArray<T>(size) - { - } - - private: - T get_impl(const int64_t index) const override - { - T value; - varray_->get(index, &value); - return value; - } - - void set_impl(const int64_t index, T value) override - { - varray_->set_by_relocate(index, &value); - } - - bool is_span_impl() const override - { - return varray_->is_span(); - } - Span<T> get_internal_span_impl() const override + bool try_assign_GVArray(GVArray &varray) const override { - return varray_->get_internal_span().template typed<T>(); + varray = varray_; + return true; } - bool is_single_impl() const override + bool may_have_ownership() const override { - return varray_->is_single(); - } - - T get_internal_single_impl() const override - { - T value; - varray_->get_internal_single(&value); - return value; + return varray_.may_have_ownership(); } }; /* Used to convert any typed virtual mutable array into a generic one. */ -template<typename T> class GVMutableArray_For_VMutableArray : public GVMutableArray { +template<typename T> class GVMutableArrayImpl_For_VMutableArray : public GVMutableArrayImpl { protected: - VMutableArray<T> *varray_ = nullptr; + VMutableArray<T> varray_; public: - GVMutableArray_For_VMutableArray(VMutableArray<T> &varray) - : GVMutableArray(CPPType::get<T>(), varray.size()), varray_(&varray) + GVMutableArrayImpl_For_VMutableArray(VMutableArray<T> varray) + : GVMutableArrayImpl(CPPType::get<T>(), varray.size()), varray_(std::move(varray)) { } protected: - GVMutableArray_For_VMutableArray(const int64_t size) : GVMutableArray(CPPType::get<T>(), size) + void get(const int64_t index, void *r_value) const override { + *(T *)r_value = varray_[index]; } - void get_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { - *(T *)r_value = varray_->get(index); + new (r_value) T(varray_[index]); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + bool is_span() const override { - new (r_value) T(varray_->get(index)); + return varray_.is_span(); } - bool is_span_impl() const override + GSpan get_internal_span() const override { - return varray_->is_span(); - } - - GSpan get_internal_span_impl() const override - { - Span<T> span = varray_->get_internal_span(); + Span<T> span = varray_.get_internal_span(); return span; } - bool is_single_impl() const override + bool is_single() const override { - return varray_->is_single(); + return varray_.is_single(); } - void get_internal_single_impl(void *r_value) const override + void get_internal_single(void *r_value) const override { - *(T *)r_value = varray_->get_internal_single(); + *(T *)r_value = varray_.get_internal_single(); } - void set_by_copy_impl(const int64_t index, const void *value) override + void set_by_copy(const int64_t index, const void *value) override { const T &value_ = *(const T *)value; - varray_->set(index, value_); + varray_.set(index, value_); } - void set_by_relocate_impl(const int64_t index, void *value) override + void set_by_relocate(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); value_.~T(); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { T &value_ = *(T *)value; - varray_->set(index, std::move(value_)); + varray_.set(index, std::move(value_)); } - void set_all_impl(const void *src) override + void set_all(const void *src) override { - varray_->set_all(Span((T *)src, size_)); + varray_.set_all(Span((T *)src, size_)); } - void materialize_impl(const IndexMask mask, void *dst) const override + void materialize(const IndexMask mask, void *dst) const override { - varray_->materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize(mask, MutableSpan((T *)dst, mask.min_array_size())); } - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override + void materialize_to_uninitialized(const IndexMask mask, void *dst) const override { - varray_->materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); + varray_.materialize_to_uninitialized(mask, MutableSpan((T *)dst, mask.min_array_size())); } - const void *try_get_internal_varray_impl() const override + bool try_assign_VArray(void *varray) const override { - return (const VArray<T> *)varray_; + *(VArray<T> *)varray = varray_; + return true; } - void *try_get_internal_mutable_varray_impl() override + bool try_assign_VMutableArray(void *varray) const override { - return varray_; + *(VMutableArray<T> *)varray = varray_; + return true; } -}; - -/* A generic version of VArray_Span. */ -class GVArray_GSpan : public GSpan { - private: - const GVArray &varray_; - void *owned_data_ = nullptr; - - public: - GVArray_GSpan(const GVArray &varray); - ~GVArray_GSpan(); -}; - -/* A generic version of VMutableArray_Span. */ -class GVMutableArray_GSpan : public GMutableSpan { - private: - GVMutableArray &varray_; - void *owned_data_ = nullptr; - bool save_has_been_called_ = false; - bool show_not_saved_warning_ = true; - - public: - GVMutableArray_GSpan(GVMutableArray &varray, bool copy_values_to_span = true); - ~GVMutableArray_GSpan(); - - void save(); - void disable_not_applied_warning(); -}; - -/* Similar to GVArray_GSpan, but the resulting span is typed. */ -template<typename T> class GVArray_Span : public Span<T> { - private: - GVArray_GSpan varray_gspan_; - public: - GVArray_Span(const GVArray &varray) : varray_gspan_(varray) + bool may_have_ownership() const override { - BLI_assert(varray.type().is<T>()); - this->data_ = (const T *)varray_gspan_.data(); - this->size_ = varray_gspan_.size(); + return varray_.may_have_ownership(); } }; -template<typename T> class GVArray_For_OwnedVArray : public GVArray_For_VArray<T> { - private: - VArrayPtr<T> owned_varray_; +/* Used to convert an generic mutable virtual array into a typed one. */ +template<typename T> class VMutableArrayImpl_For_GVMutableArray : public VMutableArrayImpl<T> { + protected: + GVMutableArray varray_; public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVArray_For_OwnedVArray(VArrayPtr<T> varray) - : GVArray_For_VArray<T>(*varray), owned_varray_(std::move(varray)) + VMutableArrayImpl_For_GVMutableArray(GVMutableArray varray) + : VMutableArrayImpl<T>(varray.size()), varray_(varray) { + BLI_assert(varray_); + BLI_assert(varray_.type().template is<T>()); } -}; -template<typename T> class VArray_For_OwnedGVArray : public VArray_For_GVArray<T> { private: - GVArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VArray_For_OwnedGVArray(GVArrayPtr varray) - : VArray_For_GVArray<T>(*varray), owned_varray_(std::move(varray)) + T get(const int64_t index) const override { + T value; + varray_.get(index, &value); + return value; } -}; -template<typename T> -class GVMutableArray_For_OwnedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayPtr<T> owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - GVMutableArray_For_OwnedVMutableArray(VMutableArrayPtr<T> varray) - : GVMutableArray_For_VMutableArray<T>(*varray), owned_varray_(std::move(varray)) + void set(const int64_t index, T value) override { + varray_.set_by_relocate(index, &value); } -}; -template<typename T> -class VMutableArray_For_OwnedGVMutableArray : public VMutableArray_For_GVMutableArray<T> { - private: - GVMutableArrayPtr owned_varray_; - - public: - /* Takes ownership of varray and passes a reference to the base class. */ - VMutableArray_For_OwnedGVMutableArray(GVMutableArrayPtr varray) - : VMutableArray_For_GVMutableArray<T>(*varray), owned_varray_(std::move(varray)) + bool is_span() const override { + return varray_.is_span(); } -}; - -/* Utility to embed a typed virtual array into a generic one. This avoids one allocation and give - * the compiler more opportunity to optimize the generic virtual array. */ -template<typename T, typename VArrayT> -class GVArray_For_EmbeddedVArray : public GVArray_For_VArray<T> { - private: - VArrayT embedded_varray_; - public: - template<typename... Args> - GVArray_For_EmbeddedVArray(const int64_t size, Args &&...args) - : GVArray_For_VArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + Span<T> get_internal_span() const override { - this->varray_ = &embedded_varray_; + return varray_.get_internal_span().template typed<T>(); } -}; -/* Same as GVArray_For_EmbeddedVArray, but for mutable virtual arrays. */ -template<typename T, typename VMutableArrayT> -class GVMutableArray_For_EmbeddedVMutableArray : public GVMutableArray_For_VMutableArray<T> { - private: - VMutableArrayT embedded_varray_; - - public: - template<typename... Args> - GVMutableArray_For_EmbeddedVMutableArray(const int64_t size, Args &&...args) - : GVMutableArray_For_VMutableArray<T>(size), embedded_varray_(std::forward<Args>(args)...) + bool is_single() const override { - this->varray_ = &embedded_varray_; + return varray_.is_single(); } -}; -/* Same as VArray_For_ArrayContainer, but for a generic virtual array. */ -template<typename Container, typename T = typename Container::value_type> -class GVArray_For_ArrayContainer - : public GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>> { - public: - GVArray_For_ArrayContainer(Container container) - : GVArray_For_EmbeddedVArray<T, VArray_For_ArrayContainer<Container, T>>( - container.size(), std::move(container)) + T get_internal_single() const override { + T value; + varray_.get_internal_single(&value); + return value; } -}; -/* Same as VArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class GVArray_For_DerivedSpan - : public GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>> { - public: - GVArray_For_DerivedSpan(const Span<StructT> data) - : GVArray_For_EmbeddedVArray<ElemT, VArray_For_DerivedSpan<StructT, ElemT, GetFunc>>( - data.size(), data) + bool try_assign_GVArray(GVArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VMutableArray_For_DerivedSpan, but for a generic virtual array. */ -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, ElemT)> -class GVMutableArray_For_DerivedSpan - : public GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>> { - public: - GVMutableArray_For_DerivedSpan(const MutableSpan<StructT> data) - : GVMutableArray_For_EmbeddedVMutableArray< - ElemT, - VMutableArray_For_DerivedSpan<StructT, ElemT, GetFunc, SetFunc>>(data.size(), data) + bool try_assign_GVMutableArray(GVMutableArray &varray) const override { + varray = varray_; + return true; } -}; -/* Same as VArray_For_Span, but for a generic virtual array. */ -template<typename T> -class GVArray_For_Span : public GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>> { - public: - GVArray_For_Span(const Span<T> data) - : GVArray_For_EmbeddedVArray<T, VArray_For_Span<T>>(data.size(), data) + bool may_have_ownership() const override { + return varray_.may_have_ownership(); } }; -/* Same as VMutableArray_For_MutableSpan, but for a generic virtual array. */ -template<typename T> -class GVMutableArray_For_MutableSpan - : public GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>> { +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayImpl_For_GSpan and #GVMutableArrayImpl_For_GMutableSpan. + * \{ */ + +class GVArrayImpl_For_GSpan : public GVArrayImpl { + protected: + const void *data_ = nullptr; + const int64_t element_size_; + public: - GVMutableArray_For_MutableSpan(const MutableSpan<T> data) - : GVMutableArray_For_EmbeddedVMutableArray<T, VMutableArray_For_MutableSpan<T>>(data.size(), - data) - { - } + GVArrayImpl_For_GSpan(const GSpan span); + + protected: + GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size); + + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; + + bool is_span() const override; + GSpan get_internal_span() const override; }; -/** - * Utility class to create the "best" typed virtual array for a given generic virtual array. - * In most cases we don't just want to use VArray_For_GVArray, because it adds an additional - * indirection on element-access that can be avoided in many cases (e.g. when the virtual array is - * just a span or single value). - * - * This is not a virtual array itself, but is used to get a virtual array. - */ -template<typename T> class GVArray_Typed { - private: - const VArray<T> *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<VArray_For_Span<T>> varray_span_; - std::optional<VArray_For_Single<T>> varray_single_; - std::optional<VArray_For_GVArray<T>> varray_any_; - GVArrayPtr owned_gvarray_; +class GVMutableArrayImpl_For_GMutableSpan : public GVMutableArrayImpl { + protected: + void *data_ = nullptr; + const int64_t element_size_; public: - explicit GVArray_Typed(const GVArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (gvarray.is_single()) { - T single_value; - gvarray.get_internal_single(&single_value); - varray_single_.emplace(single_value, gvarray.size()); - varray_ = &*varray_single_; - } - else if (const VArray<T> *internal_varray = gvarray.try_get_internal_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } + GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span); - /* Same as the constructor above, but also takes ownership of the passed in virtual array. */ - explicit GVArray_Typed(GVArrayPtr gvarray) : GVArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } + protected: + GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, const int64_t size); - const VArray<T> &operator*() const - { - return *varray_; - } + public: + void get(const int64_t index, void *r_value) const override; + void get_to_uninitialized(const int64_t index, void *r_value) const override; - const VArray<T> *operator->() const - { - return varray_; - } + void set_by_copy(const int64_t index, const void *value) override; + void set_by_move(const int64_t index, void *value) override; + void set_by_relocate(const int64_t index, void *value) override; - /* Support implicit cast to the typed virtual array for convenience when `varray->typed<T>()` is - * used within an expression. */ - operator const VArray<T> &() const - { - return *varray_; - } + bool is_span() const override; + GSpan get_internal_span() const override; +}; - T operator[](const int64_t index) const - { - return varray_->get(index); - } +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayImpl. + * \{ */ + +inline GVArrayImpl::GVArrayImpl(const CPPType &type, const int64_t size) + : type_(&type), size_(size) +{ + BLI_assert(size_ >= 0); +} + +inline const CPPType &GVArrayImpl::type() const +{ + return *type_; +} + +inline int64_t GVArrayImpl::size() const +{ + return size_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArrayImpl. + * \{ */ + +inline void GVMutableArray::set_by_copy(const int64_t index, const void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_copy(index, value); +} + +inline void GVMutableArray::set_by_move(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_move(index, value); +} + +inline void GVMutableArray::set_by_relocate(const int64_t index, void *value) +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + this->get_impl()->set_by_relocate(index, value); +} - int64_t size() const - { - return varray_->size(); +template<typename T> +inline bool GVMutableArray::try_assign_VMutableArray(VMutableArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return this->get_impl()->try_assign_VMutableArray(&varray); +} + +inline GVMutableArrayImpl *GVMutableArray::get_impl() const +{ + return (GVMutableArrayImpl *)impl_; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArrayCommon. + * \{ */ + +template<typename ImplT, typename... Args> inline void GVArrayCommon::emplace(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + if constexpr (std::is_copy_constructible_v<ImplT> && Storage::template is_inline_v<ImplT>) { + impl_ = &storage_.template emplace<ImplT>(std::forward<Args>(args)...); + } + else { + std::shared_ptr<const GVArrayImpl> ptr = std::make_shared<ImplT>(std::forward<Args>(args)...); + impl_ = &*ptr; + storage_ = std::move(ptr); + } +} + +/* Copies the value at the given index into the provided storage. The `r_value` pointer is + * expected to point to initialized memory. */ +inline void GVArrayCommon::get(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get(index, r_value); +} + +/* Same as `get`, but `r_value` is expected to point to uninitialized memory. */ +inline void GVArrayCommon::get_to_uninitialized(const int64_t index, void *r_value) const +{ + BLI_assert(index >= 0); + BLI_assert(index < this->size()); + impl_->get_to_uninitialized(index, r_value); +} + +template<typename T> inline bool GVArrayCommon::try_assign_VArray(VArray<T> &varray) const +{ + BLI_assert(impl_->type().is<T>()); + return impl_->try_assign_VArray(&varray); +} + +inline const CPPType &GVArrayCommon::type() const +{ + return impl_->type(); +} + +inline GVArrayCommon::operator bool() const +{ + return impl_ != nullptr; +} + +inline int64_t GVArrayCommon::size() const +{ + if (impl_ == nullptr) { + return 0; + } + return impl_->size(); +} + +inline bool GVArrayCommon::is_empty() const +{ + return this->size() == 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVArray. + * \{ */ + +namespace detail { +template<typename StorageT> inline GVArrayAnyExtraInfo GVArrayAnyExtraInfo::get() +{ + static_assert(std::is_base_of_v<GVArrayImpl, StorageT> || + std::is_same_v<StorageT, const GVArrayImpl *> || + std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>); + + if constexpr (std::is_base_of_v<GVArrayImpl, StorageT>) { + return {[](const void *buffer) { + return static_cast<const GVArrayImpl *>((const StorageT *)buffer); + }}; + } + else if constexpr (std::is_same_v<StorageT, const GVArrayImpl *>) { + return {[](const void *buffer) { return *(const StorageT *)buffer; }}; + } + else if constexpr (std::is_same_v<StorageT, std::shared_ptr<const GVArrayImpl>>) { + return {[](const void *buffer) { return ((const StorageT *)buffer)->get(); }}; + } + else { + BLI_assert_unreachable(); + return {}; + } +} +} // namespace detail + +template<typename ImplT, typename... Args> inline GVArray GVArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVArrayImpl, ImplT>); + GVArray varray; + varray.template emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} + +template<typename T> inline GVArray::GVArray(const VArray<T> &varray) +{ + if (!varray) { + return; + } + if (varray.try_assign_GVArray(*this)) { + return; + } + /* Need to check this before the span/single special cases, because otherwise we might loose + * ownership to the referenced data when #varray goes out of scope. */ + if (varray.may_have_ownership()) { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } + else if (varray.is_span()) { + Span<T> data = varray.get_internal_span(); + *this = GVArray::ForSpan(data); + } + else if (varray.is_single()) { + T value = varray.get_internal_single(); + *this = GVArray::ForSingle(CPPType::get<T>(), varray.size(), &value); + } + else { + *this = GVArray::For<GVArrayImpl_For_VArray<T>>(varray); + } +} + +template<typename T> inline VArray<T> GVArray::typed() const +{ + if (!*this) { + return {}; + } + BLI_assert(impl_->type().is<T>()); + VArray<T> varray; + if (this->try_assign_VArray(varray)) { + return varray; + } + if (this->may_have_ownership()) { + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); + } + if (this->is_span()) { + const Span<T> span = this->get_internal_span().typed<T>(); + return VArray<T>::ForSpan(span); } - - IndexRange index_range() const - { - return IndexRange(this->size()); + if (this->is_single()) { + T value; + this->get_internal_single(&value); + return VArray<T>::ForSingle(value, this->size()); } -}; + return VArray<T>::template For<VArrayImpl_For_GVArray<T>>(*this); +} -/* Same as GVArray_Typed, but for mutable virtual arrays. */ -template<typename T> class GVMutableArray_Typed { - private: - VMutableArray<T> *varray_; - std::optional<VMutableArray_For_MutableSpan<T>> varray_span_; - std::optional<VMutableArray_For_GVMutableArray<T>> varray_any_; - GVMutableArrayPtr owned_gvarray_; +/** \} */ - public: - explicit GVMutableArray_Typed(GVMutableArray &gvarray) - { - BLI_assert(gvarray.type().is<T>()); - if (gvarray.is_span()) { - const GMutableSpan span = gvarray.get_internal_span(); - varray_span_.emplace(span.typed<T>()); - varray_ = &*varray_span_; - } - else if (VMutableArray<T> *internal_varray = gvarray.try_get_internal_mutable_varray<T>()) { - varray_ = internal_varray; - } - else { - varray_any_.emplace(gvarray); - varray_ = &*varray_any_; - } - } +/* -------------------------------------------------------------------- */ +/** \name Inline methods for #GVMutableArray. + * \{ */ - explicit GVMutableArray_Typed(GVMutableArrayPtr gvarray) : GVMutableArray_Typed(*gvarray) - { - owned_gvarray_ = std::move(gvarray); - } +template<typename ImplT, typename... Args> +inline GVMutableArray GVMutableArray::For(Args &&...args) +{ + static_assert(std::is_base_of_v<GVMutableArrayImpl, ImplT>); + GVMutableArray varray; + varray.emplace<ImplT>(std::forward<Args>(args)...); + return varray; +} - VMutableArray<T> &operator*() - { - return *varray_; +template<typename T> inline GVMutableArray::GVMutableArray(const VMutableArray<T> &varray) +{ + if (!varray) { + return; } - - VMutableArray<T> *operator->() - { - return varray_; + if (varray.try_assign_GVMutableArray(*this)) { + return; } - - operator VMutableArray<T> &() - { - return *varray_; + if (varray.may_have_ownership()) { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } - - T operator[](const int64_t index) const - { - return varray_->get(index); + else if (varray.is_span()) { + MutableSpan<T> data = varray.get_internal_span(); + *this = GVMutableArray::ForSpan(data); } - - int64_t size() const - { - return varray_->size(); + else { + *this = GVMutableArray::For<GVMutableArrayImpl_For_VMutableArray<T>>(varray); } -}; - -class GVArray_For_SlicedGVArray : public GVArray { - protected: - const GVArray &varray_; - int64_t offset_; +} - public: - GVArray_For_SlicedGVArray(const GVArray &varray, const IndexRange slice) - : GVArray(varray.type(), slice.size()), varray_(varray), offset_(slice.start()) - { - BLI_assert(slice.one_after_last() <= varray.size()); +template<typename T> inline VMutableArray<T> GVMutableArray::typed() const +{ + if (!*this) { + return {}; } - - /* TODO: Add #materialize method. */ - void get_impl(const int64_t index, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override; -}; - -/** - * Utility class to create the "best" sliced virtual array. - */ -class GVArray_Slice { - private: - const GVArray *varray_; - /* Of these optional virtual arrays, at most one is constructed at any time. */ - std::optional<GVArray_For_GSpan> varray_span_; - std::optional<GVArray_For_SlicedGVArray> varray_any_; - - public: - GVArray_Slice(const GVArray &varray, const IndexRange slice); - - const GVArray &operator*() - { - return *varray_; + BLI_assert(this->type().is<T>()); + VMutableArray<T> varray; + if (this->try_assign_VMutableArray(varray)) { + return varray; } - - const GVArray *operator->() - { - return varray_; + if (this->may_have_ownership()) { + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); } - - operator const GVArray &() - { - return *varray_; + if (this->is_span()) { + const MutableSpan<T> span = this->get_internal_span().typed<T>(); + return VMutableArray<T>::ForSpan(span); } -}; + return VMutableArray<T>::template For<VMutableArrayImpl_For_GVMutableArray<T>>(*this); +} + +/** \} */ } // namespace blender::fn diff --git a/source/blender/functions/FN_generic_virtual_vector_array.hh b/source/blender/functions/FN_generic_virtual_vector_array.hh index 4155a55a801..b80e21eaef1 100644 --- a/source/blender/functions/FN_generic_virtual_vector_array.hh +++ b/source/blender/functions/FN_generic_virtual_vector_array.hh @@ -100,31 +100,31 @@ class GVVectorArray { } }; -class GVArray_For_GVVectorArrayIndex : public GVArray { +class GVArray_For_GVVectorArrayIndex : public GVArrayImpl { private: const GVVectorArray &vector_array_; const int64_t index_; public: GVArray_For_GVVectorArrayIndex(const GVVectorArray &vector_array, const int64_t index) - : GVArray(vector_array.type(), vector_array.get_vector_size(index)), + : GVArrayImpl(vector_array.type(), vector_array.get_vector_size(index)), vector_array_(vector_array), index_(index) { } protected: - void get_impl(const int64_t index_in_vector, void *r_value) const override; - void get_to_uninitialized_impl(const int64_t index_in_vector, void *r_value) const override; + void get(const int64_t index_in_vector, void *r_value) const override; + void get_to_uninitialized(const int64_t index_in_vector, void *r_value) const override; }; class GVVectorArray_For_SingleGVArray : public GVVectorArray { private: - const GVArray &array_; + GVArray varray_; public: - GVVectorArray_For_SingleGVArray(const GVArray &array, const int64_t size) - : GVVectorArray(array.type(), size), array_(array) + GVVectorArray_For_SingleGVArray(GVArray varray, const int64_t size) + : GVVectorArray(varray.type(), size), varray_(std::move(varray)) { } diff --git a/source/blender/functions/FN_multi_function.hh b/source/blender/functions/FN_multi_function.hh index 98788025558..3059fe59ca7 100644 --- a/source/blender/functions/FN_multi_function.hh +++ b/source/blender/functions/FN_multi_function.hh @@ -97,6 +97,8 @@ class MultiFunction { return signature_ref_->function_name; } + virtual std::string debug_name() const; + bool depends_on_context() const { return signature_ref_->depends_on_context; @@ -131,8 +133,6 @@ inline MFParamsBuilder::MFParamsBuilder(const MultiFunction &fn, const IndexMask { } -extern const MultiFunction &dummy_multi_function; - namespace multi_function_types { using fn::CPPType; using fn::GMutableSpan; diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 0ce05cbca30..eaf9e5ce70f 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -43,7 +43,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio MFSignature signature_; public: - CustomMF_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -53,7 +53,7 @@ template<typename In1, typename Out1> class CustomMF_SI_SO : public MultiFunctio } template<typename ElementFuncT> - CustomMF_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SO(name, CustomMF_SI_SO::create_function(element_fn)) { } @@ -92,7 +92,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -103,7 +103,7 @@ class CustomMF_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SO(name, CustomMF_SI_SI_SO::create_function(element_fn)) { } @@ -150,7 +150,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -162,7 +162,7 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SO::create_function(element_fn)) { } @@ -211,7 +211,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { MFSignature signature_; public: - CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SI_SI_SI_SI_SO(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_input<In1>("In1"); @@ -224,7 +224,7 @@ class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + CustomMF_SI_SI_SI_SI_SO(const char *name, ElementFuncT element_fn) : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn)) { } @@ -265,7 +265,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { MFSignature signature_; public: - CustomMF_SM(StringRef name, FunctionT function) : function_(std::move(function)) + CustomMF_SM(const char *name, FunctionT function) : function_(std::move(function)) { MFSignatureBuilder signature{name}; signature.single_mutable<Mut1>("Mut1"); @@ -274,7 +274,7 @@ template<typename Mut1> class CustomMF_SM : public MultiFunction { } template<typename ElementFuncT> - CustomMF_SM(StringRef name, ElementFuncT element_fn) + CustomMF_SM(const char *name, ElementFuncT element_fn) : CustomMF_SM(name, CustomMF_SM::create_function(element_fn)) { } @@ -306,8 +306,8 @@ template<typename From, typename To> class CustomMF_Convert : public MultiFuncti static MFSignature create_signature() { - std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); - MFSignatureBuilder signature{std::move(name)}; + static std::string name = CPPType::get<From>().name() + " to " + CPPType::get<To>().name(); + MFSignatureBuilder signature{name.c_str()}; signature.single_input<From>("Input"); signature.single_output<To>("Output"); return signature.build(); @@ -372,9 +372,7 @@ template<typename T> class CustomMF_Constant : public MultiFunction { template<typename U> CustomMF_Constant(U &&value) : value_(std::forward<U>(value)) { MFSignatureBuilder signature{"Constant"}; - std::stringstream ss; - ss << value_; - signature.single_output<T>(ss.str()); + signature.single_output<T>("Value"); signature_ = signature.build(); this->set_signature(&signature_); } @@ -414,9 +412,7 @@ class CustomMF_DefaultOutput : public MultiFunction { MFSignature signature_; public: - CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, - Span<MFDataType> output_types); + CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types); void call(IndexMask mask, MFParams params, MFContext context) const override; }; @@ -425,7 +421,7 @@ class CustomMF_GenericCopy : public MultiFunction { MFSignature signature_; public: - CustomMF_GenericCopy(StringRef name, MFDataType data_type); + CustomMF_GenericCopy(MFDataType data_type); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_params.hh b/source/blender/functions/FN_multi_function_params.hh index d187985de9d..5c7e75230f3 100644 --- a/source/blender/functions/FN_multi_function_params.hh +++ b/source/blender/functions/FN_multi_function_params.hh @@ -40,7 +40,7 @@ class MFParamsBuilder { const MFSignature *signature_; IndexMask mask_; int64_t min_array_size_; - Vector<const GVArray *> virtual_arrays_; + Vector<GVArray> virtual_arrays_; Vector<GMutableSpan> mutable_spans_; Vector<const GVVectorArray *> virtual_vector_arrays_; Vector<GVectorArray *> vector_arrays_; @@ -68,24 +68,22 @@ class MFParamsBuilder { template<typename T> void add_readonly_single_input(const T *value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(CPPType::get<T>(), min_array_size_, value), - expected_name); + GVArray::ForSingleRef(CPPType::get<T>(), min_array_size_, value), expected_name); } void add_readonly_single_input(const GSpan span, StringRef expected_name = "") { - this->add_readonly_single_input(scope_.construct<GVArray_For_GSpan>(span), expected_name); + this->add_readonly_single_input(GVArray::ForSpan(span), expected_name); } void add_readonly_single_input(GPointer value, StringRef expected_name = "") { this->add_readonly_single_input( - scope_.construct<GVArray_For_SingleValueRef>(*value.type(), min_array_size_, value.get()), - expected_name); + GVArray::ForSingleRef(*value.type(), min_array_size_, value.get()), expected_name); } - void add_readonly_single_input(const GVArray &ref, StringRef expected_name = "") + void add_readonly_single_input(GVArray varray, StringRef expected_name = "") { - this->assert_current_param_type(MFParamType::ForSingleInput(ref.type()), expected_name); - BLI_assert(ref.size() >= min_array_size_); - virtual_arrays_.append(&ref); + this->assert_current_param_type(MFParamType::ForSingleInput(varray.type()), expected_name); + BLI_assert(varray.size() >= min_array_size_); + virtual_arrays_.append(varray); } void add_readonly_vector_input(const GVectorArray &vector_array, StringRef expected_name = "") @@ -221,16 +219,16 @@ class MFParams { { } - template<typename T> const VArray<T> &readonly_single_input(int param_index, StringRef name = "") + template<typename T> VArray<T> readonly_single_input(int param_index, StringRef name = "") { - const GVArray &array = this->readonly_single_input(param_index, name); - return builder_->scope_.construct<GVArray_Typed<T>>(array); + const GVArray &varray = this->readonly_single_input(param_index, name); + return varray.typed<T>(); } const GVArray &readonly_single_input(int param_index, StringRef name = "") { this->assert_correct_param(param_index, name, MFParamType::SingleInput); int data_index = builder_->signature_->data_index(param_index); - return *builder_->virtual_arrays_[data_index]; + return builder_->virtual_arrays_[data_index]; } /** diff --git a/source/blender/functions/FN_multi_function_procedure_executor.hh b/source/blender/functions/FN_multi_function_procedure_executor.hh index 9c8b59739b8..b12e3a91210 100644 --- a/source/blender/functions/FN_multi_function_procedure_executor.hh +++ b/source/blender/functions/FN_multi_function_procedure_executor.hh @@ -31,7 +31,7 @@ class MFProcedureExecutor : public MultiFunction { const MFProcedure &procedure_; public: - MFProcedureExecutor(std::string name, const MFProcedure &procedure); + MFProcedureExecutor(const MFProcedure &procedure); void call(IndexMask mask, MFParams params, MFContext context) const override; }; diff --git a/source/blender/functions/FN_multi_function_signature.hh b/source/blender/functions/FN_multi_function_signature.hh index d05948cc645..3c991bc9c56 100644 --- a/source/blender/functions/FN_multi_function_signature.hh +++ b/source/blender/functions/FN_multi_function_signature.hh @@ -30,8 +30,15 @@ namespace blender::fn { struct MFSignature { - std::string function_name; - Vector<std::string> param_names; + /** + * The name should be statically allocated so that it lives longer than this signature. This is + * used instead of an #std::string because of the overhead when many functions are created. + * If the name of the function has to be more dynamic for debugging purposes, override + * #MultiFunction::debug_name() instead. Then the dynamic name will only be computed when it is + * actually needed. + */ + const char *function_name; + Vector<const char *> param_names; Vector<MFParamType> param_types; Vector<int> param_data_indices; bool depends_on_context = false; @@ -51,9 +58,9 @@ class MFSignatureBuilder { int vector_array_count_ = 0; public: - MFSignatureBuilder(std::string function_name) + MFSignatureBuilder(const char *function_name) { - signature_.function_name = std::move(function_name); + signature_.function_name = function_name; } MFSignature build() const @@ -63,23 +70,23 @@ class MFSignatureBuilder { /* Input Parameter Types */ - template<typename T> void single_input(StringRef name) + template<typename T> void single_input(const char *name) { this->single_input(name, CPPType::get<T>()); } - void single_input(StringRef name, const CPPType &type) + void single_input(const char *name, const CPPType &type) { this->input(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_input(StringRef name) + template<typename T> void vector_input(const char *name) { this->vector_input(name, CPPType::get<T>()); } - void vector_input(StringRef name, const CPPType &base_type) + void vector_input(const char *name, const CPPType &base_type) { this->input(name, MFDataType::ForVector(base_type)); } - void input(StringRef name, MFDataType data_type) + void input(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Input, data_type)); @@ -96,23 +103,23 @@ class MFSignatureBuilder { /* Output Parameter Types */ - template<typename T> void single_output(StringRef name) + template<typename T> void single_output(const char *name) { this->single_output(name, CPPType::get<T>()); } - void single_output(StringRef name, const CPPType &type) + void single_output(const char *name, const CPPType &type) { this->output(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_output(StringRef name) + template<typename T> void vector_output(const char *name) { this->vector_output(name, CPPType::get<T>()); } - void vector_output(StringRef name, const CPPType &base_type) + void vector_output(const char *name, const CPPType &base_type) { this->output(name, MFDataType::ForVector(base_type)); } - void output(StringRef name, MFDataType data_type) + void output(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Output, data_type)); @@ -129,23 +136,23 @@ class MFSignatureBuilder { /* Mutable Parameter Types */ - template<typename T> void single_mutable(StringRef name) + template<typename T> void single_mutable(const char *name) { this->single_mutable(name, CPPType::get<T>()); } - void single_mutable(StringRef name, const CPPType &type) + void single_mutable(const char *name, const CPPType &type) { this->mutable_(name, MFDataType::ForSingle(type)); } - template<typename T> void vector_mutable(StringRef name) + template<typename T> void vector_mutable(const char *name) { this->vector_mutable(name, CPPType::get<T>()); } - void vector_mutable(StringRef name, const CPPType &base_type) + void vector_mutable(const char *name, const CPPType &base_type) { this->mutable_(name, MFDataType::ForVector(base_type)); } - void mutable_(StringRef name, MFDataType data_type) + void mutable_(const char *name, MFDataType data_type) { signature_.param_names.append(name); signature_.param_types.append(MFParamType(MFParamType::Mutable, data_type)); @@ -160,7 +167,7 @@ class MFSignatureBuilder { } } - void add(StringRef name, const MFParamType ¶m_type) + void add(const char *name, const MFParamType ¶m_type) { switch (param_type.interface_type()) { case MFParamType::Input: diff --git a/source/blender/functions/intern/field.cc b/source/blender/functions/intern/field.cc index 4de5e71c910..7934490a6d9 100644 --- a/source/blender/functions/intern/field.cc +++ b/source/blender/functions/intern/field.cc @@ -81,19 +81,18 @@ static FieldTreeInfo preprocess_field_tree(Span<GFieldRef> entry_fields) /** * Retrieves the data from the context that is passed as input into the field. */ -static Vector<const GVArray *> get_field_context_inputs( +static Vector<GVArray> get_field_context_inputs( ResourceScope &scope, const IndexMask mask, const FieldContext &context, const Span<std::reference_wrapper<const FieldInput>> field_inputs) { - Vector<const GVArray *> field_context_inputs; + Vector<GVArray> field_context_inputs; for (const FieldInput &field_input : field_inputs) { - const GVArray *varray = context.get_varray_for_input(field_input, mask, scope); - if (varray == nullptr) { + GVArray varray = context.get_varray_for_input(field_input, mask, scope); + if (!varray) { const CPPType &type = field_input.cpp_type(); - varray = &scope.construct<GVArray_For_SingleValueRef>( - type, mask.min_array_size(), type.default_value()); + varray = GVArray::ForSingleDefault(type, mask.min_array_size()); } field_context_inputs.append(varray); } @@ -105,7 +104,7 @@ static Vector<const GVArray *> get_field_context_inputs( * for different indices. */ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, - Span<const GVArray *> field_context_inputs) + Span<GVArray> field_context_inputs) { Set<GFieldRef> found_fields; Stack<GFieldRef> fields_to_check; @@ -114,8 +113,8 @@ static Set<GFieldRef> find_varying_fields(const FieldTreeInfo &field_tree_info, * start the tree search at the non-constant input fields and traverse through all fields that * depend on them. */ for (const int i : field_context_inputs.index_range()) { - const GVArray *varray = field_context_inputs[i]; - if (varray->is_single()) { + const GVArray &varray = field_context_inputs[i]; + if (varray.is_single()) { continue; } const FieldInput &field_input = field_tree_info.deduplicated_field_inputs[i]; @@ -238,8 +237,7 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, if (!already_output_variables.add(variable)) { /* One variable can be output at most once. To output the same value twice, we have to make * a copy first. */ - const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>("copy", - variable->data_type()); + const MultiFunction ©_fn = scope.construct<CustomMF_GenericCopy>(variable->data_type()); variable = builder.add_call<1>(copy_fn, {variable})[0]; } builder.add_output_parameter(*variable); @@ -278,29 +276,42 @@ static void build_multi_function_procedure_for_fields(MFProcedure &procedure, * \return The computed virtual arrays for each provided field. If #dst_varrays is passed, the * provided virtual arrays are returned. */ -Vector<const GVArray *> evaluate_fields(ResourceScope &scope, - Span<GFieldRef> fields_to_evaluate, - IndexMask mask, - const FieldContext &context, - Span<GVMutableArray *> dst_varrays) +Vector<GVArray> evaluate_fields(ResourceScope &scope, + Span<GFieldRef> fields_to_evaluate, + IndexMask mask, + const FieldContext &context, + Span<GVMutableArray> dst_varrays) { - Vector<const GVArray *> r_varrays(fields_to_evaluate.size(), nullptr); + Vector<GVArray> r_varrays(fields_to_evaluate.size()); + Array<bool> is_output_written_to_dst(fields_to_evaluate.size(), false); const int array_size = mask.min_array_size(); + if (mask.is_empty()) { + for (const int i : fields_to_evaluate.index_range()) { + const CPPType &type = fields_to_evaluate[i].cpp_type(); + r_varrays[i] = GVArray::ForEmpty(type); + } + return r_varrays; + } + /* Destination arrays are optional. Create a small utility method to access them. */ - auto get_dst_varray_if_available = [&](int index) -> GVMutableArray * { + auto get_dst_varray = [&](int index) -> GVMutableArray { if (dst_varrays.is_empty()) { - return nullptr; + return {}; + } + const GVMutableArray &varray = dst_varrays[index]; + if (!varray) { + return {}; } - BLI_assert(dst_varrays[index] == nullptr || dst_varrays[index]->size() >= array_size); - return dst_varrays[index]; + BLI_assert(varray.size() >= array_size); + return varray; }; /* Traverse the field tree and prepare some data that is used in later steps. */ FieldTreeInfo field_tree_info = preprocess_field_tree(fields_to_evaluate); /* Get inputs that will be passed into the field when evaluated. */ - Vector<const GVArray *> field_context_inputs = get_field_context_inputs( + Vector<GVArray> field_context_inputs = get_field_context_inputs( scope, mask, context, field_tree_info.deduplicated_field_inputs); /* Finish fields that output an input varray directly. For those we don't have to do any further @@ -312,7 +323,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, } const FieldInput &field_input = static_cast<const FieldInput &>(field.node()); const int field_input_index = field_tree_info.deduplicated_field_inputs.index_of(field_input); - const GVArray *varray = field_context_inputs[field_input_index]; + const GVArray &varray = field_context_inputs[field_input_index]; r_varrays[out_index] = varray; } @@ -325,7 +336,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, Vector<GFieldRef> constant_fields_to_evaluate; Vector<int> constant_field_indices; for (const int i : fields_to_evaluate.index_range()) { - if (r_varrays[i] != nullptr) { + if (r_varrays[i]) { /* Already done. */ continue; } @@ -346,7 +357,7 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, varying_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; + MFProcedureExecutor procedure_executor{procedure}; /* Add multi threading capabilities to the field evaluation. */ const int grain_size = 10000; fn::ParallelMultiFunction parallel_procedure_executor{procedure_executor, grain_size}; @@ -357,8 +368,8 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : varying_fields_to_evaluate.index_range()) { @@ -367,9 +378,9 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, const int out_index = varying_field_indices[i]; /* Try to get an existing virtual array that the result should be written into. */ - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); + GVMutableArray dst_varray = get_dst_varray(out_index); void *buffer; - if (output_varray == nullptr || !output_varray->is_span()) { + if (!dst_varray || !dst_varray.is_span()) { /* Allocate a new buffer for the computed result. */ buffer = scope.linear_allocator().allocate(type.size() * array_size, type.alignment()); @@ -379,14 +390,14 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, [buffer, mask, &type]() { type.destruct_indices(buffer, mask); }); } - r_varrays[out_index] = &scope.construct<GVArray_For_GSpan>( - GSpan{type, buffer, array_size}); + r_varrays[out_index] = GVArray::ForSpan({type, buffer, array_size}); } else { /* Write the result into the existing span. */ - buffer = output_varray->get_internal_span().data(); + buffer = dst_varray.get_internal_span().data(); - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; + is_output_written_to_dst[out_index] = true; } /* Pass output buffer to the procedure executor. */ @@ -403,16 +414,13 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, MFProcedure procedure; build_multi_function_procedure_for_fields( procedure, scope, field_tree_info, constant_fields_to_evaluate); - MFProcedureExecutor procedure_executor{"Procedure", procedure}; - /* Run the code below even when the mask is empty, so that outputs are properly prepared. - * Higher level code can detect this as well and just skip evaluating the field. */ - const int mask_size = mask.is_empty() ? 0 : 1; - MFParamsBuilder mf_params{procedure_executor, mask_size}; + MFProcedureExecutor procedure_executor{procedure}; + MFParamsBuilder mf_params{procedure_executor, 1}; MFContextBuilder mf_context; /* Provide inputs to the procedure executor. */ - for (const GVArray *varray : field_context_inputs) { - mf_params.add_readonly_single_input(*varray); + for (const GVArray &varray : field_context_inputs) { + mf_params.add_readonly_single_input(varray); } for (const int i : constant_fields_to_evaluate.index_range()) { @@ -421,55 +429,52 @@ Vector<const GVArray *> evaluate_fields(ResourceScope &scope, /* Allocate memory where the computed value will be stored in. */ void *buffer = scope.linear_allocator().allocate(type.size(), type.alignment()); - if (!type.is_trivially_destructible() && mask_size > 0) { - BLI_assert(mask_size == 1); + if (!type.is_trivially_destructible()) { /* Destruct value in the end. */ scope.add_destruct_call([buffer, &type]() { type.destruct(buffer); }); } /* Pass output buffer to the procedure executor. */ - mf_params.add_uninitialized_single_output({type, buffer, mask_size}); + mf_params.add_uninitialized_single_output({type, buffer, 1}); /* Create virtual array that can be used after the procedure has been executed below. */ const int out_index = constant_field_indices[i]; - r_varrays[out_index] = &scope.construct<GVArray_For_SingleValueRef>( - type, array_size, buffer); + r_varrays[out_index] = GVArray::ForSingleRef(type, array_size, buffer); } - procedure_executor.call(IndexRange(mask_size), mf_params, mf_context); + procedure_executor.call(IndexRange(1), mf_params, mf_context); } - /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above has - * written the computed data in the right place already. */ + /* Copy data to supplied destination arrays if necessary. In some cases the evaluation above + * has written the computed data in the right place already. */ if (!dst_varrays.is_empty()) { for (const int out_index : fields_to_evaluate.index_range()) { - GVMutableArray *output_varray = get_dst_varray_if_available(out_index); - if (output_varray == nullptr) { + GVMutableArray dst_varray = get_dst_varray(out_index); + if (!dst_varray) { /* Caller did not provide a destination for this output. */ continue; } - const GVArray *computed_varray = r_varrays[out_index]; - BLI_assert(computed_varray->type() == output_varray->type()); - if (output_varray == computed_varray) { + const GVArray &computed_varray = r_varrays[out_index]; + BLI_assert(computed_varray.type() == dst_varray.type()); + if (is_output_written_to_dst[out_index]) { /* The result has been written into the destination provided by the caller already. */ continue; } /* Still have to copy over the data in the destination provided by the caller. */ - if (output_varray->is_span()) { + if (dst_varray.is_span()) { /* Materialize into a span. */ - computed_varray->materialize_to_uninitialized(mask, - output_varray->get_internal_span().data()); + computed_varray.materialize_to_uninitialized(mask, dst_varray.get_internal_span().data()); } else { /* Slower materialize into a different structure. */ - const CPPType &type = computed_varray->type(); + const CPPType &type = computed_varray.type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); for (const int i : mask) { - computed_varray->get_to_uninitialized(i, buffer); - output_varray->set_by_relocate(i, buffer); + computed_varray.get_to_uninitialized(i, buffer); + dst_varray.set_by_relocate(i, buffer); } } - r_varrays[out_index] = output_varray; + r_varrays[out_index] = dst_varray; } } return r_varrays; @@ -485,8 +490,8 @@ void evaluate_constant_field(const GField &field, void *r_value) ResourceScope scope; FieldContext context; - Vector<const GVArray *> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); - varrays[0]->get_to_uninitialized(0, r_value); + Vector<GVArray> varrays = evaluate_fields(scope, {field}, IndexRange(1), context); + varrays[0].get_to_uninitialized(0, r_value); } /** @@ -506,15 +511,21 @@ GField make_field_constant_if_possible(GField field) const CPPType &type = field.cpp_type(); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); evaluate_constant_field(field, buffer); - auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, buffer, true); + GField new_field = make_constant_field(type, buffer); type.destruct(buffer); + return new_field; +} + +GField make_constant_field(const CPPType &type, const void *value) +{ + auto constant_fn = std::make_unique<CustomMF_GenericConstant>(type, value, true); auto operation = std::make_shared<FieldOperation>(std::move(constant_fn)); - return GField{operation, 0}; + return GField{std::move(operation), 0}; } -const GVArray *FieldContext::get_varray_for_input(const FieldInput &field_input, - IndexMask mask, - ResourceScope &scope) const +GVArray FieldContext::get_varray_for_input(const FieldInput &field_input, + IndexMask mask, + ResourceScope &scope) const { /* By default ask the field input to create the varray. Another field context might overwrite * the context here. */ @@ -526,17 +537,15 @@ IndexFieldInput::IndexFieldInput() : FieldInput(CPPType::get<int>(), "Index") category_ = Category::Generated; } -GVArray *IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &scope) +GVArray IndexFieldInput::get_index_varray(IndexMask mask, ResourceScope &UNUSED(scope)) { auto index_func = [](int i) { return i; }; - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } -const GVArray *IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const +GVArray IndexFieldInput::get_varray_for_context(const fn::FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &scope) const { /* TODO: Investigate a similar method to IndexRange::as_span() */ return get_index_varray(mask, scope); @@ -631,27 +640,26 @@ static Vector<int64_t> indices_from_selection(const VArray<bool> &selection) return indices; } -int FieldEvaluator::add_with_destination(GField field, GVMutableArray &dst) +int FieldEvaluator::add_with_destination(GField field, GVMutableArray dst) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); - dst_varrays_.append(&dst); + dst_varrays_.append(dst); output_pointer_infos_.append({}); return field_index; } int FieldEvaluator::add_with_destination(GField field, GMutableSpan dst) { - GVMutableArray &varray = scope_.construct<GVMutableArray_For_GMutableSpan>(dst); - return this->add_with_destination(std::move(field), varray); + return this->add_with_destination(std::move(field), GVMutableArray::ForSpan(dst)); } -int FieldEvaluator::add(GField field, const GVArray **varray_ptr) +int FieldEvaluator::add(GField field, GVArray *varray_ptr) { const int field_index = fields_to_evaluate_.append_and_get_index(std::move(field)); dst_varrays_.append(nullptr); output_pointer_infos_.append(OutputPointerInfo{ varray_ptr, [](void *dst, const GVArray &varray, ResourceScope &UNUSED(scope)) { - *(const GVArray **)dst = &varray; + *(GVArray *)dst = varray; }}); return field_index; } @@ -676,7 +684,7 @@ void FieldEvaluator::evaluate() for (const int i : fields_to_evaluate_.index_range()) { OutputPointerInfo &info = output_pointer_infos_[i]; if (info.dst != nullptr) { - info.set(info.dst, *evaluated_varrays_[i], scope_); + info.set(info.dst, evaluated_varrays_[i], scope_); } } is_evaluated_ = true; @@ -684,17 +692,16 @@ void FieldEvaluator::evaluate() IndexMask FieldEvaluator::get_evaluated_as_mask(const int field_index) { - const GVArray &varray = this->get_evaluated(field_index); - GVArray_Typed<bool> typed_varray{varray}; + VArray<bool> varray = this->get_evaluated(field_index).typed<bool>(); - if (typed_varray->is_single()) { - if (typed_varray->get_internal_single()) { - return IndexRange(typed_varray.size()); + if (varray.is_single()) { + if (varray.get_internal_single()) { + return IndexRange(varray.size()); } return IndexRange(0); } - return scope_.add_value(indices_from_selection(*typed_varray)).as_span(); + return scope_.add_value(indices_from_selection(varray)).as_span(); } } // namespace blender::fn diff --git a/source/blender/functions/intern/generic_vector_array.cc b/source/blender/functions/intern/generic_vector_array.cc index ec95a283919..0d478007a5a 100644 --- a/source/blender/functions/intern/generic_vector_array.cc +++ b/source/blender/functions/intern/generic_vector_array.cc @@ -60,15 +60,14 @@ void GVectorArray::extend(const int64_t index, const GVArray &values) void GVectorArray::extend(const int64_t index, const GSpan values) { - GVArray_For_GSpan varray{values}; - this->extend(index, varray); + this->extend(index, GVArray::ForSpan(values)); } void GVectorArray::extend(IndexMask mask, const GVVectorArray &values) { for (const int i : mask) { GVArray_For_GVVectorArrayIndex array{values, i}; - this->extend(i, array); + this->extend(i, GVArray(&array)); } } diff --git a/source/blender/functions/intern/generic_virtual_array.cc b/source/blender/functions/intern/generic_virtual_array.cc index ea54f1e7c00..1fe1c2fc229 100644 --- a/source/blender/functions/intern/generic_virtual_array.cc +++ b/source/blender/functions/intern/generic_virtual_array.cc @@ -19,52 +19,10 @@ namespace blender::fn { /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_ShallowCopy +/** \name #GVArrayImpl * \{ */ -class GVArray_For_ShallowCopy : public GVArray { - private: - const GVArray &varray_; - - public: - GVArray_For_ShallowCopy(const GVArray &varray) - : GVArray(varray.type(), varray.size()), varray_(varray) - { - } - - private: - void get_impl(const int64_t index, void *r_value) const override - { - varray_.get(index, r_value); - } - - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override - { - varray_.get_to_uninitialized(index, r_value); - } - - void materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const override - { - varray_.materialize_to_uninitialized(mask, dst); - } -}; -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name #GVArray - * \{ */ - -void GVArray::materialize(void *dst) const -{ - this->materialize(IndexMask(size_), dst); -} - -void GVArray::materialize(const IndexMask mask, void *dst) const -{ - this->materialize_impl(mask, dst); -} - -void GVArray::materialize_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -72,18 +30,7 @@ void GVArray::materialize_impl(const IndexMask mask, void *dst) const } } -void GVArray::materialize_to_uninitialized(void *dst) const -{ - this->materialize_to_uninitialized(IndexMask(size_), dst); -} - -void GVArray::materialize_to_uninitialized(const IndexMask mask, void *dst) const -{ - BLI_assert(mask.min_array_size() <= size_); - this->materialize_to_uninitialized_impl(mask, dst); -} - -void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) const +void GVArrayImpl::materialize_to_uninitialized(const IndexMask mask, void *dst) const { for (const int64_t i : mask) { void *elem_dst = POINTER_OFFSET(dst, type_->size() * i); @@ -91,83 +38,75 @@ void GVArray::materialize_to_uninitialized_impl(const IndexMask mask, void *dst) } } -void GVArray::get_impl(const int64_t index, void *r_value) const +void GVArrayImpl::get(const int64_t index, void *r_value) const { type_->destruct(r_value); - this->get_to_uninitialized_impl(index, r_value); + this->get_to_uninitialized(index, r_value); } -bool GVArray::is_span_impl() const +bool GVArrayImpl::is_span() const { return false; } -GSpan GVArray::get_internal_span_impl() const +GSpan GVArrayImpl::get_internal_span() const { BLI_assert(false); return GSpan(*type_); } -bool GVArray::is_single_impl() const +bool GVArrayImpl::is_single() const { return false; } -void GVArray::get_internal_single_impl(void *UNUSED(r_value)) const +void GVArrayImpl::get_internal_single(void *UNUSED(r_value)) const { BLI_assert(false); } -const void *GVArray::try_get_internal_varray_impl() const +bool GVArrayImpl::try_assign_VArray(void *UNUSED(varray)) const { - return nullptr; + return false; } -/** - * Creates a new `std::unique_ptr<GVArray>` based on this `GVArray`. - * The lifetime of the returned virtual array must not be longer than the lifetime of this virtual - * array. - */ -GVArrayPtr GVArray::shallow_copy() const +bool GVArrayImpl::may_have_ownership() const { - if (this->is_span()) { - return std::make_unique<GVArray_For_GSpan>(this->get_internal_span()); - } - if (this->is_single()) { - BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); - this->get_internal_single(buffer); - std::unique_ptr new_varray = std::make_unique<GVArray_For_SingleValue>(*type_, size_, buffer); - type_->destruct(buffer); - return new_varray; - } - return std::make_unique<GVArray_For_ShallowCopy>(*this); + /* Use true as default to avoid accidentally creating subclasses that have this set to false but + * actually own data. Subclasses should set the to false instead. */ + return true; } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray +/** \name #GVMutableArrayImpl * \{ */ -void GVMutableArray::set_by_copy_impl(const int64_t index, const void *value) +GVMutableArrayImpl::GVMutableArrayImpl(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size) +{ +} + +void GVMutableArrayImpl::set_by_copy(const int64_t index, const void *value) { BUFFER_FOR_CPP_TYPE_VALUE(*type_, buffer); type_->copy_construct(value, buffer); - this->set_by_move_impl(index, buffer); + this->set_by_move(index, buffer); type_->destruct(buffer); } -void GVMutableArray::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl::set_by_relocate(const int64_t index, void *value) { - this->set_by_move_impl(index, value); + this->set_by_move(index, value); type_->destruct(value); } -void GVMutableArray::set_all_impl(const void *src) +void GVMutableArrayImpl::set_all(const void *src) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->copy_assign_n(src, span.data(), size_); + const GSpan span = this->get_internal_span(); + type_->copy_assign_n(src, const_cast<void *>(span.data()), size_); } else { for (int64_t i : IndexRange(size_)) { @@ -176,149 +115,224 @@ void GVMutableArray::set_all_impl(const void *src) } } -void *GVMutableArray::try_get_internal_mutable_varray_impl() -{ - return nullptr; -} - void GVMutableArray::fill(const void *value) { if (this->is_span()) { - const GMutableSpan span = this->get_internal_span(); - type_->fill_assign_n(value, span.data(), size_); + const GSpan span = this->get_internal_span(); + this->type().fill_assign_n(value, const_cast<void *>(span.data()), this->size()); } else { - for (int64_t i : IndexRange(size_)) { + for (int64_t i : IndexRange(this->size())) { this->set_by_copy(i, value); } } } +bool GVMutableArrayImpl::try_assign_VMutableArray(void *UNUSED(varray)) const +{ + return false; +} + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_GSpan +/** \name #GVArrayImpl_For_GSpan * \{ */ -void GVArray_For_GSpan::get_impl(const int64_t index, void *r_value) const +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const GSpan span) + : GVArrayImpl(span.type(), span.size()), data_(span.data()), element_size_(span.type().size()) +{ +} + +GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan(const CPPType &type, const int64_t size) + : GVArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVArrayImpl_For_GSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVArray_For_GSpan::get_to_uninitialized_impl(const int64_t index, void *r_value) const +void GVArrayImpl_For_GSpan::get_to_uninitialized(const int64_t index, void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -bool GVArray_For_GSpan::is_span_impl() const +bool GVArrayImpl_For_GSpan::is_span() const { return true; } -GSpan GVArray_For_GSpan::get_internal_span_impl() const +GSpan GVArrayImpl_For_GSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +/** See #VArrayImpl_For_Span_final. */ +class GVArrayImpl_For_GSpan_final final : public GVArrayImpl_For_GSpan { + public: + using GVArrayImpl_For_GSpan::GVArrayImpl_For_GSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVMutableArray_For_GMutableSpan +/** \name #GVMutableArrayImpl_For_GMutableSpan * \{ */ -void GVMutableArray_For_GMutableSpan::get_impl(const int64_t index, void *r_value) const +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const GMutableSpan span) + : GVMutableArrayImpl(span.type(), span.size()), + data_(span.data()), + element_size_(span.type().size()) +{ +} + +GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan(const CPPType &type, + const int64_t size) + : GVMutableArrayImpl(type, size), element_size_(type.size()) +{ +} + +void GVMutableArrayImpl_For_GMutableSpan::get(const int64_t index, void *r_value) const { type_->copy_assign(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::get_to_uninitialized_impl(const int64_t index, - void *r_value) const +void GVMutableArrayImpl_For_GMutableSpan::get_to_uninitialized(const int64_t index, + void *r_value) const { type_->copy_construct(POINTER_OFFSET(data_, element_size_ * index), r_value); } -void GVMutableArray_For_GMutableSpan::set_by_copy_impl(const int64_t index, const void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_copy(const int64_t index, const void *value) { type_->copy_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_move_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_move(const int64_t index, void *value) { type_->move_construct(value, POINTER_OFFSET(data_, element_size_ * index)); } -void GVMutableArray_For_GMutableSpan::set_by_relocate_impl(const int64_t index, void *value) +void GVMutableArrayImpl_For_GMutableSpan::set_by_relocate(const int64_t index, void *value) { type_->relocate_assign(value, POINTER_OFFSET(data_, element_size_ * index)); } -bool GVMutableArray_For_GMutableSpan::is_span_impl() const +bool GVMutableArrayImpl_For_GMutableSpan::is_span() const { return true; } -GSpan GVMutableArray_For_GMutableSpan::get_internal_span_impl() const +GSpan GVMutableArrayImpl_For_GMutableSpan::get_internal_span() const { return GSpan(*type_, data_, size_); } +class GVMutableArrayImpl_For_GMutableSpan_final final + : public GVMutableArrayImpl_For_GMutableSpan { + public: + using GVMutableArrayImpl_For_GMutableSpan::GVMutableArrayImpl_For_GMutableSpan; + + private: + bool may_have_ownership() const override + { + return false; + } +}; + /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValueRef +/** \name #GVArrayImpl_For_SingleValueRef * \{ */ -void GVArray_For_SingleValueRef::get_impl(const int64_t UNUSED(index), void *r_value) const -{ - type_->copy_assign(value_, r_value); -} +/* Generic virtual array where each element has the same value. The value is not owned. */ +class GVArrayImpl_For_SingleValueRef : public GVArrayImpl { + protected: + const void *value_ = nullptr; -void GVArray_For_SingleValueRef::get_to_uninitialized_impl(const int64_t UNUSED(index), - void *r_value) const -{ - type_->copy_construct(value_, r_value); -} + public: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl(type, size), value_(value) + { + } -bool GVArray_For_SingleValueRef::is_span_impl() const -{ - return size_ == 1; -} + protected: + GVArrayImpl_For_SingleValueRef(const CPPType &type, const int64_t size) : GVArrayImpl(type, size) + { + } -GSpan GVArray_For_SingleValueRef::get_internal_span_impl() const -{ - return GSpan{*type_, value_, 1}; -} + void get(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_assign(value_, r_value); + } + void get_to_uninitialized(const int64_t UNUSED(index), void *r_value) const override + { + type_->copy_construct(value_, r_value); + } -bool GVArray_For_SingleValueRef::is_single_impl() const -{ - return true; -} + bool is_span() const override + { + return size_ == 1; + } + GSpan get_internal_span() const override + { + return GSpan{*type_, value_, 1}; + } -void GVArray_For_SingleValueRef::get_internal_single_impl(void *r_value) const -{ - type_->copy_assign(value_, r_value); -} + bool is_single() const override + { + return true; + } + void get_internal_single(void *r_value) const override + { + type_->copy_assign(value_, r_value); + } +}; + +class GVArrayImpl_For_SingleValueRef_final final : public GVArrayImpl_For_SingleValueRef { + public: + using GVArrayImpl_For_SingleValueRef::GVArrayImpl_For_SingleValueRef; + + private: + bool may_have_ownership() const override + { + return false; + } +}; /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SingleValue +/** \name #GVArrayImpl_For_SingleValue * \{ */ -GVArray_For_SingleValue::GVArray_For_SingleValue(const CPPType &type, - const int64_t size, - const void *value) - : GVArray_For_SingleValueRef(type, size) -{ - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_construct(value, (void *)value_); -} +/* Same as GVArrayImpl_For_SingleValueRef, but the value is owned. */ +class GVArrayImpl_For_SingleValue : public GVArrayImpl_For_SingleValueRef, + NonCopyable, + NonMovable { + public: + GVArrayImpl_For_SingleValue(const CPPType &type, const int64_t size, const void *value) + : GVArrayImpl_For_SingleValueRef(type, size) + { + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_construct(value, (void *)value_); + } -GVArray_For_SingleValue::~GVArray_For_SingleValue() -{ - type_->destruct((void *)value_); - MEM_freeN((void *)value_); -} + ~GVArrayImpl_For_SingleValue() override + { + type_->destruct((void *)value_); + MEM_freeN((void *)value_); + } +}; /** \} */ @@ -326,7 +340,7 @@ GVArray_For_SingleValue::~GVArray_For_SingleValue() /** \name #GVArray_GSpan * \{ */ -GVArray_GSpan::GVArray_GSpan(const GVArray &varray) : GSpan(varray.type()), varray_(varray) +GVArray_GSpan::GVArray_GSpan(GVArray varray) : GSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -353,8 +367,8 @@ GVArray_GSpan::~GVArray_GSpan() /** \name #GVMutableArray_GSpan * \{ */ -GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray &varray, const bool copy_values_to_span) - : GMutableSpan(varray.type()), varray_(varray) +GVMutableArray_GSpan::GVMutableArray_GSpan(GVMutableArray varray, const bool copy_values_to_span) + : GMutableSpan(varray.type()), varray_(std::move(varray)) { size_ = varray_.size(); if (varray_.is_span()) { @@ -405,48 +419,314 @@ void GVMutableArray_GSpan::disable_not_applied_warning() /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_For_SlicedGVArray +/** \name #GVArrayImpl_For_SlicedGVArray * \{ */ -void GVArray_For_SlicedGVArray::get_impl(const int64_t index, void *r_value) const +class GVArrayImpl_For_SlicedGVArray : public GVArrayImpl { + protected: + GVArray varray_; + int64_t offset_; + + public: + GVArrayImpl_For_SlicedGVArray(GVArray varray, const IndexRange slice) + : GVArrayImpl(varray.type(), slice.size()), + varray_(std::move(varray)), + offset_(slice.start()) + { + BLI_assert(slice.one_after_last() <= varray_.size()); + } + + void get(const int64_t index, void *r_value) const override + { + varray_.get(index + offset_, r_value); + } + + void get_to_uninitialized(const int64_t index, void *r_value) const override + { + varray_.get_to_uninitialized(index + offset_, r_value); + } +}; + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVArrayCommon + * \{ */ + +GVArrayCommon::GVArrayCommon() = default; + +GVArrayCommon::GVArrayCommon(const GVArrayCommon &other) : storage_(other.storage_) +{ + impl_ = this->impl_from_storage(); +} + +GVArrayCommon::GVArrayCommon(GVArrayCommon &&other) noexcept : storage_(std::move(other.storage_)) +{ + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +GVArrayCommon::GVArrayCommon(const GVArrayImpl *impl) : impl_(impl) +{ + storage_ = impl_; +} + +GVArrayCommon::GVArrayCommon(std::shared_ptr<const GVArrayImpl> impl) : impl_(impl.get()) +{ + if (impl) { + storage_ = std::move(impl); + } +} + +GVArrayCommon::~GVArrayCommon() = default; + +void GVArrayCommon::materialize(void *dst) const +{ + this->materialize(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize(const IndexMask mask, void *dst) const +{ + impl_->materialize(mask, dst); +} + +void GVArrayCommon::materialize_to_uninitialized(void *dst) const +{ + this->materialize_to_uninitialized(IndexMask(impl_->size()), dst); +} + +void GVArrayCommon::materialize_to_uninitialized(const IndexMask mask, void *dst) const +{ + BLI_assert(mask.min_array_size() <= impl_->size()); + impl_->materialize_to_uninitialized(mask, dst); +} + +bool GVArrayCommon::may_have_ownership() const +{ + return impl_->may_have_ownership(); +} + +void GVArrayCommon::copy_from(const GVArrayCommon &other) +{ + if (this == &other) { + return; + } + storage_ = other.storage_; + impl_ = this->impl_from_storage(); +} + +void GVArrayCommon::move_from(GVArrayCommon &&other) noexcept +{ + if (this == &other) { + return; + } + storage_ = std::move(other.storage_); + impl_ = this->impl_from_storage(); + other.storage_.reset(); + other.impl_ = nullptr; +} + +/* Returns true when the virtual array is stored as a span internally. */ +bool GVArrayCommon::is_span() const +{ + if (this->is_empty()) { + return true; + } + return impl_->is_span(); +} + +/* Returns the internally used span of the virtual array. This invokes undefined behavior is the + * virtual array is not stored as a span internally. */ +GSpan GVArrayCommon::get_internal_span() const { - varray_.get(index + offset_, r_value); + BLI_assert(this->is_span()); + if (this->is_empty()) { + return GSpan(impl_->type()); + } + return impl_->get_internal_span(); } -void GVArray_For_SlicedGVArray::get_to_uninitialized_impl(const int64_t index, void *r_value) const +/* Returns true when the virtual array returns the same value for every index. */ +bool GVArrayCommon::is_single() const { - varray_.get_to_uninitialized(index + offset_, r_value); + if (impl_->size() == 1) { + return true; + } + return impl_->is_single(); +} + +/* Copies the value that is used for every element into `r_value`, which is expected to point to + * initialized memory. This invokes undefined behavior if the virtual array would not return the + * same value for every index. */ +void GVArrayCommon::get_internal_single(void *r_value) const +{ + BLI_assert(this->is_single()); + if (impl_->size() == 1) { + impl_->get(0, r_value); + return; + } + impl_->get_internal_single(r_value); +} + +/* Same as `get_internal_single`, but `r_value` points to initialized memory. */ +void GVArrayCommon::get_internal_single_to_uninitialized(void *r_value) const +{ + impl_->type().default_construct(r_value); + this->get_internal_single(r_value); +} + +const GVArrayImpl *GVArrayCommon::impl_from_storage() const +{ + return storage_.extra_info().get_varray(storage_.get()); +} + +IndexRange GVArrayCommon::index_range() const +{ + return IndexRange(this->size()); } /** \} */ /* -------------------------------------------------------------------- */ -/** \name #GVArray_Slice +/** \name #GVArray * \{ */ -GVArray_Slice::GVArray_Slice(const GVArray &varray, const IndexRange slice) +GVArray::GVArray(const GVArray &other) = default; + +GVArray::GVArray(GVArray &&other) noexcept = default; + +GVArray::GVArray(const GVArrayImpl *impl) : GVArrayCommon(impl) { - if (varray.is_span()) { - /* Create a new virtual for the sliced span. */ - const GSpan span = varray.get_internal_span(); - const GSpan sliced_span = span.slice(slice.start(), slice.size()); - varray_span_.emplace(sliced_span); - varray_ = &*varray_span_; - } - else if (varray.is_single()) { - /* Can just use the existing virtual array, because it's the same value for the indices in the - * slice anyway. */ - varray_ = &varray; - } - else { - /* Generic version when none of the above method works. - * We don't necessarily want to materialize the input varray because there might be - * large distances between the required indices. Then we would materialize many elements that - * are not accessed later on. - */ - varray_any_.emplace(varray, slice); - varray_ = &*varray_any_; +} + +GVArray::GVArray(std::shared_ptr<const GVArrayImpl> impl) : GVArrayCommon(std::move(impl)) +{ +} + +GVArray GVArray::ForSingle(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValue>(type, size, value); +} + +GVArray GVArray::ForSingleRef(const CPPType &type, const int64_t size, const void *value) +{ + return GVArray::For<GVArrayImpl_For_SingleValueRef_final>(type, size, value); +} + +GVArray GVArray::ForSingleDefault(const CPPType &type, const int64_t size) +{ + return GVArray::ForSingleRef(type, size, type.default_value()); +} + +GVArray GVArray::ForSpan(GSpan span) +{ + return GVArray::For<GVArrayImpl_For_GSpan_final>(span); +} + +class GVArrayImpl_For_GArray : public GVArrayImpl_For_GSpan { + protected: + GArray<> array_; + + public: + GVArrayImpl_For_GArray(GArray<> array) + : GVArrayImpl_For_GSpan(array.as_span()), array_(std::move(array)) + { } +}; + +GVArray GVArray::ForGArray(GArray<> array) +{ + return GVArray::For<GVArrayImpl_For_GArray>(array); +} + +GVArray GVArray::ForEmpty(const CPPType &type) +{ + return GVArray::ForSpan(GSpan(type)); +} + +GVArray GVArray::slice(IndexRange slice) const +{ + return GVArray::For<GVArrayImpl_For_SlicedGVArray>(*this, slice); +} + +GVArray &GVArray::operator=(const GVArray &other) +{ + this->copy_from(other); + return *this; +} + +GVArray &GVArray::operator=(GVArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name #GVMutableArray + * \{ */ + +GVMutableArray::GVMutableArray(const GVMutableArray &other) = default; +GVMutableArray::GVMutableArray(GVMutableArray &&other) noexcept = default; + +GVMutableArray::GVMutableArray(GVMutableArrayImpl *impl) : GVArrayCommon(impl) +{ +} + +GVMutableArray::GVMutableArray(std::shared_ptr<GVMutableArrayImpl> impl) + : GVArrayCommon(std::move(impl)) +{ +} + +GVMutableArray GVMutableArray::ForSpan(GMutableSpan span) +{ + return GVMutableArray::For<GVMutableArrayImpl_For_GMutableSpan_final>(span); +} + +GVMutableArray::operator GVArray() const & +{ + GVArray varray; + varray.copy_from(*this); + return varray; +} + +GVMutableArray::operator GVArray() &&noexcept +{ + GVArray varray; + varray.move_from(std::move(*this)); + return varray; +} + +GVMutableArray &GVMutableArray::operator=(const GVMutableArray &other) +{ + this->copy_from(other); + return *this; +} + +GVMutableArray &GVMutableArray::operator=(GVMutableArray &&other) noexcept +{ + this->move_from(std::move(other)); + return *this; +} + +GVMutableArrayImpl *GVMutableArray::get_implementation() const +{ + return this->get_impl(); +} + +/* Copy the values from the source buffer to all elements in the virtual array. */ +void GVMutableArray::set_all(const void *src) +{ + this->get_impl()->set_all(src); +} + +GMutableSpan GVMutableArray::get_internal_span() const +{ + BLI_assert(this->is_span()); + const GSpan span = impl_->get_internal_span(); + return GMutableSpan(span.type(), const_cast<void *>(span.data()), span.size()); } /** \} */ diff --git a/source/blender/functions/intern/generic_virtual_vector_array.cc b/source/blender/functions/intern/generic_virtual_vector_array.cc index 6b90ce993ae..e3c0d3109fa 100644 --- a/source/blender/functions/intern/generic_virtual_vector_array.cc +++ b/source/blender/functions/intern/generic_virtual_vector_array.cc @@ -18,13 +18,13 @@ namespace blender::fn { -void GVArray_For_GVVectorArrayIndex::get_impl(const int64_t index_in_vector, void *r_value) const +void GVArray_For_GVVectorArrayIndex::get(const int64_t index_in_vector, void *r_value) const { vector_array_.get_vector_element(index_, index_in_vector, r_value); } -void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t index_in_vector, - void *r_value) const +void GVArray_For_GVVectorArrayIndex::get_to_uninitialized(const int64_t index_in_vector, + void *r_value) const { type_->default_construct(r_value); vector_array_.get_vector_element(index_, index_in_vector, r_value); @@ -32,14 +32,14 @@ void GVArray_For_GVVectorArrayIndex::get_to_uninitialized_impl(const int64_t ind int64_t GVVectorArray_For_SingleGVArray::get_vector_size_impl(const int64_t UNUSED(index)) const { - return array_.size(); + return varray_.size(); } void GVVectorArray_For_SingleGVArray::get_vector_element_impl(const int64_t UNUSED(index), const int64_t index_in_vector, void *r_value) const { - array_.get(index_in_vector, r_value); + varray_.get(index_in_vector, r_value); } bool GVVectorArray_For_SingleGVArray::is_single_vector_impl() const diff --git a/source/blender/functions/intern/multi_function.cc b/source/blender/functions/intern/multi_function.cc index bb657f321ec..ee2c69068db 100644 --- a/source/blender/functions/intern/multi_function.cc +++ b/source/blender/functions/intern/multi_function.cc @@ -18,28 +18,9 @@ namespace blender::fn { -class DummyMultiFunction : public MultiFunction { - public: - DummyMultiFunction() - { - static MFSignature signature = create_signature(); - this->set_signature(&signature); - } - - static MFSignature create_signature() - { - MFSignatureBuilder signature{"Dummy"}; - return signature.build(); - } - - void call(IndexMask UNUSED(mask), - MFParams UNUSED(params), - MFContext UNUSED(context)) const override - { - } -}; - -static DummyMultiFunction dummy_multi_function_; -const MultiFunction &dummy_multi_function = dummy_multi_function_; +std::string MultiFunction::debug_name() const +{ + return signature_ref_->function_name; +} } // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_builder.cc b/source/blender/functions/intern/multi_function_builder.cc index f891f162820..24f9bbe0179 100644 --- a/source/blender/functions/intern/multi_function_builder.cc +++ b/source/blender/functions/intern/multi_function_builder.cc @@ -32,10 +32,8 @@ CustomMF_GenericConstant::CustomMF_GenericConstant(const CPPType &type, } value_ = value; - MFSignatureBuilder signature{"Constant " + type.name()}; - std::stringstream ss; - type.print_or_default(value, ss, type.name()); - signature.single_output(ss.str(), type); + MFSignatureBuilder signature{"Constant"}; + signature.single_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -73,28 +71,11 @@ bool CustomMF_GenericConstant::equals(const MultiFunction &other) const return type_.is_equal(value_, _other->value_); } -static std::string gspan_to_string(GSpan array) -{ - const CPPType &type = array.type(); - std::stringstream ss; - ss << "["; - const int64_t max_amount = 5; - for (int64_t i : IndexRange(std::min(max_amount, array.size()))) { - type.print_or_default(array[i], ss, type.name()); - ss << ", "; - } - if (max_amount < array.size()) { - ss << "..."; - } - ss << "]"; - return ss.str(); -} - CustomMF_GenericConstantArray::CustomMF_GenericConstantArray(GSpan array) : array_(array) { const CPPType &type = array.type(); - MFSignatureBuilder signature{"Constant " + type.name() + " Vector"}; - signature.vector_output(gspan_to_string(array), type); + MFSignatureBuilder signature{"Constant Vector"}; + signature.vector_output("Value", type); signature_ = signature.build(); this->set_signature(&signature_); } @@ -109,12 +90,11 @@ void CustomMF_GenericConstantArray::call(IndexMask mask, } } -CustomMF_DefaultOutput::CustomMF_DefaultOutput(StringRef name, - Span<MFDataType> input_types, +CustomMF_DefaultOutput::CustomMF_DefaultOutput(Span<MFDataType> input_types, Span<MFDataType> output_types) : output_amount_(output_types.size()) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Default Output"}; for (MFDataType data_type : input_types) { signature.input("Input", data_type); } @@ -140,9 +120,9 @@ void CustomMF_DefaultOutput::call(IndexMask mask, MFParams params, MFContext UNU } } -CustomMF_GenericCopy::CustomMF_GenericCopy(StringRef name, MFDataType data_type) +CustomMF_GenericCopy::CustomMF_GenericCopy(MFDataType data_type) { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Copy"}; signature.input("Input", data_type); signature.output("Output", data_type); signature_ = signature.build(); diff --git a/source/blender/functions/intern/multi_function_parallel.cc b/source/blender/functions/intern/multi_function_parallel.cc index 5a8c621f0b3..eefe647644d 100644 --- a/source/blender/functions/intern/multi_function_parallel.cc +++ b/source/blender/functions/intern/multi_function_parallel.cc @@ -54,7 +54,6 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext const IndexRange input_slice_range{input_slice_start, input_slice_size}; MFParamsBuilder sub_params{fn_, sub_mask.min_array_size()}; - ResourceScope &scope = sub_params.resource_scope(); /* All parameters are sliced so that the wrapped multi-function does not have to take care of * the index offset. */ @@ -63,8 +62,7 @@ void ParallelMultiFunction::call(IndexMask full_mask, MFParams params, MFContext switch (param_type.category()) { case MFParamType::SingleInput: { const GVArray &varray = params.readonly_single_input(param_index); - const GVArray &sliced_varray = scope.construct<GVArray_Slice>(varray, input_slice_range); - sub_params.add_readonly_single_input(sliced_varray); + sub_params.add_readonly_single_input(varray.slice(input_slice_range)); break; } case MFParamType::SingleMutable: { diff --git a/source/blender/functions/intern/multi_function_procedure.cc b/source/blender/functions/intern/multi_function_procedure.cc index 986c5dff0c4..804beb7d66f 100644 --- a/source/blender/functions/intern/multi_function_procedure.cc +++ b/source/blender/functions/intern/multi_function_procedure.cc @@ -782,7 +782,7 @@ class MFProcedureDotExport { void instruction_to_string(const MFCallInstruction &instruction, std::stringstream &ss) { const MultiFunction &fn = instruction.fn(); - this->instruction_name_format(fn.name() + ": ", ss); + this->instruction_name_format(fn.debug_name() + ": ", ss); for (const int param_index : fn.param_indices()) { const MFParamType param_type = fn.param_type(param_index); const MFVariable *variable = instruction.params()[param_index]; diff --git a/source/blender/functions/intern/multi_function_procedure_executor.cc b/source/blender/functions/intern/multi_function_procedure_executor.cc index 6d2d121bafd..06c97fd1173 100644 --- a/source/blender/functions/intern/multi_function_procedure_executor.cc +++ b/source/blender/functions/intern/multi_function_procedure_executor.cc @@ -20,13 +20,12 @@ namespace blender::fn { -MFProcedureExecutor::MFProcedureExecutor(std::string name, const MFProcedure &procedure) - : procedure_(procedure) +MFProcedureExecutor::MFProcedureExecutor(const MFProcedure &procedure) : procedure_(procedure) { - MFSignatureBuilder signature(std::move(name)); + MFSignatureBuilder signature("Procedure Executor"); for (const ConstMFParameter ¶m : procedure.params()) { - signature.add(param.variable->name(), MFParamType(param.type, param.variable->data_type())); + signature.add("Parameter", MFParamType(param.type, param.variable->data_type())); } signature_ = signature.build(); @@ -66,6 +65,7 @@ struct VariableValue_GVArray : public VariableValue { VariableValue_GVArray(const GVArray &data) : VariableValue(static_type), data(data) { + BLI_assert(data); } }; @@ -756,7 +756,7 @@ class VariableState : NonCopyable, NonMovable { switch (value_->type) { case ValueType::GVArray: { - const GVArray_Typed<bool> varray{this->value_as<VariableValue_GVArray>()->data}; + const VArray<bool> varray = this->value_as<VariableValue_GVArray>()->data.typed<bool>(); for (const int i : mask) { r_indices[varray[i]].append(i); } diff --git a/source/blender/functions/tests/FN_field_test.cc b/source/blender/functions/tests/FN_field_test.cc index 041cdbd0f00..4614f9eee58 100644 --- a/source/blender/functions/tests/FN_field_test.cc +++ b/source/blender/functions/tests/FN_field_test.cc @@ -34,14 +34,12 @@ class IndexFieldInput final : public FieldInput { { } - const GVArray *get_varray_for_context(const FieldContext &UNUSED(context), - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const FieldContext &UNUSED(context), + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { auto index_func = [](int i) { return i; }; - return &scope.construct< - GVArray_For_EmbeddedVArray<int, VArray_For_Func<int, decltype(index_func)>>>( - mask.min_array_size(), mask.min_array_size(), index_func); + return VArray<int>::ForFunc(mask.min_array_size(), index_func); } }; @@ -162,9 +160,9 @@ class TwoOutputFunction : public MultiFunction { MFSignature signature_; public: - TwoOutputFunction(StringRef name) + TwoOutputFunction() { - MFSignatureBuilder signature{name}; + MFSignatureBuilder signature{"Two Outputs"}; signature.single_input<int>("In1"); signature.single_input<int>("In2"); signature.single_output<int>("Add"); @@ -192,8 +190,8 @@ TEST(field, FunctionTwoOutputs) GField index_field_1{std::make_shared<IndexFieldInput>()}; GField index_field_2{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field_1, index_field_2})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field_1, index_field_2})); GField result_field_1{fn, 0}; GField result_field_2{fn, 1}; @@ -223,8 +221,8 @@ TEST(field, TwoFunctionsTwoOutputs) { GField index_field{std::make_shared<IndexFieldInput>()}; - std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>(FieldOperation( - std::make_unique<TwoOutputFunction>("SI_SI_SO_SO"), {index_field, index_field})); + std::shared_ptr<FieldOperation> fn = std::make_shared<FieldOperation>( + FieldOperation(std::make_unique<TwoOutputFunction>(), {index_field, index_field})); Array<int64_t> mask_indices = {2, 4, 6, 8}; IndexMask mask = mask_indices.as_span(); @@ -240,20 +238,20 @@ TEST(field, TwoFunctionsTwoOutputs) FieldContext field_context; FieldEvaluator field_evaluator{field_context, &mask}; - const VArray<int> *result_1 = nullptr; - const VArray<int> *result_2 = nullptr; + VArray<int> result_1; + VArray<int> result_2; field_evaluator.add(result_field_1, &result_1); field_evaluator.add(result_field_2, &result_2); field_evaluator.evaluate(); - EXPECT_EQ(result_1->get(2), 4); - EXPECT_EQ(result_1->get(4), 8); - EXPECT_EQ(result_1->get(6), 12); - EXPECT_EQ(result_1->get(8), 16); - EXPECT_EQ(result_2->get(2), 24); - EXPECT_EQ(result_2->get(4), 28); - EXPECT_EQ(result_2->get(6), 32); - EXPECT_EQ(result_2->get(8), 36); + EXPECT_EQ(result_1.get(2), 4); + EXPECT_EQ(result_1.get(4), 8); + EXPECT_EQ(result_1.get(6), 12); + EXPECT_EQ(result_1.get(8), 16); + EXPECT_EQ(result_2.get(2), 24); + EXPECT_EQ(result_2.get(4), 28); + EXPECT_EQ(result_2.get(6), 32); + EXPECT_EQ(result_2.get(8), 36); } TEST(field, SameFieldTwice) @@ -264,16 +262,16 @@ TEST(field, SameFieldTwice) FieldContext field_context; IndexMask mask{IndexRange(2)}; ResourceScope scope; - Vector<const GVArray *> results = evaluate_fields( + Vector<GVArray> results = evaluate_fields( scope, {constant_field, constant_field}, mask, field_context); - GVArray_Typed<int> varray1{*results[0]}; - GVArray_Typed<int> varray2{*results[1]}; + VArray<int> varray1 = results[0].typed<int>(); + VArray<int> varray2 = results[1].typed<int>(); - EXPECT_EQ(varray1->get(0), 10); - EXPECT_EQ(varray1->get(1), 10); - EXPECT_EQ(varray2->get(0), 10); - EXPECT_EQ(varray2->get(1), 10); + EXPECT_EQ(varray1.get(0), 10); + EXPECT_EQ(varray1.get(1), 10); + EXPECT_EQ(varray2.get(0), 10); + EXPECT_EQ(varray2.get(1), 10); } TEST(field, IgnoredOutput) @@ -283,12 +281,12 @@ TEST(field, IgnoredOutput) FieldContext field_context; FieldEvaluator field_evaluator{field_context, 10}; - const VArray<int> *results = nullptr; + VArray<int> results; field_evaluator.add(field, &results); field_evaluator.evaluate(); - EXPECT_EQ(results->get(0), 5); - EXPECT_EQ(results->get(3), 5); + EXPECT_EQ(results.get(0), 5); + EXPECT_EQ(results.get(3), 5); } } // namespace blender::fn::tests diff --git a/source/blender/functions/tests/FN_multi_function_procedure_test.cc b/source/blender/functions/tests/FN_multi_function_procedure_test.cc index 0b4b88fba3d..e3de23550c5 100644 --- a/source/blender/functions/tests/FN_multi_function_procedure_test.cc +++ b/source/blender/functions/tests/FN_multi_function_procedure_test.cc @@ -9,6 +9,43 @@ namespace blender::fn::tests { +TEST(multi_function_procedure, ConstantOutput) +{ + /** + * procedure(int *var2) { + * var1 = 5; + * var2 = var1 + var1; + * } + */ + + CustomMF_Constant<int> constant_fn{5}; + CustomMF_SI_SI_SO<int, int, int> add_fn{"Add", [](int a, int b) { return a + b; }}; + + MFProcedure procedure; + MFProcedureBuilder builder{procedure}; + + auto [var1] = builder.add_call<1>(constant_fn); + auto [var2] = builder.add_call<1>(add_fn, {var1, var1}); + builder.add_destruct(*var1); + builder.add_return(); + builder.add_output_parameter(*var2); + + EXPECT_TRUE(procedure.validate()); + + MFProcedureExecutor executor{procedure}; + + MFParamsBuilder params{executor, 2}; + MFContextBuilder context; + + Array<int> output_array(2); + params.add_uninitialized_single_output(output_array.as_mutable_span()); + + executor.call(IndexRange(2), params, context); + + EXPECT_EQ(output_array[0], 10); + EXPECT_EQ(output_array[1], 10); +} + TEST(multi_function_procedure, SimpleTest) { /** @@ -36,7 +73,7 @@ TEST(multi_function_procedure, SimpleTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor executor{"My Procedure", procedure}; + MFProcedureExecutor executor{procedure}; MFParamsBuilder params{executor, 3}; MFContextBuilder context; @@ -88,7 +125,7 @@ TEST(multi_function_procedure, BranchTest) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Condition Test", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params(procedure_fn, 5); Array<int> values_a = {1, 5, 3, 6, 2}; @@ -130,7 +167,7 @@ TEST(multi_function_procedure, EvaluateOne) builder.add_return(); builder.add_output_parameter(*var2); - MFProcedureExecutor procedure_fn{"Evaluate One", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> values_out = {1, 2, 3, 4, 5}; @@ -202,7 +239,7 @@ TEST(multi_function_procedure, SimpleLoop) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Simple Loop", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> counts = {4, 3, 7, 6, 4}; @@ -258,7 +295,7 @@ TEST(multi_function_procedure, Vectors) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Vectors", procedure}; + MFProcedureExecutor procedure_fn{procedure}; MFParamsBuilder params{procedure_fn, 5}; Array<int> v1 = {5, 2, 3}; @@ -322,7 +359,7 @@ TEST(multi_function_procedure, BufferReuse) EXPECT_TRUE(procedure.validate()); - MFProcedureExecutor procedure_fn{"Buffer Reuse", procedure}; + MFProcedureExecutor procedure_fn{procedure}; Array<int> inputs = {4, 1, 6, 2, 3}; Array<int> results(5, -1); diff --git a/source/blender/functions/tests/FN_multi_function_test.cc b/source/blender/functions/tests/FN_multi_function_test.cc index d99993b35ac..20ca00cf598 100644 --- a/source/blender/functions/tests/FN_multi_function_test.cc +++ b/source/blender/functions/tests/FN_multi_function_test.cc @@ -264,7 +264,6 @@ TEST(multi_function, CustomMF_GenericConstant) { int value = 42; CustomMF_GenericConstant fn{CPPType::get<int32_t>(), (const void *)&value, false}; - EXPECT_EQ(fn.param_name(0), "42"); Array<int> outputs(4, 0); @@ -285,7 +284,6 @@ TEST(multi_function, CustomMF_GenericConstantArray) { std::array<int, 4> values = {3, 4, 5, 6}; CustomMF_GenericConstantArray fn{GSpan(Span(values))}; - EXPECT_EQ(fn.param_name(0), "[3, 4, 5, 6, ]"); GVectorArray vector_array{CPPType::get<int32_t>(), 4}; GVectorArray_TypedMutableRef<int> vector_array_ref{vector_array}; diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc index 24f0b6308ba..7aaaec9f0c5 100644 --- a/source/blender/geometry/intern/mesh_to_curve_convert.cc +++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc @@ -50,23 +50,23 @@ static void copy_attributes_to_points(CurveEval &curve, /* Copy builtin control point attributes. */ if (source_attribute_ids.contains("tilt")) { - const fn::GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> tilt_attribute = mesh_component.attribute_get_for_read<float>( "tilt", ATTR_DOMAIN_POINT, 0.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); + tilt_attribute, point_to_vert_maps[i], splines[i]->tilts()); } }); source_attribute_ids.remove_contained("tilt"); } if (source_attribute_ids.contains("radius")) { - const fn::GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>( + const VArray<float> radius_attribute = mesh_component.attribute_get_for_read<float>( "radius", ATTR_DOMAIN_POINT, 1.0f); threading::parallel_for(splines.index_range(), 256, [&](IndexRange range) { for (const int i : range) { copy_attribute_to_points<float>( - *radius_attribute, point_to_vert_maps[i], splines[i]->radii()); + radius_attribute, point_to_vert_maps[i], splines[i]->radii()); } }); source_attribute_ids.remove_contained("radius"); @@ -82,7 +82,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const fn::GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read( + const fn::GVArray mesh_attribute = mesh_component.attribute_try_get_for_read( attribute_id, ATTR_DOMAIN_POINT); /* Some attributes might not exist if they were builtin attribute on domains that don't * have any elements, i.e. a face attribute on the output of the line primitive node. */ @@ -90,7 +90,7 @@ static void copy_attributes_to_points(CurveEval &curve, continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute.type()); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { @@ -101,10 +101,10 @@ static void copy_attributes_to_points(CurveEval &curve, BLI_assert(spline_attribute); /* Copy attribute based on the map for this spline. */ - attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) { + attribute_math::convert_to_static_type(mesh_attribute.type(), [&](auto dummy) { using T = decltype(dummy); copy_attribute_to_points<T>( - mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); + mesh_attribute.typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>()); }); } }); diff --git a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c index 88d717eb032..3773af70498 100644 --- a/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c +++ b/source/blender/gpencil_modifiers/intern/lineart/lineart_cpu.c @@ -579,9 +579,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] c2 = ratiod(v0[1], v1[1], v[1]); return (c2 >= -DBL_TRIANGLE_LIM && c2 <= 1 + DBL_TRIANGLE_LIM); } - else { - return false; - } + return false; } if (!LRT_DOUBLE_CLOSE_ENOUGH(v1[1], v0[1])) { @@ -592,9 +590,7 @@ static int lineart_point_on_line_segment(double v[2], double v0[2], double v1[2] c1 = ratiod(v0[0], v1[0], v[0]); return (c1 >= -DBL_TRIANGLE_LIM && c1 <= 1 + DBL_TRIANGLE_LIM); } - else { - return false; - } + return false; } if (LRT_DOUBLE_CLOSE_ENOUGH(c1, c2) && c1 >= 0 && c1 <= 1) { diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index b92b341fb73..4868096e594 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -37,6 +37,7 @@ set(INC ../imbuf ../makesdna ../makesrna + ../windowmanager ../editors/include diff --git a/source/blender/gpu/GPU_immediate_util.h b/source/blender/gpu/GPU_immediate_util.h index 0d3d39839b2..047c3d3da00 100644 --- a/source/blender/gpu/GPU_immediate_util.h +++ b/source/blender/gpu/GPU_immediate_util.h @@ -92,6 +92,7 @@ void imm_draw_cylinder_wire_3d( void imm_draw_cylinder_fill_3d( uint pos, float base, float top, float height, int slices, int stacks); +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos); #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/intern/gpu_immediate_util.c b/source/blender/gpu/intern/gpu_immediate_util.c index 032974db8d1..df18b89bd67 100644 --- a/source/blender/gpu/intern/gpu_immediate_util.c +++ b/source/blender/gpu/intern/gpu_immediate_util.c @@ -602,3 +602,55 @@ void imm_draw_cylinder_fill_3d( } immEnd(); } + +/* Circle Drawing - Tables for Optimized Drawing Speed */ +#define CIRCLE_RESOL 32 + +static void circball_array_fill(const float verts[CIRCLE_RESOL][3], + const float cent[3], + float rad, + const float tmat[4][4]) +{ + /* 32 values of sin function (still same result!) */ + const float sinval[CIRCLE_RESOL] = { + 0.00000000, 0.20129852, 0.39435585, 0.57126821, 0.72479278, 0.84864425, 0.93775213, + 0.98846832, 0.99871650, 0.96807711, 0.89780453, 0.79077573, 0.65137248, 0.48530196, + 0.29936312, 0.10116832, -0.10116832, -0.29936312, -0.48530196, -0.65137248, -0.79077573, + -0.89780453, -0.96807711, -0.99871650, -0.98846832, -0.93775213, -0.84864425, -0.72479278, + -0.57126821, -0.39435585, -0.20129852, 0.00000000, + }; + + /* 32 values of cos function (still same result!) */ + const float cosval[CIRCLE_RESOL] = { + 1.00000000, 0.97952994, 0.91895781, 0.82076344, 0.68896691, 0.52896401, 0.34730525, + 0.15142777, -0.05064916, -0.25065253, -0.44039415, -0.61210598, -0.75875812, -0.87434661, + -0.95413925, -0.99486932, -0.99486932, -0.95413925, -0.87434661, -0.75875812, -0.61210598, + -0.44039415, -0.25065253, -0.05064916, 0.15142777, 0.34730525, 0.52896401, 0.68896691, + 0.82076344, 0.91895781, 0.97952994, 1.00000000, + }; + + float vx[3], vy[3]; + float *viter = (float *)verts; + + mul_v3_v3fl(vx, tmat[0], rad); + mul_v3_v3fl(vy, tmat[1], rad); + + for (uint a = 0; a < CIRCLE_RESOL; a++, viter += 3) { + viter[0] = cent[0] + sinval[a] * vx[0] + cosval[a] * vy[0]; + viter[1] = cent[1] + sinval[a] * vx[1] + cosval[a] * vy[1]; + viter[2] = cent[2] + sinval[a] * vx[2] + cosval[a] * vy[2]; + } +} + +void imm_drawcircball(const float cent[3], float rad, const float tmat[4][4], uint pos) +{ + float verts[CIRCLE_RESOL][3]; + + circball_array_fill(verts, cent, rad, tmat); + + immBegin(GPU_PRIM_LINE_LOOP, CIRCLE_RESOL); + for (int i = 0; i < CIRCLE_RESOL; i++) { + immVertex3fv(pos, verts[i]); + } + immEnd(); +} diff --git a/source/blender/gpu/tests/gpu_testing.cc b/source/blender/gpu/tests/gpu_testing.cc index ac42c5875c8..7fd473069c2 100644 --- a/source/blender/gpu/tests/gpu_testing.cc +++ b/source/blender/gpu/tests/gpu_testing.cc @@ -18,6 +18,7 @@ void GPUTest::SetUp() CLG_init(); ghost_system = GHOST_CreateSystem(); ghost_context = GHOST_CreateOpenGLContext(ghost_system, glSettings); + GHOST_ActivateOpenGLContext(ghost_context); context = GPU_context_create(nullptr); GPU_init(); } diff --git a/source/blender/imbuf/intern/anim_movie.c b/source/blender/imbuf/intern/anim_movie.c index 87f2fd124c0..1d81653c7cd 100644 --- a/source/blender/imbuf/intern/anim_movie.c +++ b/source/blender/imbuf/intern/anim_movie.c @@ -58,6 +58,8 @@ #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "DNA_scene_types.h" + #include "MEM_guardedalloc.h" #ifdef WITH_AVI @@ -1443,7 +1445,15 @@ static ImBuf *ffmpeg_fetchibuf(struct anim *anim, int position, IMB_Timecode_Typ * * The issue was reported to FFmpeg under ticket #8747 in the FFmpeg tracker * and is fixed in the newer versions than 4.3.1. */ - anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, 32, 0); + + const AVPixFmtDescriptor *pix_fmt_descriptor = av_pix_fmt_desc_get(anim->pCodecCtx->pix_fmt); + + int planes = R_IMF_PLANES_RGBA; + if ((pix_fmt_descriptor->flags & AV_PIX_FMT_FLAG_ALPHA) == 0) { + planes = R_IMF_PLANES_RGB; + } + + anim->cur_frame_final = IMB_allocImBuf(anim->x, anim->y, planes, 0); anim->cur_frame_final->rect = MEM_mallocN_aligned( (size_t)4 * anim->x * anim->y, 32, "ffmpeg ibuf"); anim->cur_frame_final->mall |= IB_rect; diff --git a/source/blender/imbuf/intern/indexer.c b/source/blender/imbuf/intern/indexer.c index bbb0f3b5b22..6cd87e29c9d 100644 --- a/source/blender/imbuf/intern/indexer.c +++ b/source/blender/imbuf/intern/indexer.c @@ -183,13 +183,13 @@ struct anim_index *IMB_indexer_open(const char *name) header[12] = 0; if (memcmp(header, binary_header_str, 8) != 0) { - fprintf(stderr, "Error reading %s: Binary file type string missmatch\n", name); + fprintf(stderr, "Error reading %s: Binary file type string mismatch\n", name); fclose(fp); return NULL; } if (atoi(header + 9) != INDEX_FILE_VERSION) { - fprintf(stderr, "Error reading %s: File version missmatch\n", name); + fprintf(stderr, "Error reading %s: File version mismatch\n", name); fclose(fp); return NULL; } @@ -222,7 +222,7 @@ struct anim_index *IMB_indexer_open(const char *name) } if (UNLIKELY(items_read != idx->num_entries * 5)) { - fprintf(stderr, "Error: Element data size missmatch in: %s\n", name); + fprintf(stderr, "Error: Element data size mismatch in: %s\n", name); MEM_freeN(idx->entries); MEM_freeN(idx); fclose(fp); diff --git a/source/blender/imbuf/intern/moviecache.c b/source/blender/imbuf/intern/moviecache.c index 4f316150e10..773a3486233 100644 --- a/source/blender/imbuf/intern/moviecache.c +++ b/source/blender/imbuf/intern/moviecache.c @@ -122,7 +122,12 @@ static void moviecache_valfree(void *val) PRINT("%s: cache '%s' free item %p buffer %p\n", __func__, cache->name, item, item->ibuf); - MEM_CacheLimiter_unmanage(item->c_handle); + if (item->c_handle) { + BLI_mutex_lock(&limitor_lock); + MEM_CacheLimiter_unmanage(item->c_handle); + BLI_mutex_unlock(&limitor_lock); + } + if (item->ibuf) { IMB_freeImBuf(item->ibuf); } @@ -263,6 +268,7 @@ void IMB_moviecache_destruct(void) { if (limitor) { delete_MEM_CacheLimiter(limitor); + limitor = NULL; } } diff --git a/source/blender/io/alembic/exporter/abc_writer_mesh.cc b/source/blender/io/alembic/exporter/abc_writer_mesh.cc index 8f410978211..7275d0addf0 100644 --- a/source/blender/io/alembic/exporter/abc_writer_mesh.cc +++ b/source/blender/io/alembic/exporter/abc_writer_mesh.cc @@ -166,9 +166,10 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) const int quad_method = args_.export_params->quad_method; const int ngon_method = args_.export_params->ngon_method; - struct BMeshCreateParams bmcp = {false}; - struct BMeshFromMeshParams bmfmp = {true, false, false, 0}; - BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmcp, &bmfmp); + BMeshCreateParams bmesh_create_params{}; + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = true; + BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params); BM_mesh_triangulate(bm, quad_method, ngon_method, 4, tag_only, nullptr, nullptr, nullptr); @@ -189,6 +190,7 @@ void ABCGenericMeshWriter::do_write(HierarchyContext &context) m_custom_data_config.totpoly = mesh->totpoly; m_custom_data_config.totloop = mesh->totloop; m_custom_data_config.totvert = mesh->totvert; + m_custom_data_config.timesample_index = timesample_index_; try { if (is_subd_) { @@ -350,7 +352,7 @@ void ABCGenericMeshWriter::write_face_sets(Object *object, struct Mesh *mesh, Sc void ABCGenericMeshWriter::write_arb_geo_params(struct Mesh *me) { - if (frame_has_been_written_ || !args_.export_params->vcolors) { + if (!args_.export_params->vcolors) { return; } diff --git a/source/blender/io/alembic/intern/abc_customdata.cc b/source/blender/io/alembic/intern/abc_customdata.cc index 087d60f8896..188e8daac8f 100644 --- a/source/blender/io/alembic/intern/abc_customdata.cc +++ b/source/blender/io/alembic/intern/abc_customdata.cc @@ -176,29 +176,23 @@ static void write_uv(const OCompoundProperty &prop, UInt32ArraySample(&indices.front(), indices.size()), kFacevaryingScope); param.set(sample); + param.setTimeSampling(config.timesample_index); config.abc_uv_maps[uv_map_name] = param; } -/* Convention to write Vertex Colors: - * - C3fGeomParam/C4fGeomParam on the arbGeomParam - * - set scope as vertex varying - */ -static void write_mcol(const OCompoundProperty &prop, - const CDStreamConfig &config, - void *data, - const char *name) +static void get_cols(const CDStreamConfig &config, + std::vector<Imath::C4f> &buffer, + std::vector<uint32_t> &uvidx, + void *cd_data) { const float cscale = 1.0f / 255.0f; MPoly *polys = config.mpoly; MLoop *mloops = config.mloop; - MCol *cfaces = static_cast<MCol *>(data); - - std::vector<Imath::C4f> buffer; - std::vector<uint32_t> indices; + MCol *cfaces = static_cast<MCol *>(cd_data); buffer.reserve(config.totvert); - indices.reserve(config.totvert); + uvidx.reserve(config.totvert); Imath::C4f col; @@ -217,17 +211,44 @@ static void write_mcol(const OCompoundProperty &prop, col[3] = cface->b * cscale; buffer.push_back(col); - indices.push_back(buffer.size() - 1); + uvidx.push_back(buffer.size() - 1); } } +} + +/* Convention to write Vertex Colors: + * - C3fGeomParam/C4fGeomParam on the arbGeomParam + * - set scope as vertex varying + */ +static void write_mcol(const OCompoundProperty &prop, + CDStreamConfig &config, + void *data, + const char *name) +{ + std::vector<uint32_t> indices; + std::vector<Imath::C4f> buffer; + + get_cols(config, buffer, indices, data); + + if (indices.empty() || buffer.empty()) { + return; + } - OC4fGeomParam param(prop, name, true, kFacevaryingScope, 1); + std::string vcol_name(name); + OC4fGeomParam param = config.abc_vertex_colors[vcol_name]; + + if (!param.valid()) { + param = OC4fGeomParam(prop, name, true, kFacevaryingScope, 1); + } OC4fGeomParam::Sample sample(C4fArraySample(&buffer.front(), buffer.size()), UInt32ArraySample(&indices.front(), indices.size()), kVertexScope); param.set(sample); + param.setTimeSampling(config.timesample_index); + + config.abc_vertex_colors[vcol_name] = param; } void write_generated_coordinates(const OCompoundProperty &prop, CDStreamConfig &config) diff --git a/source/blender/io/alembic/intern/abc_customdata.h b/source/blender/io/alembic/intern/abc_customdata.h index 03e6f697f0c..5eae6307474 100644 --- a/source/blender/io/alembic/intern/abc_customdata.h +++ b/source/blender/io/alembic/intern/abc_customdata.h @@ -66,6 +66,7 @@ struct CDStreamConfig { float weight; float time; + int timesample_index; bool use_vertex_interpolation; Alembic::AbcGeom::index_t index; Alembic::AbcGeom::index_t ceil_index; @@ -82,6 +83,9 @@ struct CDStreamConfig { /* ORCO coordinates, aka Generated Coordinates. */ Alembic::AbcGeom::OV3fGeomParam abc_orco; + /* Mapping from vertex color layer name to its Alembic color data. */ + std::map<std::string, Alembic::AbcGeom::OC4fGeomParam> abc_vertex_colors; + CDStreamConfig() : mloop(NULL), totloop(0), diff --git a/source/blender/io/avi/intern/avi.c b/source/blender/io/avi/intern/avi.c index 87058693378..221e56ac793 100644 --- a/source/blender/io/avi/intern/avi.c +++ b/source/blender/io/avi/intern/avi.c @@ -591,7 +591,7 @@ AviError AVI_open_movie(const char *name, AviMovie *movie) BLI_fseek(movie->fp, size - 4, SEEK_CUR); if (GET_FCC(movie->fp) != FCC("idx1")) { - DEBUG_PRINT("bad index informatio\n"); + DEBUG_PRINT("bad index information\n"); return AVI_ERROR_FORMAT; } diff --git a/source/blender/io/collada/AnimationExporter.cpp b/source/blender/io/collada/AnimationExporter.cpp index 9ba59c0414d..56274e7e6ca 100644 --- a/source/blender/io/collada/AnimationExporter.cpp +++ b/source/blender/io/collada/AnimationExporter.cpp @@ -549,7 +549,7 @@ void AnimationExporter::add_source_parameters(COLLADASW::SourceBase::ParameterNa param.push_back("TRANSFORM"); } else { - /* assumes if axis isn't specified all axises are added */ + /* assumes if axis isn't specified all axes are added */ param.push_back("X"); param.push_back("Y"); param.push_back("Z"); diff --git a/source/blender/io/collada/collada_utils.cpp b/source/blender/io/collada/collada_utils.cpp index 60c4a9bad13..c1f25ea9a26 100644 --- a/source/blender/io/collada/collada_utils.cpp +++ b/source/blender/io/collada/collada_utils.cpp @@ -444,14 +444,14 @@ void bc_triangulate_mesh(Mesh *me) /* XXX: The triangulation method selection could be offered in the UI. */ int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; - const struct BMeshCreateParams bm_create_params = {0}; + const BMeshCreateParams bm_create_params{}; BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_create_params); - BMeshFromMeshParams bm_from_me_params = {0}; + BMeshFromMeshParams bm_from_me_params{}; bm_from_me_params.calc_face_normal = true; BM_mesh_bm_from_me(bm, me, &bm_from_me_params); BM_mesh_triangulate(bm, quad_method, use_beauty, 4, tag_only, nullptr, nullptr, nullptr); - BMeshToMeshParams bm_to_me_params = {0}; + BMeshToMeshParams bm_to_me_params{}; bm_to_me_params.calc_object_remap = false; BM_mesh_bm_to_me(nullptr, bm, me, &bm_to_me_params); BM_mesh_free(bm); diff --git a/source/blender/io/gpencil/gpencil_io.h b/source/blender/io/gpencil/gpencil_io.h index fab867b38b3..cb004910c1e 100644 --- a/source/blender/io/gpencil/gpencil_io.h +++ b/source/blender/io/gpencil/gpencil_io.h @@ -82,6 +82,7 @@ typedef enum eGpencilExportSelect { typedef enum eGpencilExportFrame { GP_EXPORT_FRAME_ACTIVE = 0, GP_EXPORT_FRAME_SELECTED = 1, + GP_EXPORT_FRAME_SCENE = 2, } eGpencilExportFrame; bool gpencil_io_export(const char *filename, struct GpencilIOParams *iparams); diff --git a/source/blender/io/gpencil/intern/gpencil_io_capi.cc b/source/blender/io/gpencil/intern/gpencil_io_capi.cc index 544c51e0b4f..95f5839682f 100644 --- a/source/blender/io/gpencil/intern/gpencil_io_capi.cc +++ b/source/blender/io/gpencil/intern/gpencil_io_capi.cc @@ -112,32 +112,39 @@ static bool gpencil_io_export_pdf(Depsgraph *depsgraph, exporter->frame_number_set(iparams->frame_cur); result |= exporter->new_document(); - const bool use_frame_selected = (iparams->frame_mode == GP_EXPORT_FRAME_SELECTED); - if (use_frame_selected) { - for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) { - if (!is_keyframe_included(gpd_eval, i, use_frame_selected)) { - continue; - } - - CFRA = i; - BKE_scene_graph_update_for_newframe(depsgraph); + switch (iparams->frame_mode) { + case GP_EXPORT_FRAME_ACTIVE: { exporter->prepare_camera_params(scene, iparams); - exporter->frame_number_set(i); exporter->add_newpage(); exporter->add_body(); + result = exporter->write(); + break; } - result = exporter->write(); - /* Back to original frame. */ - exporter->frame_number_set(iparams->frame_cur); - CFRA = iparams->frame_cur; - BKE_scene_camera_switch_update(scene); - BKE_scene_graph_update_for_newframe(depsgraph); - } - else { - exporter->prepare_camera_params(scene, iparams); - exporter->add_newpage(); - exporter->add_body(); - result = exporter->write(); + case GP_EXPORT_FRAME_SELECTED: + case GP_EXPORT_FRAME_SCENE: { + for (int32_t i = iparams->frame_start; i < iparams->frame_end + 1; i++) { + if ((iparams->frame_mode == GP_EXPORT_FRAME_SELECTED) && + (!is_keyframe_included(gpd_eval, i, true))) { + continue; + } + + CFRA = i; + BKE_scene_graph_update_for_newframe(depsgraph); + exporter->prepare_camera_params(scene, iparams); + exporter->frame_number_set(i); + exporter->add_newpage(); + exporter->add_body(); + } + result = exporter->write(); + /* Back to original frame. */ + exporter->frame_number_set(iparams->frame_cur); + CFRA = iparams->frame_cur; + BKE_scene_camera_switch_update(scene); + BKE_scene_graph_update_for_newframe(depsgraph); + break; + } + default: + break; } return result; diff --git a/source/blender/makesdna/DNA_constraint_types.h b/source/blender/makesdna/DNA_constraint_types.h index 6dc2d00252f..d587bd8082b 100644 --- a/source/blender/makesdna/DNA_constraint_types.h +++ b/source/blender/makesdna/DNA_constraint_types.h @@ -728,7 +728,7 @@ typedef enum eBConstraint_Flags { /* bConstraint->ownspace/tarspace */ typedef enum eBConstraint_SpaceTypes { - /** Default for all - worldspace. */ + /** Default for all - world-space. */ CONSTRAINT_SPACE_WORLD = 0, /** For all - custom space. */ CONSTRAINT_SPACE_CUSTOM = 5, diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 0cbef540306..d8065410f2b 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -513,7 +513,7 @@ typedef struct FluidDomainSettings { float p1[3]; /* End point of BB in local space. */ float dp0[3]; /* Difference from object center to grid start point. */ float cell_size[3]; /* Size of simulation cell in local space. */ - float global_size[3]; /* Global size of domain axises. */ + float global_size[3]; /* Global size of domain axes. */ float prev_loc[3]; int shift[3]; /* Current domain shift in simulation cells. */ float shift_f[3]; /* Exact domain shift. */ @@ -694,7 +694,7 @@ typedef struct FluidDomainSettings { char openvdb_data_depth; char _pad11[7]; /* Unused. */ - /* -- Deprecated / unsed options (below). -- */ + /* -- Deprecated / unused options (below). -- */ /* View options. */ int viewsettings; diff --git a/source/blender/makesdna/DNA_image_types.h b/source/blender/makesdna/DNA_image_types.h index 2464eb05a6d..64c8fd3e3a9 100644 --- a/source/blender/makesdna/DNA_image_types.h +++ b/source/blender/makesdna/DNA_image_types.h @@ -142,6 +142,12 @@ typedef enum eImageTextureResolution { IMA_TEXTURE_RESOLUTION_LEN } eImageTextureResolution; +typedef struct Image_Runtime { + /* Mutex used to guarantee thread-safe access to the cached ImBuf of the corresponding image ID. + */ + void *cache_mutex; +} Image_Runtime; + typedef struct Image { ID id; @@ -208,6 +214,8 @@ typedef struct Image { /** ImageView. */ ListBase views; struct Stereo3dFormat *stereo3d_format; + + Image_Runtime runtime; } Image; /* **************** IMAGE ********************* */ diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 038de8e49cc..1a3bda34a84 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -149,7 +149,7 @@ BLI_STATIC_ASSERT_ALIGN(LightGridCache, 16) typedef struct LightCacheTexture { struct GPUTexture *tex; - /** Copy of GPU datas to create GPUTextures on file read. */ + /** Copy of GPU data to create GPUTextures on file read. */ char *data; int tex_size[3]; char data_type; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index d5d2520ddf6..59cf4da26f6 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -46,6 +46,7 @@ struct bNodePreview; struct bNodeTreeExec; struct bNodeType; struct uiBlock; +struct PreviewImage; #define NODE_MAXSTR 64 @@ -80,6 +81,19 @@ typedef struct bNodeStack { #define NS_CR_FIT 4 #define NS_CR_STRETCH 5 +/** Workaround to forward-declare C++ type in C header. */ +#ifdef __cplusplus +namespace blender::nodes { +class NodeDeclaration; +class SocketDeclaration; +} // namespace blender::nodes +using NodeDeclarationHandle = blender::nodes::NodeDeclaration; +using SocketDeclarationHandle = blender::nodes::SocketDeclaration; +#else +typedef struct NodeDeclarationHandle NodeDeclarationHandle; +typedef struct SocketDeclarationHandle SocketDeclarationHandle; +#endif + typedef struct bNodeSocket { struct bNodeSocket *next, *prev, *new_sock; @@ -152,6 +166,12 @@ typedef struct bNodeSocket { * kept for forward compatibility */ /** Custom data for inputs, only UI writes in this. */ bNodeStack ns DNA_DEPRECATED; + + /** + * References a socket declaration that is owned by `node->declaration`. This is only runtime + * data. It has to be updated when the node declaration changes. + */ + const SocketDeclarationHandle *declaration; } bNodeSocket; /* sock->type */ @@ -219,16 +239,6 @@ typedef enum eNodeSocketFlag { SOCK_HIDE_LABEL = (1 << 12), } eNodeSocketFlag; -/** Workaround to forward-declare C++ type in C header. */ -#ifdef __cplusplus -namespace blender::nodes { -class NodeDeclaration; -} -using NodeDeclarationHandle = blender::nodes::NodeDeclaration; -#else -typedef struct NodeDeclarationHandle NodeDeclarationHandle; -#endif - /* TODO: Limit data in bNode to what we want to see saved. */ typedef struct bNode { struct bNode *next, *prev, *new_node; @@ -292,7 +302,7 @@ typedef struct bNode { char _pad1[4]; - /** Entire boundbox (worldspace). */ + /** Entire boundbox (world-space). */ rctf totr; /** Optional buttons area. */ rctf butr; @@ -561,10 +571,15 @@ typedef struct bNodeTree { int (*test_break)(void *); void (*update_draw)(void *); void *tbh, *prh, *sdh, *udh; + + /** Image representing what the node group does. */ + struct PreviewImage *preview; } bNodeTree; /* ntree->type, index */ -#define NTREE_CUSTOM -1 /* for dynamically registered custom types */ + +#define NTREE_UNDEFINED -2 /* Represents #NodeTreeTypeUndefined type. */ +#define NTREE_CUSTOM -1 /* for dynamically registered custom types */ #define NTREE_SHADER 0 #define NTREE_COMPOSIT 1 #define NTREE_TEXTURE 2 diff --git a/source/blender/makesdna/DNA_object_types.h b/source/blender/makesdna/DNA_object_types.h index e94541fdc7f..57c8ef200ae 100644 --- a/source/blender/makesdna/DNA_object_types.h +++ b/source/blender/makesdna/DNA_object_types.h @@ -311,7 +311,7 @@ typedef struct Object { float rotAxis[3], drotAxis[3]; /** Axis angle rotation - angle part. */ float rotAngle, drotAngle; - /** Final worldspace matrix with constraints & animsys applied. */ + /** Final world-space matrix with constraints & animsys applied. */ float obmat[4][4]; /** Inverse result of parent, so that object doesn't 'stick' to parent. */ float parentinv[4][4]; diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index eeff5473d16..634e97f782f 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -2066,6 +2066,9 @@ enum { #define SCE_SNAP_MODE_VOLUME (1 << 3) #define SCE_SNAP_MODE_EDGE_MIDPOINT (1 << 4) #define SCE_SNAP_MODE_EDGE_PERPENDICULAR (1 << 5) +#define SCE_SNAP_MODE_GEOM \ + (SCE_SNAP_MODE_VERTEX | SCE_SNAP_MODE_EDGE | SCE_SNAP_MODE_FACE | \ + SCE_SNAP_MODE_EDGE_PERPENDICULAR | SCE_SNAP_MODE_EDGE_MIDPOINT) /** #SequencerToolSettings.snap_mode */ #define SEQ_SNAP_TO_STRIPS (1 << 0) diff --git a/source/blender/makesdna/DNA_screen_types.h b/source/blender/makesdna/DNA_screen_types.h index 86fd6b9744a..f15767ff692 100644 --- a/source/blender/makesdna/DNA_screen_types.h +++ b/source/blender/makesdna/DNA_screen_types.h @@ -458,6 +458,9 @@ typedef struct ARegion_Runtime { /* The offset needed to not overlap with window scrollbars. Only used by HUD regions for now. */ int offset_x, offset_y; + + /* Maps uiBlock->name to uiBlock for faster lookups. */ + struct GHash *block_name_map; } ARegion_Runtime; typedef struct ARegion { @@ -667,7 +670,7 @@ typedef enum eRegion_Type { RGN_TYPE_FOOTER = 11, RGN_TYPE_TOOL_HEADER = 12, /* Region type used exclusively by internal code and add-ons to register draw callbacks to the XR - context (surface, mirror view). Does not represent any real region. */ + * context (surface, mirror view). Does not represent any real region. */ RGN_TYPE_XR = 13, #define RGN_TYPE_LEN (RGN_TYPE_XR + 1) diff --git a/source/blender/makesdna/DNA_sequence_types.h b/source/blender/makesdna/DNA_sequence_types.h index fc23d3c69a3..9e6cf907444 100644 --- a/source/blender/makesdna/DNA_sequence_types.h +++ b/source/blender/makesdna/DNA_sequence_types.h @@ -378,7 +378,7 @@ typedef struct TextVars { char text[512]; struct VFont *text_font; int text_blf_id; - int text_size; + float text_size; float color[4], shadow_color[4], box_color[4]; float loc[2]; float wrap_width; diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 5ebc81fff4f..88c5ace9cb3 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -64,7 +64,7 @@ struct wmTimer; /* Defined in `buttons_intern.h`. */ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; -/* Defined in `node_intern.h`. */ +/* Defined in `node_intern.hh`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; /* Defined in `file_intern.h`. */ @@ -1158,8 +1158,12 @@ typedef struct FileDirEntryArr { /* FileDirEntry.flags */ enum { - FILE_ENTRY_INVALID_PREVIEW = 1 << 0, /* The preview for this entry could not be generated. */ + /* The preview for this entry could not be generated. */ + FILE_ENTRY_INVALID_PREVIEW = 1 << 0, + /* The entry name needs to be freed when clearing file list. */ FILE_ENTRY_NAME_FREE = 1 << 1, + /* The preview for this entry is being loaded on another thread. */ + FILE_ENTRY_PREVIEW_LOADING = 1 << 2, }; /** \} */ @@ -1516,6 +1520,7 @@ typedef struct SpaceNodeOverlay { typedef enum eSpaceNodeOverlay_Flag { SN_OVERLAY_SHOW_OVERLAYS = (1 << 1), SN_OVERLAY_SHOW_WIRE_COLORS = (1 << 2), + SN_OVERLAY_SHOW_TIMINGS = (1 << 3), } eSpaceNodeOverlay_Flag; typedef struct SpaceNode { @@ -2006,6 +2011,7 @@ typedef enum eSpreadsheetColumnValueType { SPREADSHEET_VALUE_TYPE_FLOAT3 = 4, SPREADSHEET_VALUE_TYPE_COLOR = 5, SPREADSHEET_VALUE_TYPE_INSTANCES = 6, + SPREADSHEET_VALUE_TYPE_STRING = 7, } eSpreadsheetColumnValueType; /** diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index ee33e8666ec..2c3cd8eab77 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -128,9 +128,9 @@ typedef struct PointDensity { struct Object *object; /** `index + 1` in ob.particlesystem, non-ID pointer not allowed */ int psys; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short psys_cache_space; - /** cache points in worldspace, object space, ... ? */ + /** cache points in world-space, object space, ... ? */ short ob_cache_space; /** vertex attribute layer for color source, MAX_CUSTOMDATA_LAYER_NAME */ char vertex_attribute_name[64]; diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index 104f335cd16..c8fdac19b61 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -69,8 +69,9 @@ typedef struct uiFont { typedef struct uiFontStyle { /** Saved in file, 0 is default. */ short uifont_id; + char _pad1[2]; /** Actual size depends on 'global' dpi. */ - short points; + float points; /** Style hint. */ short italic, bold; /** Value is amount of pixels blur. */ @@ -82,6 +83,7 @@ typedef struct uiFontStyle { float shadowalpha; /** 1 value, typically white or black anyway. */ float shadowcolor; + char _pad2[4]; } uiFontStyle; /* this is fed to the layout engine and widget code */ @@ -557,7 +559,7 @@ typedef struct bUserMenuItem_Op { bUserMenuItem item; char op_idname[64]; struct IDProperty *prop; - char opcontext; + char opcontext; /* #wmOperatorCallContext */ char _pad0[7]; } bUserMenuItem_Op; @@ -939,7 +941,8 @@ typedef struct UserDef { short sequencer_proxy_setup; /* eUserpref_SeqProxySetup */ float collection_instance_empty_size; - char _pad10[2]; + char text_flag; + char _pad10[1]; char file_preview_type; /* eUserpref_File_Preview_Type */ char statusbar_flag; /* eUserpref_StatusBar_Flag */ @@ -1264,6 +1267,14 @@ typedef enum eDupli_ID_Flags { } eDupli_ID_Flags; /** + * Text Editor options + * #UserDef.text_flag + */ +typedef enum eTextEdit_Flags { + USER_TEXT_EDIT_AUTO_CLOSE = (1 << 0), +} eTextEdit_Flags; + +/** * Text draw options * #UserDef.text_render */ diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 9b5ed133feb..3fd2f1208dd 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -64,8 +64,10 @@ typedef struct RegionView3D { /** User defined clipping planes. */ float clip[6][4]; - /** Clip in object space, - * means we can test for clipping in editmode without first going into worldspace. */ + /** + * Clip in object space, + * means we can test for clipping in edit-mode without first going into world-space. + */ float clip_local[6][4]; struct BoundBox *clipbb; @@ -94,8 +96,8 @@ typedef struct RegionView3D { /** Runtime only. */ float pixsize; /** - * View center & orbit pivot, negative of worldspace location, - * also matches -viewinv[3][0:3] in ortho mode. + * View center & orbit pivot, negative of world-space location, + * also matches `-viewinv[3][0:3]` in orthographic mode. */ float ofs[3]; /** Viewport zoom on the camera frame, see BKE_screen_view3d_zoom_to_fac. */ diff --git a/source/blender/makesrna/RNA_enum_items.h b/source/blender/makesrna/RNA_enum_items.h index f3e15d08fa3..fb18802483d 100644 --- a/source/blender/makesrna/RNA_enum_items.h +++ b/source/blender/makesrna/RNA_enum_items.h @@ -211,6 +211,8 @@ DEF_ENUM(rna_enum_attribute_domain_items) DEF_ENUM(rna_enum_attribute_domain_without_corner_items) DEF_ENUM(rna_enum_attribute_domain_with_auto_items) +DEF_ENUM(rna_enum_volume_grid_data_type_items) + DEF_ENUM(rna_enum_collection_color_items) DEF_ENUM(rna_enum_strip_color_items) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index f2e87b29c1f..a6732ca1760 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4698,6 +4698,19 @@ static const char *cpp_classes = " inline static int sname##_##identifier##_length_wrap(PointerRNA *ptr) \\\n" " { return sname##_##identifier##_length(ptr); } \n" "\n" + "#define COLLECTION_PROPERTY_EMPTY_false(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { \\\n" + " CollectionPropertyIterator iter; \\\n" + " sname##_##identifier##_begin(&iter, ptr); \\\n" + " bool empty = !iter.valid; \\\n" + " sname##_##identifier##_end(&iter); \\\n" + " return empty; \\\n" + " } \n" + "#define COLLECTION_PROPERTY_EMPTY_true(sname, identifier) \\\n" + " inline static bool sname##_##identifier##_empty_wrap(PointerRNA *ptr) \\\n" + " { return sname##_##identifier##_length(ptr) == 0; } \n" + "\n" "#define COLLECTION_PROPERTY_LOOKUP_INT_false(sname, identifier) \\\n" " inline static int sname##_##identifier##_lookup_int_wrap(PointerRNA *ptr, int key, " "PointerRNA *r_ptr) \\\n" @@ -4774,11 +4787,13 @@ static const char *cpp_classes = " typedef CollectionIterator<type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end> identifier##_iterator; \\\n" " COLLECTION_PROPERTY_LENGTH_##has_length(sname, identifier) \\\n" + " COLLECTION_PROPERTY_EMPTY_##has_length(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_INT_##has_lookup_int(sname, identifier) \\\n" " COLLECTION_PROPERTY_LOOKUP_STRING_##has_lookup_string(sname, identifier) \\\n" " CollectionRef<sname, type, sname##_##identifier##_begin, \\\n" " sname##_##identifier##_next, sname##_##identifier##_end, \\\n" " sname##_##identifier##_length_wrap, \\\n" + " sname##_##identifier##_empty_wrap, \\\n" " sname##_##identifier##_lookup_int_wrap, sname##_##identifier##_lookup_string_wrap, " "collection_funcs> identifier;\n" "\n" @@ -4844,6 +4859,7 @@ static const char *cpp_classes = "typedef void (*TNextFunc)(CollectionPropertyIterator *iter);\n" "typedef void (*TEndFunc)(CollectionPropertyIterator *iter);\n" "typedef int (*TLengthFunc)(PointerRNA *ptr);\n" + "typedef bool (*TEmptyFunc)(PointerRNA *ptr);\n" "typedef int (*TLookupIntFunc)(PointerRNA *ptr, int key, PointerRNA *r_ptr);\n" "typedef int (*TLookupStringFunc)(PointerRNA *ptr, const char *key, PointerRNA *r_ptr);\n" "\n" @@ -4882,8 +4898,8 @@ static const char *cpp_classes = "};\n" "\n" "template<typename Tp, typename T, TBeginFunc Tbegin, TNextFunc Tnext, TEndFunc Tend,\n" - " TLengthFunc Tlength, TLookupIntFunc Tlookup_int, TLookupStringFunc Tlookup_string,\n" - " typename Tcollection_funcs>\n" + " TLengthFunc Tlength, TEmptyFunc Tempty, TLookupIntFunc Tlookup_int,\n" + " TLookupStringFunc Tlookup_string, typename Tcollection_funcs>\n" "class CollectionRef : public Tcollection_funcs {\n" "public:\n" " CollectionRef(const PointerRNA &p) : Tcollection_funcs(p), ptr(p) {}\n" @@ -4897,6 +4913,8 @@ static const char *cpp_classes = "" " int length()\n" " { return Tlength(&ptr); }\n" + " bool empty()\n" + " { return Tempty(&ptr); }\n" " T operator[](int key)\n" " { PointerRNA r_ptr; Tlookup_int(&ptr, key, &r_ptr); return T(r_ptr); }\n" " T operator[](const std::string &key)\n" diff --git a/source/blender/makesrna/intern/rna_animviz.c b/source/blender/makesrna/intern/rna_animviz.c index b205b3d7139..1511921cef0 100644 --- a/source/blender/makesrna/intern/rna_animviz.c +++ b/source/blender/makesrna/intern/rna_animviz.c @@ -117,7 +117,7 @@ static void rna_def_animviz_motion_path(BlenderRNA *brna) srna = RNA_def_struct(brna, "MotionPath", NULL); RNA_def_struct_sdna(srna, "bMotionPath"); RNA_def_struct_ui_text( - srna, "Motion Path", "Cache of the worldspace positions of an element over a frame range"); + srna, "Motion Path", "Cache of the world-space positions of an element over a frame range"); /* Collections */ prop = RNA_def_property(srna, "points", PROP_COLLECTION, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_attribute.c b/source/blender/makesrna/intern/rna_attribute.c index dbf20896463..78c15444308 100644 --- a/source/blender/makesrna/intern/rna_attribute.c +++ b/source/blender/makesrna/intern/rna_attribute.c @@ -72,6 +72,7 @@ const EnumPropertyItem rna_enum_attribute_domain_items[] = { /* Not implement yet */ // {ATTR_DOMAIN_GRIDS, "GRIDS", 0, "Grids", "Attribute on mesh multires grids"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -80,6 +81,7 @@ const EnumPropertyItem rna_enum_attribute_domain_without_corner_items[] = { {ATTR_DOMAIN_EDGE, "EDGE", 0, "Edge", "Attribute on mesh edge"}, {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; @@ -90,6 +92,7 @@ const EnumPropertyItem rna_enum_attribute_domain_with_auto_items[] = { {ATTR_DOMAIN_FACE, "FACE", 0, "Face", "Attribute on mesh faces"}, {ATTR_DOMAIN_CORNER, "CORNER", 0, "Face Corner", "Attribute on mesh face corner"}, {ATTR_DOMAIN_CURVE, "CURVE", 0, "Spline", "Attribute on spline"}, + {ATTR_DOMAIN_INSTANCE, "INSTANCE", 0, "Instance", "Attribute on instance"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_brush.c b/source/blender/makesrna/intern/rna_brush.c index 1d3b8cd9f9c..b4cf15ebfc6 100644 --- a/source/blender/makesrna/intern/rna_brush.c +++ b/source/blender/makesrna/intern/rna_brush.c @@ -1283,7 +1283,7 @@ static void rna_def_gpencil_options(BlenderRNA *brna) static EnumPropertyItem gppaint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_gpencil_modifier.c b/source/blender/makesrna/intern/rna_gpencil_modifier.c index 7fe51d45eb2..82f3279146a 100644 --- a/source/blender/makesrna/intern/rna_gpencil_modifier.c +++ b/source/blender/makesrna/intern/rna_gpencil_modifier.c @@ -167,14 +167,14 @@ const EnumPropertyItem rna_enum_object_greasepencil_modifier_type_items[] = { #ifndef RNA_RUNTIME static const EnumPropertyItem modifier_modify_color_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem modifier_modify_opacity_items[] = { - {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke and Fill", "Modify fill and stroke colors"}, + {GP_MODIFY_COLOR_BOTH, "BOTH", 0, "Stroke & Fill", "Modify fill and stroke colors"}, {GP_MODIFY_COLOR_STROKE, "STROKE", 0, "Stroke", "Modify stroke color only"}, {GP_MODIFY_COLOR_FILL, "FILL", 0, "Fill", "Modify fill color only"}, {GP_MODIFY_COLOR_HARDNESS, "HARDNESS", 0, "Hardness", "Modify stroke hardness"}, @@ -1450,7 +1450,7 @@ static void rna_def_modifier_gpenciltint(BlenderRNA *brna) static EnumPropertyItem tint_mode_types_items[] = { {GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Vertex Color affects to Stroke only"}, {GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Vertex Color affects to Fill only"}, - {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Vertex Color affects to Stroke and Fill"}, + {GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke & Fill", "Vertex Color affects to Stroke and Fill"}, {0, NULL, 0, NULL, NULL}, }; @@ -2677,7 +2677,7 @@ static void rna_def_modifier_gpenciltexture(BlenderRNA *brna) {STROKE_AND_FILL, "STROKE_AND_FILL", 0, - "Stroke and Fill", + "Stroke & Fill", "Manipulate both stroke and fill texture coordinates"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index e6b732aabd4..aef3823338b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -12754,6 +12754,11 @@ static void rna_def_nodetree(BlenderRNA *brna) PropertyRNA *parm; static const EnumPropertyItem static_type_items[] = { + {NTREE_UNDEFINED, + "UNDEFINED", + ICON_QUESTION, + "Undefined", + "Undefined type of nodes (can happen e.g. when a linked node tree goes missing)"}, {NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"}, {NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"}, {NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"}, diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c index 10094ade711..63c4774d0e5 100644 --- a/source/blender/makesrna/intern/rna_object_api.c +++ b/source/blender/makesrna/intern/rna_object_api.c @@ -530,7 +530,7 @@ static int mesh_looptri_to_poly_index(Mesh *me_eval, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } -/* TOOD(sergey): Make the Python API more clear that evaluation might happen, or requite +/* TODO(sergey): Make the Python API more clear that evaluation might happen, or require * passing fully evaluated depsgraph. */ static Object *eval_object_ensure(Object *ob, bContext *C, diff --git a/source/blender/makesrna/intern/rna_object_force.c b/source/blender/makesrna/intern/rna_object_force.c index 186222d2ca0..2fca9f0af7a 100644 --- a/source/blender/makesrna/intern/rna_object_force.c +++ b/source/blender/makesrna/intern/rna_object_force.c @@ -1006,8 +1006,7 @@ static void rna_def_pointcache_common(StructRNA *srna) prop = RNA_def_property(srna, "is_frame_skip", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "flag", PTCACHE_FRAMES_SKIPPED); RNA_def_property_clear_flag(prop, PROP_EDITABLE); - RNA_def_property_ui_text( - prop, "", "Some frames were skipped while baking/saving that cache"); + RNA_def_property_ui_text(prop, "", "Some frames were skipped while baking/saving that cache"); prop = RNA_def_property(srna, "name", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "name"); diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 9f92f1c6e5f..f92043995dd 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -1366,6 +1366,28 @@ static float rna_Sequence_fps_get(PointerRNA *ptr) return SEQ_time_sequence_get_fps(scene, seq); } +static void rna_Sequence_separate(ID *id, Sequence *seqm, Main *bmain) +{ + Scene *scene = (Scene *)id; + + /* Find the appropriate seqbase */ + Editing *ed = SEQ_editing_get(scene); + ListBase *seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, seqm); + + LISTBASE_FOREACH_MUTABLE (Sequence *, seq, &seqm->seqbase) { + SEQ_edit_move_strip_to_seqbase(scene, &seqm->seqbase, seq, seqbase); + } + + SEQ_edit_flag_for_removal(scene, seqbase, seqm); + SEQ_edit_remove_flagged_sequences(scene, seqbase); + + /* Update depsgraph. */ + DEG_relations_tag_update(bmain); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); + + WM_main_add_notifier(NC_SCENE | ND_SEQUENCER, scene); +} + #else static void rna_def_strip_element(BlenderRNA *brna) @@ -2439,6 +2461,7 @@ static void rna_def_image(BlenderRNA *brna) static void rna_def_meta(BlenderRNA *brna) { StructRNA *srna; + FunctionRNA *func; PropertyRNA *prop; srna = RNA_def_struct(brna, "MetaSequence", "Sequence"); @@ -2452,6 +2475,10 @@ static void rna_def_meta(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Sequences", "Sequences nested in meta strip"); RNA_api_sequences(brna, prop, true); + func = RNA_def_function(srna, "separate", "rna_Sequence_separate"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_USE_MAIN); + RNA_def_function_ui_description(func, "Separate meta"); + rna_def_filter_video(srna); rna_def_proxy(srna); rna_def_input(srna); @@ -2980,11 +3007,11 @@ static void rna_def_text(StructRNA *srna) RNA_def_property_pointer_funcs(prop, NULL, "rna_Sequence_text_font_set", NULL, NULL); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); - prop = RNA_def_property(srna, "font_size", PROP_INT, PROP_UNSIGNED); - RNA_def_property_int_sdna(prop, NULL, "text_size"); + prop = RNA_def_property(srna, "font_size", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "text_size"); RNA_def_property_ui_text(prop, "Size", "Size of the text"); RNA_def_property_range(prop, 0.0, 2000); - RNA_def_property_ui_range(prop, 0.0f, 2000, 1, -1); + RNA_def_property_ui_range(prop, 0.0f, 2000, 10.f, 1); RNA_def_property_update(prop, NC_SCENE | ND_SEQUENCER, "rna_Sequence_invalidate_raw_update"); prop = RNA_def_property(srna, "color", PROP_FLOAT, PROP_COLOR_GAMMA); diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 03976967e9f..8f04524c5c1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -3090,7 +3090,7 @@ static void rna_SpaceSpreadsheet_geometry_component_type_update(Main *UNUSED(bma break; } case GEO_COMPONENT_TYPE_INSTANCES: { - sspreadsheet->attribute_domain = ATTR_DOMAIN_POINT; + sspreadsheet->attribute_domain = ATTR_DOMAIN_INSTANCE; break; } case GEO_COMPONENT_TYPE_VOLUME: { @@ -7110,6 +7110,12 @@ static void rna_def_space_node_overlay(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Show Wire Colors", "Color node links based on their connected sockets"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); + + prop = RNA_def_property(srna, "show_timing", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "overlay.flag", SN_OVERLAY_SHOW_TIMINGS); + RNA_def_property_boolean_default(prop, false); + RNA_def_property_ui_text(prop, "Show Timing", "Display each node's last execution time"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL); } static void rna_def_space_node(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_ui.c b/source/blender/makesrna/intern/rna_ui.c index c73599c19ac..05ed5e096d8 100644 --- a/source/blender/makesrna/intern/rna_ui.c +++ b/source/blender/makesrna/intern/rna_ui.c @@ -1471,15 +1471,12 @@ static void rna_def_panel(BlenderRNA *brna) RNA_def_property_string_sdna(prop, NULL, "type->category"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); RNA_def_property_ui_text( - prop, - "", - "The category (tab) in which the panel will be displayed, when applicable"); + prop, "", "The category (tab) in which the panel will be displayed, when applicable"); prop = RNA_def_property(srna, "bl_owner_id", PROP_STRING, PROP_NONE); RNA_def_property_string_sdna(prop, NULL, "type->owner_id"); RNA_def_property_flag(prop, PROP_REGISTER_OPTIONAL); - RNA_def_property_ui_text( - prop, "", "The ID owning the data displayed in the panel, if any"); + RNA_def_property_ui_text(prop, "", "The ID owning the data displayed in the panel, if any"); prop = RNA_def_property(srna, "bl_space_type", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "type->space_type"); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 4542f8fa1d7..dd1252ffebf 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -265,6 +265,14 @@ static void rna_userdef_theme_update(Main *bmain, Scene *scene, PointerRNA *ptr) rna_userdef_update(bmain, scene, ptr); } +static void rna_userdef_theme_text_style_update(Main *bmain, Scene *scene, PointerRNA *ptr) +{ + const uiStyle *style = UI_style_get(); + BLF_default_size(style->widgetlabel.points); + + rna_userdef_update(bmain, scene, ptr); +} + static void rna_userdef_gizmo_update(Main *bmain, Scene *scene, PointerRNA *ptr) { WM_reinit_gizmomap_all(bmain); @@ -1134,39 +1142,40 @@ static void rna_def_userdef_theme_ui_font_style(BlenderRNA *brna) RNA_def_struct_clear_flag(srna, STRUCT_UNDO); RNA_def_struct_ui_text(srna, "Font Style", "Theme settings for Font"); - prop = RNA_def_property(srna, "points", PROP_INT, PROP_NONE); - RNA_def_property_range(prop, 6, 24); + prop = RNA_def_property(srna, "points", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_range(prop, 6.0f, 32.0f); + RNA_def_property_ui_range(prop, 8.0f, 20.0f, 10.0f, 1); RNA_def_property_ui_text(prop, "Points", "Font size in points"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_dpi_update"); prop = RNA_def_property(srna, "shadow", PROP_INT, PROP_PIXEL); RNA_def_property_range(prop, 0, 5); RNA_def_property_ui_text(prop, "Shadow Size", "Shadow size (0, 3 and 5 supported)"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_offset_x", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "shadx"); RNA_def_property_range(prop, -10, 10); RNA_def_property_ui_text(prop, "Shadow X Offset", "Shadow offset in pixels"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_offset_y", PROP_INT, PROP_PIXEL); RNA_def_property_int_sdna(prop, NULL, "shady"); RNA_def_property_range(prop, -10, 10); RNA_def_property_ui_text(prop, "Shadow Y Offset", "Shadow offset in pixels"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_alpha", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shadowalpha"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Shadow Alpha", ""); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); prop = RNA_def_property(srna, "shadow_value", PROP_FLOAT, PROP_FACTOR); RNA_def_property_float_sdna(prop, NULL, "shadowcolor"); RNA_def_property_range(prop, 0.0f, 1.0f); RNA_def_property_ui_text(prop, "Shadow Brightness", "Shadow color in gray value"); - RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_text_style_update"); } static void rna_def_userdef_theme_ui_style(BlenderRNA *brna) @@ -5022,6 +5031,14 @@ static void rna_def_userdef_edit(BlenderRNA *brna) "Collection Instance Empty Size", "Display size of the empty when new collection instances are created"); + /* Text Editor */ + + prop = RNA_def_property(srna, "use_text_edit_auto_close", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "text_flag", USER_TEXT_EDIT_AUTO_CLOSE); + RNA_def_property_ui_text( + prop, "Auto Close", "Auto close relevant characters inside the text editor"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_TEXT, NULL); + /* Undo */ prop = RNA_def_property(srna, "undo_steps", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_volume.c b/source/blender/makesrna/intern/rna_volume.c index f6b8b55688c..3100c1195f4 100644 --- a/source/blender/makesrna/intern/rna_volume.c +++ b/source/blender/makesrna/intern/rna_volume.c @@ -33,6 +33,26 @@ #include "BLI_math_base.h" +const EnumPropertyItem rna_enum_volume_grid_data_type_items[] = { + {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"}, + {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"}, + {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"}, + {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"}, + {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"}, + {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"}, + {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"}, + {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"}, + {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"}, + {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"}, + {VOLUME_GRID_POINTS, + "POINTS", + 0, + "Points (Unsupported)", + "Points grid, currently unsupported by volume objects"}, + {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"}, + {0, NULL, 0, NULL, NULL}, +}; + #ifdef RNA_RUNTIME # include "DEG_depsgraph.h" @@ -244,30 +264,10 @@ static void rna_def_volume_grid(BlenderRNA *brna) prop, "rna_VolumeGrid_name_get", "rna_VolumeGrid_name_length", NULL); RNA_def_property_ui_text(prop, "Name", "Volume grid name"); - static const EnumPropertyItem data_type_items[] = { - {VOLUME_GRID_BOOLEAN, "BOOLEAN", 0, "Boolean", "Boolean"}, - {VOLUME_GRID_FLOAT, "FLOAT", 0, "Float", "Single precision float"}, - {VOLUME_GRID_DOUBLE, "DOUBLE", 0, "Double", "Double precision"}, - {VOLUME_GRID_INT, "INT", 0, "Integer", "32-bit integer"}, - {VOLUME_GRID_INT64, "INT64", 0, "Integer 64-bit", "64-bit integer"}, - {VOLUME_GRID_MASK, "MASK", 0, "Mask", "No data, boolean mask of active voxels"}, - {VOLUME_GRID_STRING, "STRING", 0, "String", "Text string"}, - {VOLUME_GRID_VECTOR_FLOAT, "VECTOR_FLOAT", 0, "Float Vector", "3D float vector"}, - {VOLUME_GRID_VECTOR_DOUBLE, "VECTOR_DOUBLE", 0, "Double Vector", "3D double vector"}, - {VOLUME_GRID_VECTOR_INT, "VECTOR_INT", 0, "Integer Vector", "3D integer vector"}, - {VOLUME_GRID_POINTS, - "POINTS", - 0, - "Points (Unsupported)", - "Points grid, currently unsupported by volume objects"}, - {VOLUME_GRID_UNKNOWN, "UNKNOWN", 0, "Unknown", "Unsupported data type"}, - {0, NULL, 0, NULL, NULL}, - }; - prop = RNA_def_property(srna, "data_type", PROP_ENUM, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_funcs(prop, "rna_VolumeGrid_data_type_get", NULL, NULL); - RNA_def_property_enum_items(prop, data_type_items); + RNA_def_property_enum_items(prop, rna_enum_volume_grid_data_type_items); RNA_def_property_ui_text(prop, "Data Type", "Data type of voxel values"); prop = RNA_def_property(srna, "channels", PROP_INT, PROP_UNSIGNED); diff --git a/source/blender/modifiers/intern/MOD_boolean.cc b/source/blender/modifiers/intern/MOD_boolean.cc index 1121e30b0ff..f8c181905b5 100644 --- a/source/blender/modifiers/intern/MOD_boolean.cc +++ b/source/blender/modifiers/intern/MOD_boolean.cc @@ -245,16 +245,16 @@ static BMesh *BMD_mesh_bm_create( const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(mesh, mesh_operand_ob); - BMeshCreateParams bmcp = {false}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMeshCreateParams bmesh_create_params{}; + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); /* Needed so active layers are set based on `mesh` not `mesh_operand_ob`, * otherwise the wrong active render layer is used, see T92384. */ BM_mesh_copy_init_customdata_from_mesh(bm, mesh, &allocsize); - BMeshFromMeshParams params{}; - params.calc_face_normal = true; - BM_mesh_bm_from_me(bm, mesh_operand_ob, ¶ms); + BMeshFromMeshParams bmesh_from_mesh_params{}; + bmesh_from_mesh_params.calc_face_normal = true; + BM_mesh_bm_from_me(bm, mesh_operand_ob, &bmesh_from_mesh_params); if (UNLIKELY(*r_is_flip)) { const int cd_loop_mdisp_offset = CustomData_get_offset(&bm->ldata, CD_MDISPS); @@ -265,7 +265,7 @@ static BMesh *BMD_mesh_bm_create( } } - BM_mesh_bm_from_me(bm, mesh, ¶ms); + BM_mesh_bm_from_me(bm, mesh, &bmesh_from_mesh_params); return bm; } @@ -539,9 +539,9 @@ static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh * BMD_mesh_intersection(bm, md, ctx, mesh_operand_ob, object, operand_ob, is_flip); /* Needed for multiple objects to work. */ - BMeshToMeshParams params{}; - params.calc_object_remap = false; - BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); + BMeshToMeshParams bmesh_to_mesh_params{}; + bmesh_to_mesh_params.calc_object_remap = false; + BM_mesh_bm_to_me(nullptr, bm, mesh, &bmesh_to_mesh_params); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh); BM_mesh_free(bm); diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c index c997cd7377f..cb043643dd9 100644 --- a/source/blender/modifiers/intern/MOD_meshdeform.c +++ b/source/blender/modifiers/intern/MOD_meshdeform.c @@ -426,7 +426,7 @@ static void meshdeformModifier_do(ModifierData *md, bindcagecos = (float(*)[3])mmd->bindcagecos; for (a = 0; a < totcagevert; a++) { - /* get cage vertex in world space with binding transform */ + /* Get cage vertex in world-space with binding transform. */ float co[3]; mul_v3_m4v3(co, mmd->bindmat, dco[a]); /* compute difference with world space bind coord */ diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index c1cdfa43920..05e9bd7d233 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -98,6 +98,7 @@ #include "NOD_node_declaration.hh" #include "FN_field.hh" +#include "FN_field_cpp_type.hh" #include "FN_multi_function.hh" using blender::Array; @@ -113,9 +114,11 @@ using blender::StringRef; using blender::StringRefNull; using blender::Vector; using blender::bke::OutputAttribute; +using blender::fn::Field; using blender::fn::GField; using blender::fn::GMutablePointer; using blender::fn::GPointer; +using blender::fn::ValueOrField; using blender::nodes::FieldInferencingInterface; using blender::nodes::GeoNodeExecParams; using blender::nodes::InputSocketFieldType; @@ -491,35 +494,34 @@ static void init_socket_cpp_value_from_property(const IDProperty &property, else if (property.type == IDP_DOUBLE) { value = (float)IDP_Double(&property); } - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); break; } case SOCK_INT: { int value = IDP_Int(&property); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); break; } case SOCK_VECTOR: { float3 value; copy_v3_v3(value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float3>(value); break; } case SOCK_RGBA: { blender::ColorGeometry4f value; copy_v4_v4((float *)value, (const float *)IDP_Array(&property)); - new (r_value) blender::fn::Field<ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<ColorGeometry4f>(value); break; } case SOCK_BOOLEAN: { bool value = IDP_Int(&property) != 0; - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); break; } case SOCK_STRING: { std::string value = IDP_String(&property); - new (r_value) - blender::fn::Field<std::string>(blender::fn::make_constant_field(std::move(value))); + new (r_value) ValueOrField<std::string>(std::move(value)); break; } case SOCK_OBJECT: { @@ -739,8 +741,13 @@ static void initialize_group_input(NodesModifierData &nmd, if (use_attribute) { const StringRef attribute_name{IDP_String(property_attribute_name)}; auto attribute_input = std::make_shared<blender::bke::AttributeFieldInput>( - attribute_name, *socket_type.get_base_cpp_type()); - new (r_value) blender::fn::GField(std::move(attribute_input), 0); + attribute_name, *socket_type.base_cpp_type); + GField attribute_field{std::move(attribute_input), 0}; + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>( + socket_type.geometry_nodes_cpp_type); + BLI_assert(cpp_type != nullptr); + cpp_type->construct_from_field(r_value, std::move(attribute_field)); } else { init_socket_cpp_value_from_property( @@ -904,7 +911,11 @@ static void store_output_value_in_geometry(GeometrySet &geometry_set, if (attribute_name.is_empty()) { return; } - const GField &field = *(const GField *)value.get(); + const blender::fn::ValueOrFieldCPPType *cpp_type = + dynamic_cast<const blender::fn::ValueOrFieldCPPType *>(value.type()); + BLI_assert(cpp_type != nullptr); + + const GField field = cpp_type->as_field(value.get()); const bNodeSocket *interface_socket = (bNodeSocket *)BLI_findlink(&nmd->node_group->outputs, socket.index()); const AttributeDomain domain = (AttributeDomain)interface_socket->attribute_domain; @@ -963,7 +974,7 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, /* Initialize remaining group inputs. */ for (const OutputSocketRef *socket : remaining_input_sockets) { - const CPPType &cpp_type = *socket->typeinfo()->get_geometry_nodes_cpp_type(); + const CPPType &cpp_type = *socket->typeinfo()->geometry_nodes_cpp_type; void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, *socket, value_in); group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); diff --git a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc index badd633f648..e23c494f7cf 100644 --- a/source/blender/modifiers/intern/MOD_nodes_evaluator.cc +++ b/source/blender/modifiers/intern/MOD_nodes_evaluator.cc @@ -35,13 +35,17 @@ #include "BLI_task.hh" #include "BLI_vector_set.hh" +#include <chrono> + namespace blender::modifiers::geometry_nodes { using fn::CPPType; using fn::Field; -using fn::FieldCPPType; using fn::GField; using fn::GValueMap; +using fn::GVArray; +using fn::ValueOrField; +using fn::ValueOrFieldCPPType; using nodes::GeoNodeExecParams; using namespace fn::multi_function_types; @@ -309,10 +313,10 @@ class LockedNode : NonCopyable, NonMovable { static const CPPType *get_socket_cpp_type(const SocketRef &socket) { const bNodeSocketType *typeinfo = socket.typeinfo(); - if (typeinfo->get_geometry_nodes_cpp_type == nullptr) { + if (typeinfo->geometry_nodes_cpp_type == nullptr) { return nullptr; } - const CPPType *type = typeinfo->get_geometry_nodes_cpp_type(); + const CPPType *type = typeinfo->geometry_nodes_cpp_type; if (type == nullptr) { return nullptr; } @@ -348,18 +352,19 @@ static bool get_implicit_socket_input(const SocketRef &socket, void *r_value) GEO_NODE_CURVE_HANDLE_LEFT ? "handle_left" : "handle_right"; - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>(side)); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>(side)); return true; } - new (r_value) Field<float3>(bke::AttributeFieldInput::Create<float3>("position")); + new (r_value) ValueOrField<float3>(bke::AttributeFieldInput::Create<float3>("position")); return true; } if (socket.typeinfo()->type == SOCK_INT) { if (ELEM(bnode.type, FN_NODE_RANDOM_VALUE, GEO_NODE_INSTANCE_ON_POINTS)) { - new (r_value) Field<int>(std::make_shared<bke::IDAttributeFieldInput>()); + new (r_value) + ValueOrField<int>(Field<int>(std::make_shared<bke::IDAttributeFieldInput>())); return true; } - new (r_value) Field<int>(std::make_shared<fn::IndexFieldInput>()); + new (r_value) ValueOrField<int>(Field<int>(std::make_shared<fn::IndexFieldInput>())); return true; } } @@ -926,7 +931,13 @@ class GeometryNodesEvaluator { params.error_message_add(geo_log::NodeWarningType::Legacy, TIP_("Legacy node will be removed before Blender 4.0")); } + using Clock = std::chrono::steady_clock; + Clock::time_point begin = Clock::now(); bnode.typeinfo->geometry_node_execute(params); + Clock::time_point end = Clock::now(); + const std::chrono::microseconds duration = + std::chrono::duration_cast<std::chrono::microseconds>(end - begin); + params_.geo_logger->local().log_execution_time(node, duration); } void execute_multi_function_node(const DNode node, @@ -943,8 +954,9 @@ class GeometryNodesEvaluator { LinearAllocator<> &allocator = local_allocators_.local(); - /* Prepare the inputs for the multi function. */ - Vector<GField> input_fields; + bool any_input_is_field = false; + Vector<const void *, 16> input_values; + Vector<const ValueOrFieldCPPType *, 16> input_types; for (const int i : node->inputs().index_range()) { const InputSocketRef &socket_ref = node->input(i); if (!socket_ref.is_available()) { @@ -955,7 +967,37 @@ class GeometryNodesEvaluator { BLI_assert(input_state.was_ready_for_execution); SingleInputValue &single_value = *input_state.value.single; BLI_assert(single_value.value != nullptr); - input_fields.append(std::move(*(GField *)single_value.value)); + const ValueOrFieldCPPType &field_cpp_type = static_cast<const ValueOrFieldCPPType &>( + *input_state.type); + input_values.append(single_value.value); + input_types.append(&field_cpp_type); + if (field_cpp_type.is_field(single_value.value)) { + any_input_is_field = true; + } + } + + if (any_input_is_field) { + this->execute_multi_function_node__field( + node, fn_item, node_state, allocator, input_values, input_types); + } + else { + this->execute_multi_function_node__value( + node, *fn_item.fn, node_state, allocator, input_values, input_types); + } + } + + void execute_multi_function_node__field(const DNode node, + const nodes::NodeMultiFunctions::Item &fn_item, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + Vector<GField> input_fields; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + input_fields.append(field_cpp_type.as_field(input_value_or_field)); } std::shared_ptr<fn::FieldOperation> operation; @@ -966,7 +1008,6 @@ class GeometryNodesEvaluator { operation = std::make_shared<fn::FieldOperation>(*fn_item.fn, std::move(input_fields)); } - /* Forward outputs. */ int output_index = 0; for (const int i : node->outputs().index_range()) { const OutputSocketRef &socket_ref = node->output(i); @@ -975,16 +1016,68 @@ class GeometryNodesEvaluator { } OutputState &output_state = node_state.outputs[i]; const DOutputSocket socket{node.context(), &socket_ref}; - const CPPType *cpp_type = get_socket_cpp_type(socket_ref); + const ValueOrFieldCPPType *cpp_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket_ref)); GField new_field{operation, output_index}; - new_field = fn::make_field_constant_if_possible(std::move(new_field)); - GField &field_to_forward = *allocator.construct<GField>(std::move(new_field)).release(); - this->forward_output(socket, {cpp_type, &field_to_forward}); + void *buffer = allocator.allocate(cpp_type->size(), cpp_type->alignment()); + cpp_type->construct_from_field(buffer, std::move(new_field)); + this->forward_output(socket, {cpp_type, buffer}); output_state.has_been_computed = true; output_index++; } } + void execute_multi_function_node__value(const DNode node, + const MultiFunction &fn, + NodeState &node_state, + LinearAllocator<> &allocator, + Span<const void *> input_values, + Span<const ValueOrFieldCPPType *> input_types) + { + MFParamsBuilder params{fn, 1}; + for (const int i : input_values.index_range()) { + const void *input_value_or_field = input_values[i]; + const ValueOrFieldCPPType &field_cpp_type = *input_types[i]; + const CPPType &base_type = field_cpp_type.base_type(); + const void *input_value = field_cpp_type.get_value_ptr(input_value_or_field); + params.add_readonly_single_input(GVArray::ForSingleRef(base_type, 1, input_value)); + } + + Vector<GMutablePointer, 16> output_buffers; + for (const int i : node->outputs().index_range()) { + const DOutputSocket socket = node.output(i); + if (!socket->is_available()) { + output_buffers.append({}); + continue; + } + const ValueOrFieldCPPType *value_or_field_type = static_cast<const ValueOrFieldCPPType *>( + get_socket_cpp_type(socket)); + const CPPType &base_type = value_or_field_type->base_type(); + void *value_or_field_buffer = allocator.allocate(value_or_field_type->size(), + value_or_field_type->alignment()); + value_or_field_type->default_construct(value_or_field_buffer); + void *value_buffer = value_or_field_type->get_value_ptr(value_or_field_buffer); + base_type.destruct(value_buffer); + params.add_uninitialized_single_output(GMutableSpan{base_type, value_buffer, 1}); + output_buffers.append({value_or_field_type, value_or_field_buffer}); + } + + MFContextBuilder context; + fn.call(IndexRange(1), params, context); + + for (const int i : output_buffers.index_range()) { + GMutablePointer buffer = output_buffers[i]; + if (buffer.get() == nullptr) { + continue; + } + const DOutputSocket socket = node.output(i); + this->forward_output(socket, buffer); + + OutputState &output_state = node_state.outputs[i]; + output_state.has_been_computed = true; + } + } + void execute_unknown_node(const DNode node, NodeState &node_state) { LinearAllocator<> &allocator = local_allocators_.local(); @@ -1466,19 +1559,28 @@ class GeometryNodesEvaluator { from_type.copy_construct(from_value, to_value); return; } - - const FieldCPPType *from_field_type = dynamic_cast<const FieldCPPType *>(&from_type); - const FieldCPPType *to_field_type = dynamic_cast<const FieldCPPType *>(&to_type); + const ValueOrFieldCPPType *from_field_type = dynamic_cast<const ValueOrFieldCPPType *>( + &from_type); + const ValueOrFieldCPPType *to_field_type = dynamic_cast<const ValueOrFieldCPPType *>(&to_type); if (from_field_type != nullptr && to_field_type != nullptr) { - const CPPType &from_base_type = from_field_type->field_type(); - const CPPType &to_base_type = to_field_type->field_type(); + const CPPType &from_base_type = from_field_type->base_type(); + const CPPType &to_base_type = to_field_type->base_type(); if (conversions_.is_convertible(from_base_type, to_base_type)) { - const MultiFunction &fn = *conversions_.get_conversion_multi_function( - MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); - const GField &from_field = *(const GField *)from_value; - auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); - new (to_value) GField(std::move(operation), 0); + if (from_field_type->is_field(from_value)) { + const GField &from_field = *from_field_type->get_field_ptr(from_value); + const MultiFunction &fn = *conversions_.get_conversion_multi_function( + MFDataType::ForSingle(from_base_type), MFDataType::ForSingle(to_base_type)); + auto operation = std::make_shared<fn::FieldOperation>(fn, Vector<GField>{from_field}); + to_field_type->construct_from_field(to_value, GField(std::move(operation), 0)); + } + else { + to_field_type->default_construct(to_value); + const void *from_value_ptr = from_field_type->get_value_ptr(from_value); + void *to_value_ptr = to_field_type->get_value_ptr(to_value); + conversions_.get_conversion_functions(from_base_type, to_base_type) + ->convert_single_to_initialized(from_value_ptr, to_value_ptr); + } return; } } @@ -1494,14 +1596,6 @@ class GeometryNodesEvaluator { void construct_default_value(const CPPType &type, void *r_value) { - if (const FieldCPPType *field_cpp_type = dynamic_cast<const FieldCPPType *>(&type)) { - const CPPType &base_type = field_cpp_type->field_type(); - auto constant_fn = std::make_unique<fn::CustomMF_GenericConstant>( - base_type, base_type.default_value(), false); - auto operation = std::make_shared<fn::FieldOperation>(std::move(constant_fn)); - new (r_value) GField(std::move(operation), 0); - return; - } type.copy_construct(type.default_value(), r_value); } diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index 2c28e9710ef..238952fde00 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -192,7 +192,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, mul_m4_m4m4(projectors[i].projmat, offsetmat, tmpmat); - /* calculate worldspace projector normal (for best projector test) */ + /* Calculate world-space projector normal (for best projector test). */ projectors[i].normal[0] = 0; projectors[i].normal[1] = 0; projectors[i].normal[2] = 1; @@ -208,7 +208,7 @@ static Mesh *uvprojectModifier_do(UVProjectModifierData *umd, coords = BKE_mesh_vert_coords_alloc(mesh, &numVerts); - /* convert coords to world space */ + /* Convert coords to world-space. */ for (i = 0, co = coords; i < numVerts; i++, co++) { mul_m4_v3(ob->obmat, *co); } diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index f4ca9f51b1b..e256ebcff56 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -18,6 +18,8 @@ # All rights reserved. # ***** END GPL LICENSE BLOCK ***** +add_subdirectory(geometry) + set(INC . composite @@ -39,6 +41,7 @@ set(INC ../makesdna ../makesrna ../render + ../windowmanager ../../../intern/glew-mx ../../../intern/guardedalloc ../../../intern/sky/include @@ -154,148 +157,6 @@ set(SRC function/nodes/node_fn_value_to_string.cc function/node_function_util.cc - geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc - geometry/nodes/legacy/node_geo_attribute_clamp.cc - geometry/nodes/legacy/node_geo_attribute_color_ramp.cc - geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc - geometry/nodes/legacy/node_geo_attribute_compare.cc - geometry/nodes/legacy/node_geo_attribute_convert.cc - geometry/nodes/legacy/node_geo_attribute_curve_map.cc - geometry/nodes/legacy/node_geo_attribute_fill.cc - geometry/nodes/legacy/node_geo_attribute_map_range.cc - geometry/nodes/legacy/node_geo_attribute_math.cc - geometry/nodes/legacy/node_geo_attribute_mix.cc - geometry/nodes/legacy/node_geo_attribute_proximity.cc - geometry/nodes/legacy/node_geo_attribute_randomize.cc - geometry/nodes/legacy/node_geo_attribute_sample_texture.cc - geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc - geometry/nodes/legacy/node_geo_attribute_transfer.cc - geometry/nodes/legacy/node_geo_attribute_vector_math.cc - geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc - geometry/nodes/legacy/node_geo_curve_endpoints.cc - geometry/nodes/legacy/node_geo_curve_reverse.cc - geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc - geometry/nodes/legacy/node_geo_curve_set_handles.cc - geometry/nodes/legacy/node_geo_curve_spline_type.cc - geometry/nodes/legacy/node_geo_curve_subdivide.cc - geometry/nodes/legacy/node_geo_curve_to_points.cc - geometry/nodes/legacy/node_geo_delete_geometry.cc - geometry/nodes/legacy/node_geo_edge_split.cc - geometry/nodes/legacy/node_geo_material_assign.cc - geometry/nodes/legacy/node_geo_mesh_to_curve.cc - geometry/nodes/legacy/node_geo_point_distribute.cc - geometry/nodes/legacy/node_geo_point_instance.cc - geometry/nodes/legacy/node_geo_point_rotate.cc - geometry/nodes/legacy/node_geo_point_scale.cc - geometry/nodes/legacy/node_geo_point_separate.cc - geometry/nodes/legacy/node_geo_point_translate.cc - geometry/nodes/legacy/node_geo_points_to_volume.cc - geometry/nodes/legacy/node_geo_raycast.cc - geometry/nodes/legacy/node_geo_select_by_material.cc - geometry/nodes/legacy/node_geo_subdivision_surface.cc - geometry/nodes/legacy/node_geo_volume_to_mesh.cc - - geometry/nodes/node_geo_attribute_capture.cc - geometry/nodes/node_geo_attribute_remove.cc - geometry/nodes/node_geo_attribute_statistic.cc - geometry/nodes/node_geo_boolean.cc - geometry/nodes/node_geo_bounding_box.cc - geometry/nodes/node_geo_collection_info.cc - geometry/nodes/node_geo_common.cc - geometry/nodes/node_geo_convex_hull.cc - geometry/nodes/node_geo_curve_endpoint_selection.cc - geometry/nodes/node_geo_curve_fill.cc - geometry/nodes/node_geo_curve_fillet.cc - geometry/nodes/node_geo_curve_handle_type_selection.cc - geometry/nodes/node_geo_curve_length.cc - geometry/nodes/node_geo_curve_parameter.cc - geometry/nodes/node_geo_curve_primitive_bezier_segment.cc - geometry/nodes/node_geo_curve_primitive_circle.cc - geometry/nodes/node_geo_curve_primitive_line.cc - geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc - geometry/nodes/node_geo_curve_primitive_quadrilateral.cc - geometry/nodes/node_geo_curve_primitive_spiral.cc - geometry/nodes/node_geo_curve_primitive_star.cc - geometry/nodes/node_geo_curve_resample.cc - geometry/nodes/node_geo_curve_reverse.cc - geometry/nodes/node_geo_curve_sample.cc - geometry/nodes/node_geo_curve_set_handles.cc - geometry/nodes/node_geo_curve_spline_type.cc - geometry/nodes/node_geo_curve_subdivide.cc - geometry/nodes/node_geo_curve_to_mesh.cc - geometry/nodes/node_geo_curve_to_points.cc - geometry/nodes/node_geo_curve_trim.cc - geometry/nodes/node_geo_delete_geometry.cc - geometry/nodes/node_geo_distribute_points_on_faces.cc - geometry/nodes/node_geo_edge_split.cc - geometry/nodes/node_geo_image_texture.cc - geometry/nodes/node_geo_input_curve_handles.cc - geometry/nodes/node_geo_input_curve_tilt.cc - geometry/nodes/node_geo_input_id.cc - geometry/nodes/node_geo_input_index.cc - geometry/nodes/node_geo_input_material_index.cc - geometry/nodes/node_geo_input_material.cc - geometry/nodes/node_geo_input_normal.cc - geometry/nodes/node_geo_input_position.cc - geometry/nodes/node_geo_input_radius.cc - geometry/nodes/node_geo_input_shade_smooth.cc - geometry/nodes/node_geo_input_spline_cyclic.cc - geometry/nodes/node_geo_input_spline_length.cc - geometry/nodes/node_geo_input_spline_resolution.cc - geometry/nodes/node_geo_input_tangent.cc - geometry/nodes/node_geo_instance_on_points.cc - geometry/nodes/node_geo_instances_to_points.cc - geometry/nodes/node_geo_is_viewport.cc - geometry/nodes/node_geo_join_geometry.cc - geometry/nodes/node_geo_material_replace.cc - geometry/nodes/node_geo_material_selection.cc - geometry/nodes/node_geo_mesh_primitive_circle.cc - geometry/nodes/node_geo_mesh_primitive_cone.cc - geometry/nodes/node_geo_mesh_primitive_cube.cc - geometry/nodes/node_geo_mesh_primitive_cylinder.cc - geometry/nodes/node_geo_mesh_primitive_grid.cc - geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc - geometry/nodes/node_geo_mesh_primitive_line.cc - geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc - geometry/nodes/node_geo_mesh_subdivide.cc - geometry/nodes/node_geo_mesh_to_curve.cc - geometry/nodes/node_geo_mesh_to_points.cc - geometry/nodes/node_geo_object_info.cc - geometry/nodes/node_geo_points_to_vertices.cc - geometry/nodes/node_geo_points_to_volume.cc - geometry/nodes/node_geo_proximity.cc - geometry/nodes/node_geo_raycast.cc - geometry/nodes/node_geo_realize_instances.cc - geometry/nodes/node_geo_rotate_instances.cc - geometry/nodes/node_geo_scale_instances.cc - geometry/nodes/node_geo_separate_components.cc - geometry/nodes/node_geo_separate_geometry.cc - geometry/nodes/node_geo_set_curve_handles.cc - geometry/nodes/node_geo_set_curve_radius.cc - geometry/nodes/node_geo_set_curve_tilt.cc - geometry/nodes/node_geo_set_id.cc - geometry/nodes/node_geo_set_material_index.cc - geometry/nodes/node_geo_set_material.cc - geometry/nodes/node_geo_set_point_radius.cc - geometry/nodes/node_geo_set_position.cc - geometry/nodes/node_geo_set_shade_smooth.cc - geometry/nodes/node_geo_set_spline_cyclic.cc - geometry/nodes/node_geo_set_spline_resolution.cc - geometry/nodes/node_geo_string_join.cc - geometry/nodes/node_geo_string_to_curves.cc - geometry/nodes/node_geo_subdivision_surface.cc - geometry/nodes/node_geo_switch.cc - geometry/nodes/node_geo_transfer_attribute.cc - geometry/nodes/node_geo_transform.cc - geometry/nodes/node_geo_translate_instances.cc - geometry/nodes/node_geo_triangulate.cc - geometry/nodes/node_geo_viewer.cc - geometry/nodes/node_geo_volume_to_mesh.cc - - geometry/node_geometry_exec.cc - geometry/node_geometry_tree.cc - geometry/node_geometry_util.cc - shader/nodes/node_shader_add_shader.c shader/nodes/node_shader_ambient_occlusion.c shader/nodes/node_shader_attribute.c @@ -433,7 +294,6 @@ set(SRC composite/node_composite_util.hh function/node_function_util.hh shader/node_shader_util.h - geometry/node_geometry_util.hh texture/node_texture_util.h NOD_common.h @@ -462,8 +322,8 @@ set(SRC set(LIB bf_bmesh bf_functions - bf_geometry bf_intern_sky + bf_nodes_geometry ) if(WITH_BULLET) diff --git a/source/blender/nodes/NOD_common.h b/source/blender/nodes/NOD_common.h index 50ed992dcb6..fa979bb4799 100644 --- a/source/blender/nodes/NOD_common.h +++ b/source/blender/nodes/NOD_common.h @@ -45,6 +45,8 @@ struct bNodeSocket *node_group_output_find_socket(struct bNode *node, const char void node_group_input_update(struct bNodeTree *ntree, struct bNode *node); void node_group_output_update(struct bNodeTree *ntree, struct bNode *node); +void node_internal_links_create(struct bNodeTree *ntree, struct bNode *node); + #ifdef __cplusplus } #endif diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index 6e1f21dbae0..6b6e8a89240 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -57,13 +57,9 @@ using fn::GPointer; using fn::GSpan; using fn::GVArray; using fn::GVArray_GSpan; -using fn::GVArray_Span; -using fn::GVArray_Typed; -using fn::GVArrayPtr; using fn::GVMutableArray; using fn::GVMutableArray_GSpan; -using fn::GVMutableArray_Typed; -using fn::GVMutableArrayPtr; +using fn::ValueOrField; using geometry_nodes_eval_log::NodeWarningType; /** @@ -134,7 +130,7 @@ class GeoNodeExecParams { } template<typename T> - static inline constexpr bool is_stored_as_field_v = std::is_same_v<T, float> || + static inline constexpr bool is_field_base_type_v = std::is_same_v<T, float> || std::is_same_v<T, int> || std::is_same_v<T, bool> || std::is_same_v<T, ColorGeometry4f> || @@ -162,9 +158,15 @@ class GeoNodeExecParams { */ template<typename T> T extract_input(StringRef identifier) { - if constexpr (is_stored_as_field_v<T>) { - Field<T> field = this->extract_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->extract_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->extract_input<ValueOrField<BaseType>>( + identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -191,9 +193,9 @@ class GeoNodeExecParams { Vector<GMutablePointer> gvalues = provider_->extract_multi_input(identifier); Vector<T> values; for (GMutablePointer gvalue : gvalues) { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> field = gvalue.relocate_out<Field<T>>(); - values.append(fn::evaluate_constant_field(field)); + if constexpr (is_field_base_type_v<T>) { + const ValueOrField<T> value_or_field = gvalue.relocate_out<ValueOrField<T>>(); + values.append(value_or_field.as_value()); } else { values.append(gvalue.relocate_out<T>()); @@ -205,11 +207,16 @@ class GeoNodeExecParams { /** * Get the input value for the input socket with the given identifier. */ - template<typename T> const T get_input(StringRef identifier) const + template<typename T> T get_input(StringRef identifier) const { - if constexpr (is_stored_as_field_v<T>) { - const Field<T> &field = this->get_input<Field<T>>(identifier); - return fn::evaluate_constant_field(field); + if constexpr (is_field_base_type_v<T>) { + ValueOrField<T> value_or_field = this->get_input<ValueOrField<T>>(identifier); + return value_or_field.as_value(); + } + else if constexpr (fn::is_field_v<T>) { + using BaseType = typename T::base_type; + ValueOrField<BaseType> value_or_field = this->get_input<ValueOrField<BaseType>>(identifier); + return value_or_field.as_field(); } else { #ifdef DEBUG @@ -231,9 +238,12 @@ class GeoNodeExecParams { template<typename T> void set_output(StringRef identifier, T &&value) { using StoredT = std::decay_t<T>; - if constexpr (is_stored_as_field_v<StoredT>) { - this->set_output<Field<StoredT>>(identifier, - fn::make_constant_field<StoredT>(std::forward<T>(value))); + if constexpr (is_field_base_type_v<StoredT>) { + this->set_output(identifier, ValueOrField<StoredT>(std::forward<T>(value))); + } + else if constexpr (fn::is_field_v<StoredT>) { + using BaseType = typename StoredT::base_type; + this->set_output(identifier, ValueOrField<BaseType>(std::forward<T>(value))); } else { const CPPType &type = CPPType::get<StoredT>(); @@ -316,21 +326,21 @@ class GeoNodeExecParams { * \note This will add an error message if the string socket is active and * the input attribute does not exist. */ - GVArrayPtr get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const; + GVArray get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const; template<typename T> - GVArray_Typed<T> get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const T &default_value) const + VArray<T> get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const T &default_value) const { const CustomDataType type = bke::cpp_type_to_custom_data_type(CPPType::get<T>()); - GVArrayPtr varray = this->get_input_attribute(name, component, domain, type, &default_value); - return GVArray_Typed<T>(std::move(varray)); + GVArray varray = this->get_input_attribute(name, component, domain, type, &default_value); + return varray.typed<T>(); } /** diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh index 2a118057a03..0fbc1803db6 100644 --- a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh +++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh @@ -41,6 +41,8 @@ #include "NOD_derived_node_tree.hh" +#include <chrono> + struct SpaceNode; struct SpaceSpreadsheet; @@ -169,6 +171,11 @@ struct NodeWithWarning { NodeWarning warning; }; +struct NodeWithExecutionTime { + DNode node; + std::chrono::microseconds exec_time; +}; + /** The same value can be referenced by multiple sockets when they are linked. */ struct ValueOfSockets { Span<DSocket> sockets; @@ -189,6 +196,7 @@ class LocalGeoLogger { std::unique_ptr<LinearAllocator<>> allocator_; Vector<ValueOfSockets> values_; Vector<NodeWithWarning> node_warnings_; + Vector<NodeWithExecutionTime> node_exec_times_; friend ModifierLog; @@ -201,6 +209,7 @@ class LocalGeoLogger { void log_value_for_sockets(Span<DSocket> sockets, GPointer value); void log_multi_value_socket(DSocket socket, Span<GPointer> values); void log_node_warning(DNode node, NodeWarningType type, std::string message); + void log_execution_time(DNode node, std::chrono::microseconds exec_time); }; /** The root logger class. */ @@ -274,12 +283,14 @@ class NodeLog { Vector<SocketLog> input_logs_; Vector<SocketLog> output_logs_; Vector<NodeWarning, 0> warnings_; + std::chrono::microseconds exec_time_; friend ModifierLog; public: const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const; const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const; + void execution_time(std::chrono::microseconds exec_time); Span<SocketLog> input_logs() const { @@ -296,6 +307,11 @@ class NodeLog { return warnings_; } + std::chrono::microseconds execution_time() const + { + return exec_time_; + } + Vector<const GeometryAttributeInfo *> lookup_available_attributes() const; }; diff --git a/source/blender/nodes/NOD_node_declaration.hh b/source/blender/nodes/NOD_node_declaration.hh index e9f2996bb30..9b99026d6a7 100644 --- a/source/blender/nodes/NOD_node_declaration.hh +++ b/source/blender/nodes/NOD_node_declaration.hh @@ -228,7 +228,6 @@ class NodeDeclaration { friend NodeDeclarationBuilder; public: - void build(bNodeTree &ntree, bNode &node) const; bool matches(const bNode &node) const; Span<SocketDeclarationPtr> inputs() const; diff --git a/source/blender/nodes/NOD_type_conversions.hh b/source/blender/nodes/NOD_type_conversions.hh index ec4859f0657..c8b24fd1260 100644 --- a/source/blender/nodes/NOD_type_conversions.hh +++ b/source/blender/nodes/NOD_type_conversions.hh @@ -21,7 +21,6 @@ namespace blender::nodes { using fn::CPPType; -using fn::GVArray; struct ConversionFunctions { const fn::MultiFunction *multi_function; @@ -73,9 +72,9 @@ class DataTypeConversions { const void *from_value, void *to_value) const; - fn::GVArrayPtr try_convert(fn::GVArrayPtr varray, const CPPType &to_type) const; + fn::GVArray try_convert(fn::GVArray varray, const CPPType &to_type) const; - fn::GVMutableArrayPtr try_convert(fn::GVMutableArrayPtr varray, const CPPType &to_type) const; + fn::GVMutableArray try_convert(fn::GVMutableArray varray, const CPPType &to_type) const; }; const DataTypeConversions &get_implicit_type_conversions(); diff --git a/source/blender/nodes/composite/node_composite_util.cc b/source/blender/nodes/composite/node_composite_util.cc index 86aaec61bc3..21269b92e65 100644 --- a/source/blender/nodes/composite/node_composite_util.cc +++ b/source/blender/nodes/composite/node_composite_util.cc @@ -52,5 +52,4 @@ void cmp_node_type_base(bNodeType *ntype, int type, const char *name, short ncla ntype->poll = cmp_node_poll_default; ntype->updatefunc = cmp_node_update_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } diff --git a/source/blender/nodes/composite/nodes/node_composite_common.cc b/source/blender/nodes/composite/nodes/node_composite_common.cc index fecf6795ef7..6432a89ffa0 100644 --- a/source/blender/nodes/composite/nodes/node_composite_common.cc +++ b/source/blender/nodes/composite/nodes/node_composite_common.cc @@ -44,7 +44,6 @@ void register_node_type_cmp_group(void) ntype.poll = cmp_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("CompositorNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -66,7 +65,4 @@ void register_node_type_cmp_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index 4247e81e9b2..a1a49133a3a 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -43,8 +43,7 @@ void register_node_type_cmp_composite(void) cmp_node_type_base(&ntype, CMP_NODE_COMPOSITE, "Composite", NODE_CLASS_OUTPUT, NODE_PREVIEW); ntype.declare = blender::nodes::cmp_node_composite_declare; - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_image.cc b/source/blender/nodes/composite/nodes/node_composite_image.cc index 79cb0bd0f8c..40d4d4563c9 100644 --- a/source/blender/nodes/composite/nodes/node_composite_image.cc +++ b/source/blender/nodes/composite/nodes/node_composite_image.cc @@ -372,7 +372,8 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl for (sock = (bNodeSocket *)node->outputs.first; sock; sock = sock_next, sock_index++) { sock_next = sock->next; if (BLI_linklist_index(available_sockets.list, sock) >= 0) { - sock->flag &= ~(SOCK_UNAVAIL | SOCK_HIDDEN); + sock->flag &= ~SOCK_HIDDEN; + nodeSetSocketAvailability(ntree, sock, true); } else { bNodeLink *link; @@ -386,7 +387,7 @@ static void cmp_node_image_verify_outputs(bNodeTree *ntree, bNode *node, bool rl nodeRemoveSocket(ntree, node, sock); } else { - sock->flag |= SOCK_UNAVAIL; + nodeSetSocketAvailability(ntree, sock, false); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_scale.cc b/source/blender/nodes/composite/nodes/node_composite_scale.cc index 3972fc0d949..284d16b9b0d 100644 --- a/source/blender/nodes/composite/nodes/node_composite_scale.cc +++ b/source/blender/nodes/composite/nodes/node_composite_scale.cc @@ -32,7 +32,7 @@ static bNodeSocketTemplate cmp_node_scale_in[] = { {-1, ""}}; static bNodeSocketTemplate cmp_node_scale_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; -static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) +static void node_composite_update_scale(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; bool use_xy_scale = ELEM(node->custom1, CMP_SCALE_RELATIVE, CMP_SCALE_ABSOLUTE); @@ -40,12 +40,7 @@ static void node_composite_update_scale(bNodeTree *UNUSED(ntree), bNode *node) /* Only show X/Y scale factor inputs for modes using them! */ for (sock = (bNodeSocket *)node->inputs.first; sock; sock = sock->next) { if (STR_ELEM(sock->name, "X", "Y")) { - if (use_xy_scale) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, use_xy_scale); } } } diff --git a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc index 68c5ecdf48e..c0403a041db 100644 --- a/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_splitViewer.cc @@ -53,8 +53,7 @@ void register_node_type_cmp_splitviewer(void) node_type_init(&ntype, node_composit_init_splitviewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - /* Do not allow muting for this node. */ - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index 969e2409898..90f9882099b 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -59,7 +59,7 @@ void register_node_type_cmp_viewer(void) node_type_init(&ntype, node_composit_init_viewer); node_type_storage(&ntype, "ImageUser", node_free_standard_storage, node_copy_standard_storage); - node_type_internal_links(&ntype, nullptr); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc index 8ff8b416310..a1493d51a11 100644 --- a/source/blender/nodes/function/node_function_util.cc +++ b/source/blender/nodes/function/node_function_util.cc @@ -33,6 +33,5 @@ void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclas { node_type_base(ntype, type, name, nclass, flag); ntype->poll = fn_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc index b44e8d54ff1..ed03cc0025d 100644 --- a/source/blender/nodes/function/nodes/node_fn_boolean_math.cc +++ b/source/blender/nodes/function/nodes/node_fn_boolean_math.cc @@ -39,12 +39,12 @@ static void fn_node_boolean_math_layout(uiLayout *layout, bContext *UNUSED(C), P uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_boolean_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_boolean_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sockB, - ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); + nodeSetSocketAvailability( + ntree, sockB, ELEM(node->custom1, NODE_BOOLEAN_MATH_AND, NODE_BOOLEAN_MATH_OR)); } static void node_boolean_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen) diff --git a/source/blender/nodes/function/nodes/node_fn_float_compare.cc b/source/blender/nodes/function/nodes/node_fn_float_compare.cc index 2e1f2aaeeef..b31611a1df2 100644 --- a/source/blender/nodes/function/nodes/node_fn_float_compare.cc +++ b/source/blender/nodes/function/nodes/node_fn_float_compare.cc @@ -42,12 +42,14 @@ static void geo_node_float_compare_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void node_float_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_float_compare_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sockEpsilon = (bNodeSocket *)BLI_findlink(&node->inputs, 2); nodeSetSocketAvailability( - sockEpsilon, ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); + ntree, + sockEpsilon, + ELEM(node->custom1, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL)); } static void node_float_compare_label(bNodeTree *UNUSED(ntree), diff --git a/source/blender/nodes/function/nodes/node_fn_random_value.cc b/source/blender/nodes/function/nodes/node_fn_random_value.cc index d48b9f3461a..9720a39b740 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_value.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_value.cc @@ -63,7 +63,7 @@ static void fn_node_random_value_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_random_value_update(bNodeTree *ntree, bNode *node) { const NodeRandomValue &storage = *(const NodeRandomValue *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -81,18 +81,18 @@ static void fn_node_random_value_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *sock_out_int = sock_out_float->next; bNodeSocket *sock_out_bool = sock_out_int->next; - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_probability, data_type == CD_PROP_BOOL); - - nodeSetSocketAvailability(sock_out_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_out_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_out_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_out_bool, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_probability, data_type == CD_PROP_BOOL); + + nodeSetSocketAvailability(ntree, sock_out_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_out_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_out_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_out_bool, data_type == CD_PROP_BOOL); } class RandomVectorFunction : public fn::MultiFunction { diff --git a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc index fc4c3d8221f..7dbc11fb161 100644 --- a/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc +++ b/source/blender/nodes/function/nodes/node_fn_rotate_euler.cc @@ -36,18 +36,18 @@ static void fn_node_rotate_euler_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Rotation")); }; -static void fn_node_rotate_euler_update(bNodeTree *UNUSED(ntree), bNode *node) +static void fn_node_rotate_euler_update(bNodeTree *ntree, bNode *node) { bNodeSocket *rotate_by_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 1)); bNodeSocket *axis_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 2)); bNodeSocket *angle_socket = static_cast<bNodeSocket *>(BLI_findlink(&node->inputs, 3)); - nodeSetSocketAvailability(rotate_by_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); - nodeSetSocketAvailability(axis_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); - nodeSetSocketAvailability(angle_socket, - ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, rotate_by_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_EULER)); + nodeSetSocketAvailability( + ntree, axis_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); + nodeSetSocketAvailability( + ntree, angle_socket, ELEM(node->custom1, FN_NODE_ROTATE_EULER_TYPE_AXIS_ANGLE)); } static void fn_node_rotate_euler_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) diff --git a/source/blender/nodes/geometry/CMakeLists.txt b/source/blender/nodes/geometry/CMakeLists.txt new file mode 100644 index 00000000000..61b5bbf6e7e --- /dev/null +++ b/source/blender/nodes/geometry/CMakeLists.txt @@ -0,0 +1,267 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# +# ***** END GPL LICENSE BLOCK ***** + +set(INC + . + ../ + ../intern + ../../editors/include + ../../blenkernel + ../../blenlib + ../../blentranslation + ../../bmesh + ../../depsgraph + ../../functions + ../../geometry + ../../gpu + ../../imbuf + ../../makesdna + ../../makesrna + ../../render + ../../windowmanager + ../../../../intern/guardedalloc +) + + +set(SRC + nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc + nodes/legacy/node_geo_legacy_attribute_clamp.cc + nodes/legacy/node_geo_legacy_attribute_color_ramp.cc + nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc + nodes/legacy/node_geo_legacy_attribute_compare.cc + nodes/legacy/node_geo_legacy_attribute_convert.cc + nodes/legacy/node_geo_legacy_attribute_curve_map.cc + nodes/legacy/node_geo_legacy_attribute_fill.cc + nodes/legacy/node_geo_legacy_attribute_map_range.cc + nodes/legacy/node_geo_legacy_attribute_math.cc + nodes/legacy/node_geo_legacy_attribute_mix.cc + nodes/legacy/node_geo_legacy_attribute_proximity.cc + nodes/legacy/node_geo_legacy_attribute_randomize.cc + nodes/legacy/node_geo_legacy_attribute_sample_texture.cc + nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc + nodes/legacy/node_geo_legacy_attribute_transfer.cc + nodes/legacy/node_geo_legacy_attribute_vector_math.cc + nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc + nodes/legacy/node_geo_legacy_curve_endpoints.cc + nodes/legacy/node_geo_legacy_curve_reverse.cc + nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc + nodes/legacy/node_geo_legacy_curve_set_handles.cc + nodes/legacy/node_geo_legacy_curve_spline_type.cc + nodes/legacy/node_geo_legacy_curve_subdivide.cc + nodes/legacy/node_geo_legacy_curve_to_points.cc + nodes/legacy/node_geo_legacy_delete_geometry.cc + nodes/legacy/node_geo_legacy_edge_split.cc + nodes/legacy/node_geo_legacy_material_assign.cc + nodes/legacy/node_geo_legacy_mesh_to_curve.cc + nodes/legacy/node_geo_legacy_point_distribute.cc + nodes/legacy/node_geo_legacy_point_instance.cc + nodes/legacy/node_geo_legacy_point_rotate.cc + nodes/legacy/node_geo_legacy_point_scale.cc + nodes/legacy/node_geo_legacy_point_separate.cc + nodes/legacy/node_geo_legacy_point_translate.cc + nodes/legacy/node_geo_legacy_points_to_volume.cc + nodes/legacy/node_geo_legacy_raycast.cc + nodes/legacy/node_geo_legacy_select_by_material.cc + nodes/legacy/node_geo_legacy_subdivision_surface.cc + nodes/legacy/node_geo_legacy_volume_to_mesh.cc + + nodes/node_geo_attribute_capture.cc + nodes/node_geo_attribute_remove.cc + nodes/node_geo_attribute_statistic.cc + nodes/node_geo_boolean.cc + nodes/node_geo_bounding_box.cc + nodes/node_geo_collection_info.cc + nodes/node_geo_common.cc + nodes/node_geo_convex_hull.cc + nodes/node_geo_curve_endpoint_selection.cc + nodes/node_geo_curve_fill.cc + nodes/node_geo_curve_fillet.cc + nodes/node_geo_curve_handle_type_selection.cc + nodes/node_geo_curve_length.cc + nodes/node_geo_curve_parameter.cc + nodes/node_geo_curve_primitive_bezier_segment.cc + nodes/node_geo_curve_primitive_circle.cc + nodes/node_geo_curve_primitive_line.cc + nodes/node_geo_curve_primitive_quadratic_bezier.cc + nodes/node_geo_curve_primitive_quadrilateral.cc + nodes/node_geo_curve_primitive_spiral.cc + nodes/node_geo_curve_primitive_star.cc + nodes/node_geo_curve_resample.cc + nodes/node_geo_curve_reverse.cc + nodes/node_geo_curve_sample.cc + nodes/node_geo_curve_set_handles.cc + nodes/node_geo_curve_spline_type.cc + nodes/node_geo_curve_subdivide.cc + nodes/node_geo_curve_to_mesh.cc + nodes/node_geo_curve_to_points.cc + nodes/node_geo_curve_trim.cc + nodes/node_geo_delete_geometry.cc + nodes/node_geo_distribute_points_on_faces.cc + nodes/node_geo_edge_split.cc + nodes/node_geo_image_texture.cc + nodes/node_geo_input_curve_handles.cc + nodes/node_geo_input_curve_tilt.cc + nodes/node_geo_input_id.cc + nodes/node_geo_input_index.cc + nodes/node_geo_input_material_index.cc + nodes/node_geo_input_material.cc + nodes/node_geo_input_normal.cc + nodes/node_geo_input_position.cc + nodes/node_geo_input_radius.cc + nodes/node_geo_input_shade_smooth.cc + nodes/node_geo_input_spline_cyclic.cc + nodes/node_geo_input_spline_length.cc + nodes/node_geo_input_spline_resolution.cc + nodes/node_geo_input_tangent.cc + nodes/node_geo_instance_on_points.cc + nodes/node_geo_instances_to_points.cc + nodes/node_geo_is_viewport.cc + nodes/node_geo_join_geometry.cc + nodes/node_geo_material_replace.cc + nodes/node_geo_material_selection.cc + nodes/node_geo_mesh_primitive_circle.cc + nodes/node_geo_mesh_primitive_cone.cc + nodes/node_geo_mesh_primitive_cube.cc + nodes/node_geo_mesh_primitive_cylinder.cc + nodes/node_geo_mesh_primitive_grid.cc + nodes/node_geo_mesh_primitive_ico_sphere.cc + nodes/node_geo_mesh_primitive_line.cc + nodes/node_geo_mesh_primitive_uv_sphere.cc + nodes/node_geo_mesh_subdivide.cc + nodes/node_geo_mesh_to_curve.cc + nodes/node_geo_mesh_to_points.cc + nodes/node_geo_object_info.cc + nodes/node_geo_points_to_vertices.cc + nodes/node_geo_points_to_volume.cc + nodes/node_geo_proximity.cc + nodes/node_geo_raycast.cc + nodes/node_geo_realize_instances.cc + nodes/node_geo_rotate_instances.cc + nodes/node_geo_scale_instances.cc + nodes/node_geo_separate_components.cc + nodes/node_geo_separate_geometry.cc + nodes/node_geo_set_curve_handles.cc + nodes/node_geo_set_curve_radius.cc + nodes/node_geo_set_curve_tilt.cc + nodes/node_geo_set_id.cc + nodes/node_geo_set_material_index.cc + nodes/node_geo_set_material.cc + nodes/node_geo_set_point_radius.cc + nodes/node_geo_set_position.cc + nodes/node_geo_set_shade_smooth.cc + nodes/node_geo_set_spline_cyclic.cc + nodes/node_geo_set_spline_resolution.cc + nodes/node_geo_string_join.cc + nodes/node_geo_string_to_curves.cc + nodes/node_geo_subdivision_surface.cc + nodes/node_geo_switch.cc + nodes/node_geo_transfer_attribute.cc + nodes/node_geo_transform.cc + nodes/node_geo_translate_instances.cc + nodes/node_geo_triangulate.cc + nodes/node_geo_viewer.cc + nodes/node_geo_volume_to_mesh.cc + + node_geometry_exec.cc + node_geometry_tree.cc + node_geometry_util.cc + + node_geometry_util.hh +) + +set(LIB + bf_bmesh + bf_functions + bf_geometry +) + +if(WITH_BULLET) + list(APPEND INC_SYS + ${BULLET_INCLUDE_DIRS} + "../../../../intern/rigidbody/" + ) + if(NOT WITH_SYSTEM_BULLET) + list(APPEND LIB + extern_bullet + ) + endif() + + list(APPEND LIB + ${BULLET_LIBRARIES} + ) + add_definitions(-DWITH_BULLET) +endif() + +if(WITH_PYTHON) + list(APPEND INC + ../../python + ) + list(APPEND INC_SYS + ${PYTHON_INCLUDE_DIRS} + ) + list(APPEND LIB + ${PYTHON_LINKFLAGS} + ${PYTHON_LIBRARIES} + ) + add_definitions(-DWITH_PYTHON) +endif() + +if(WITH_INTERNATIONAL) + add_definitions(-DWITH_INTERNATIONAL) +endif() + +if(WITH_TBB) + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() +endif() + +if(WITH_IMAGE_OPENEXR) + add_definitions(-DWITH_OPENEXR) +endif() + +if(WITH_OPENSUBDIV) + add_definitions(-DWITH_OPENSUBDIV) +endif() + +if(WITH_GMP) + add_definitions(-DWITH_GMP) + + list(APPEND INC_SYS + ${GMP_INCLUDE_DIRS} + ) + + list(APPEND LIB + ${GMP_LIBRARIES} + ) +endif() + +if(WITH_OPENVDB) + list(APPEND INC_SYS + ${OPENVDB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_OPENVDB ${OPENVDB_DEFINITIONS}) +endif() + +blender_add_lib(bf_nodes_geometry "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 46e9d36c09c..5c1d507041c 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -35,7 +35,8 @@ using bke::GeometryInstanceGroup; * \param mode: Controls which socket of the group to make available. * \param name_is_available: If false, make all sockets with this name unavailable. */ -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available) @@ -50,7 +51,7 @@ void update_attribute_input_socket_availabilities(bNode &node, (socket->type == SOCK_INT && mode_ == GEO_NODE_ATTRIBUTE_INPUT_INTEGER) || (socket->type == SOCK_VECTOR && mode_ == GEO_NODE_ATTRIBUTE_INPUT_VECTOR) || (socket->type == SOCK_RGBA && mode_ == GEO_NODE_ATTRIBUTE_INPUT_COLOR)); - nodeSetSocketAvailability(socket, socket_is_available); + nodeSetSocketAvailability(&ntree, socket, socket_is_available); } } } @@ -72,6 +73,5 @@ void geo_node_type_base(bNodeType *ntype, int type, const char *name, short ncla { node_type_base(ntype, type, name, nclass, flag); ntype->poll = geo_node_poll_default; - ntype->update_internal_links = node_update_internal_links_default; ntype->insert_link = node_insert_link_default; } diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh index 167765fa131..79fe2ffc42b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.hh +++ b/source/blender/nodes/geometry/node_geometry_util.hh @@ -43,7 +43,8 @@ bool geo_node_poll_default(struct bNodeType *ntype, const char **r_disabled_hint); namespace blender::nodes { -void update_attribute_input_socket_availabilities(bNode &node, +void update_attribute_input_socket_availabilities(bNodeTree &ntree, + bNode &node, const StringRef name, const GeometryNodeAttributeInputMode mode, const bool name_is_available = true); @@ -67,13 +68,20 @@ Mesh *create_grid_mesh(const int verts_x, const float size_x, const float size_y); +struct ConeAttributeOutputs { + StrongAnonymousAttributeID top_id; + StrongAnonymousAttributeID bottom_id; + StrongAnonymousAttributeID side_id; +}; + Mesh *create_cylinder_or_cone_mesh(const float radius_top, const float radius_bottom, const float depth, const int circle_segments, const int side_segments, const int fill_segments, - const GeometryNodeMeshCircleFillType fill_type); + const GeometryNodeMeshCircleFillType fill_type, + ConeAttributeOutputs &attribute_outputs); Mesh *create_cuboid_mesh(float3 size, int verts_x, int verts_y, int verts_z); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc index b92d4704d63..5a5b0dbee9a 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_align_rotation_to_vector.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_align_rotation_to_vector.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc { -static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -40,9 +40,7 @@ static void geo_node_align_rotation_to_vector_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "axis", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -53,7 +51,7 @@ static void geo_node_align_rotation_to_vector_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_vector", 0, IFACE_("Vector"), ICON_NONE); } -static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) MEM_callocN(sizeof(NodeGeometryAlignRotationToVector), __func__); @@ -65,14 +63,14 @@ static void geo_node_align_rotation_to_vector_init(bNodeTree *UNUSED(ntree), bNo node->storage = node_storage; } -static void geo_node_align_rotation_to_vector_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryAlignRotationToVector *node_storage = (NodeGeometryAlignRotationToVector *) node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); } static void align_rotations_auto_pivot(const VArray<float3> &vectors, @@ -179,9 +177,9 @@ static void align_rotations_on_component(GeometryComponent &component, return; } - GVArray_Typed<float> factors = params.get_input_attribute<float>( + VArray<float> factors = params.get_input_attribute<float>( "Factor", component, ATTR_DOMAIN_POINT, 1.0f); - GVArray_Typed<float3> vectors = params.get_input_attribute<float3>( + VArray<float3> vectors = params.get_input_attribute<float3>( "Vector", component, ATTR_DOMAIN_POINT, {0, 0, 1}); float3 local_main_axis{0, 0, 0}; @@ -199,7 +197,7 @@ static void align_rotations_on_component(GeometryComponent &component, rotations.save(); } -static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -219,10 +217,12 @@ static void geo_node_align_rotation_to_vector_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_align_rotation_to_vector_cc void register_node_type_geo_align_rotation_to_vector() { + namespace file_ns = blender::nodes::node_geo_legacy_align_rotation_to_vector_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -230,14 +230,14 @@ void register_node_type_geo_align_rotation_to_vector() "Align Rotation to Vector", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_align_rotation_to_vector_init); - node_type_update(&ntype, blender::nodes::geo_node_align_rotation_to_vector_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryAlignRotationToVector", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_align_rotation_to_vector_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_align_rotation_to_vector_exec; - ntype.draw_buttons = blender::nodes::geo_node_align_rotation_to_vector_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc index 91ff114a480..40af5b7ec82 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_clamp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_clamp.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_clamp_cc { -static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -38,13 +38,13 @@ static void geo_node_attribute_clamp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), __func__); @@ -53,7 +53,7 @@ static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -66,14 +66,14 @@ static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *nod const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, sock_max_color, data_type == CD_PROP_COLOR); } template<typename T> T clamp_value(const T val, const T min, const T max); @@ -156,7 +156,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); const int operation = static_cast<int>(storage.operation); - GVArrayPtr attribute_input = component.attribute_try_get_for_read( + GVArray attribute_input = component.attribute_try_get_for_read( attribute_name, domain, data_type); OutputAttribute attribute_result = component.attribute_try_get_for_output_only( @@ -185,7 +185,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } } MutableSpan<float3> results = attribute_result.as_span<float3>(); - clamp_attribute<float3>(attribute_input->typed<float3>(), results, min, max); + clamp_attribute<float3>(attribute_input.typed<float3>(), results, min, max); break; } case CD_PROP_FLOAT: { @@ -193,10 +193,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const float max = params.get_input<float>("Max_001"); MutableSpan<float> results = attribute_result.as_span<float>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<float>(attribute_input->typed<float>(), results, max, min); + clamp_attribute<float>(attribute_input.typed<float>(), results, max, min); } else { - clamp_attribute<float>(attribute_input->typed<float>(), results, min, max); + clamp_attribute<float>(attribute_input.typed<float>(), results, min, max); } break; } @@ -205,10 +205,10 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam const int max = params.get_input<int>("Max_002"); MutableSpan<int> results = attribute_result.as_span<int>(); if (operation == NODE_CLAMP_RANGE && min > max) { - clamp_attribute<int>(attribute_input->typed<int>(), results, max, min); + clamp_attribute<int>(attribute_input.typed<int>(), results, max, min); } else { - clamp_attribute<int>(attribute_input->typed<int>(), results, min, max); + clamp_attribute<int>(attribute_input.typed<int>(), results, min, max); } break; } @@ -231,7 +231,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam } MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); clamp_attribute<ColorGeometry4f>( - attribute_input->typed<ColorGeometry4f>(), results, min, max); + attribute_input.typed<ColorGeometry4f>(), results, min, max); break; } default: { @@ -243,7 +243,7 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam attribute_result.save(); } -static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -262,19 +262,21 @@ static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_clamp_cc void register_node_type_geo_attribute_clamp() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_clamp_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_clamp_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_clamp_update); - ntype.declare = blender::nodes::geo_node_attribute_clamp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_clamp_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc index ab4b6aad545..66790acb712 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_color_ramp.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_color_ramp.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc { -static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -33,14 +33,12 @@ static void geo_node_attribute_color_ramp_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_color_ramp_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiTemplateColorRamp(layout, ptr, "color_ramp", false); } -static void geo_node_attribute_color_ramp_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeColorRamp *node_storage = (NodeAttributeColorRamp *)MEM_callocN( sizeof(NodeAttributeColorRamp), __func__); @@ -85,7 +83,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon return; } - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, 0.0f); MutableSpan<ColorGeometry4f> results = attribute_result.as_span(); @@ -100,7 +98,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -119,10 +117,12 @@ static void geo_node_attribute_color_ramp_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attributes_color_ramp_cc void register_node_type_geo_attribute_color_ramp() { + namespace file_ns = blender::nodes::node_geo_legacy_attributes_color_ramp_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,10 +132,10 @@ void register_node_type_geo_attribute_color_ramp() 0); node_type_storage( &ntype, "NodeAttributeColorRamp", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_color_ramp_init); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_color_ramp_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_color_ramp_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_color_ramp_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc index d4c23380b4e..f8320c57f92 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_combine_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_combine_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc { -static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("X")); @@ -34,9 +34,7 @@ static void geo_node_attribute_combine_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -46,7 +44,7 @@ static void geo_node_attribute_combine_xyz_layout(uiLayout *layout, uiItemR(col, ptr, "input_type_z", 0, IFACE_("Z"), ICON_NONE); } -static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCombineXYZ *data = (NodeAttributeCombineXYZ *)MEM_callocN( sizeof(NodeAttributeCombineXYZ), __func__); @@ -57,15 +55,15 @@ static void geo_node_attribute_combine_xyz_init(bNodeTree *UNUSED(tree), bNode * node->storage = data; } -static void geo_node_attribute_combine_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCombineXYZ *node_storage = (NodeAttributeCombineXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); + *ntree, *node, "X", (GeometryNodeAttributeInputMode)node_storage->input_type_x); update_attribute_input_socket_availabilities( - *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); + *ntree, *node, "Y", (GeometryNodeAttributeInputMode)node_storage->input_type_y); update_attribute_input_socket_availabilities( - *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); + *ntree, *node, "Z", (GeometryNodeAttributeInputMode)node_storage->input_type_z); } static AttributeDomain get_result_domain(const GeometryComponent &component, @@ -95,11 +93,11 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa if (!attribute_result) { return; } - GVArray_Typed<float> attribute_x = params.get_input_attribute<float>( + VArray<float> attribute_x = params.get_input_attribute<float>( "X", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_y = params.get_input_attribute<float>( + VArray<float> attribute_y = params.get_input_attribute<float>( "Y", component, result_domain, 0.0f); - GVArray_Typed<float> attribute_z = params.get_input_attribute<float>( + VArray<float> attribute_z = params.get_input_attribute<float>( "Z", component, result_domain, 0.0f); for (const int i : IndexRange(attribute_result->size())) { @@ -111,7 +109,7 @@ static void combine_attributes(GeometryComponent &component, const GeoNodeExecPa attribute_result.save(); } -static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -130,10 +128,12 @@ static void geo_node_attribute_combine_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_combine_xyz_cc void register_node_type_geo_attribute_combine_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_combine_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -141,13 +141,13 @@ void register_node_type_geo_attribute_combine_xyz() "Attribute Combine XYZ", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_combine_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_combine_xyz_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCombineXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_combine_xyz_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_combine_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_combine_xyz_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc index e4e43a7b724..e64f41cca72 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_compare.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_compare.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_compare_cc { -static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -39,9 +39,7 @@ static void geo_node_attribute_compare_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_compare_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); uiLayoutSetPropSep(layout, true); @@ -50,7 +48,7 @@ static void geo_node_attribute_compare_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_compare_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeCompare *data = (NodeAttributeCompare *)MEM_callocN(sizeof(NodeAttributeCompare), __func__); @@ -65,16 +63,16 @@ static bool operation_tests_equality(const NodeAttributeCompare &node_storage) return ELEM(node_storage.operation, NODE_FLOAT_COMPARE_EQUAL, NODE_FLOAT_COMPARE_NOT_EQUAL); } -static void geo_node_attribute_compare_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeCompare *node_storage = (NodeAttributeCompare *)node->storage; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); bNodeSocket *socket_threshold = (bNodeSocket *)BLI_findlink(&node->inputs, 9); - nodeSetSocketAvailability(socket_threshold, operation_tests_equality(*node_storage)); + nodeSetSocketAvailability(ntree, socket_threshold, operation_tests_equality(*node_storage)); } static void do_math_operation(const VArray<float> &input_a, @@ -257,9 +255,9 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx const CustomDataType input_data_type = get_data_type(component, params, *node_storage); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, input_data_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, input_data_type, nullptr); if (!attribute_a || !attribute_b) { @@ -276,53 +274,53 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx if (operation == NODE_FLOAT_COMPARE_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } else if (operation == NODE_FLOAT_COMPARE_NOT_EQUAL) { if (input_data_type == CD_PROP_FLOAT) { do_not_equal_operation_float( - attribute_a->typed<float>(), attribute_b->typed<float>(), threshold, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), threshold, result_span); } else if (input_data_type == CD_PROP_FLOAT3) { do_not_equal_operation_float3( - attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span); + attribute_a.typed<float3>(), attribute_b.typed<float3>(), threshold, result_span); } else if (input_data_type == CD_PROP_COLOR) { - do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(), - attribute_b->typed<ColorGeometry4f>(), + do_not_equal_operation_color4f(attribute_a.typed<ColorGeometry4f>(), + attribute_b.typed<ColorGeometry4f>(), threshold, result_span); } else if (input_data_type == CD_PROP_BOOL) { do_not_equal_operation_bool( - attribute_a->typed<bool>(), attribute_b->typed<bool>(), threshold, result_span); + attribute_a.typed<bool>(), attribute_b.typed<bool>(), threshold, result_span); } } } else { do_math_operation( - attribute_a->typed<float>(), attribute_b->typed<float>(), operation, result_span); + attribute_a.typed<float>(), attribute_b.typed<float>(), operation, result_span); } attribute_result.save(); } -static void geo_node_attribute_compare_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -341,20 +339,22 @@ static void geo_node_attribute_compare_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_compare_cc void register_node_type_geo_attribute_compare() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_compare_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_COMPARE, "Attribute Compare", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_compare_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_compare_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_compare_layout; - node_type_update(&ntype, blender::nodes::geo_node_attribute_compare_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeCompare", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_compare_init); + node_type_init(&ntype, file_ns::node_init); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc index dc05fa2c125..1f241e1f20e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_convert.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_convert.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_convert_cc { -static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -29,9 +29,7 @@ static void geo_node_attribute_convert_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_convert_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -39,7 +37,7 @@ static void geo_node_attribute_convert_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_convert_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeConvert *data = (NodeAttributeConvert *)MEM_callocN(sizeof(NodeAttributeConvert), __func__); @@ -104,7 +102,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArrayPtr source_attribute = component.attribute_try_get_for_read( + GVArray source_attribute = component.attribute_try_get_for_read( source_name, result_domain, result_type); if (!source_attribute) { params.error_message_add(NodeWarningType::Error, @@ -118,7 +116,7 @@ static void attribute_convert_calc(GeometryComponent &component, return; } - GVArray_GSpan source_span{*source_attribute}; + GVArray_GSpan source_span{source_attribute}; GMutableSpan result_span = result_attribute.as_span(); BLI_assert(source_span.size() == result_span.size()); @@ -130,7 +128,7 @@ static void attribute_convert_calc(GeometryComponent &component, result_attribute.save(); } -static void geo_node_attribute_convert_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -175,18 +173,20 @@ static void geo_node_attribute_convert_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_convert_cc void register_node_type_geo_attribute_convert() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_convert_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CONVERT, "Attribute Convert", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_convert_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_convert_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_convert_layout; - node_type_init(&ntype, blender::nodes::geo_node_attribute_convert_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeConvert", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc index 669ac21436f..8c8b43825ec 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_curve_map.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_curve_map.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc { -static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -34,9 +34,7 @@ static void geo_node_attribute_curve_map_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_curve_map_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); bNode *node = (bNode *)ptr->data; @@ -54,7 +52,7 @@ static void geo_node_attribute_curve_map_layout(uiLayout *layout, } } -static void geo_node_attribute_curve_map_free_storage(bNode *node) +static void node_free_storage(bNode *node) { if (node->storage) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -64,9 +62,9 @@ static void geo_node_attribute_curve_map_free_storage(bNode *node) } } -static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntree), - bNode *dest_node, - const bNode *src_node) +static void node_copy_storage(bNodeTree *UNUSED(dest_ntree), + bNode *dest_node, + const bNode *src_node) { dest_node->storage = MEM_dupallocN(src_node->storage); NodeAttributeCurveMap *src_data = (NodeAttributeCurveMap *)src_node->storage; @@ -75,7 +73,7 @@ static void geo_node_attribute_curve_map_copy_storage(bNodeTree *UNUSED(dest_ntr dest_data->curve_rgb = BKE_curvemapping_copy(src_data->curve_rgb); } -static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)MEM_callocN(sizeof(NodeAttributeCurveMap), __func__); @@ -87,7 +85,7 @@ static void geo_node_attribute_curve_map_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_curve_map_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *UNUSED(ntree), bNode *node) { /* Set the active curve when data type is changed. */ NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)node->storage; @@ -136,10 +134,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (result_type) { case CD_PROP_FLOAT: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>( + VArray<float> attribute_in = component.attribute_get_for_read<float>( input_name, result_domain, float(0.0f)); MutableSpan<float> results = attribute_result.as_span<float>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { results[i] = BKE_curvemapping_evaluateF(cumap, 3, attribute_in[i]); } @@ -148,10 +146,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_FLOAT3: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_vec; - GVArray_Typed<float3> attribute_in = component.attribute_get_for_read<float3>( + VArray<float3> attribute_in = component.attribute_get_for_read<float3>( input_name, result_domain, float3(0.0f)); MutableSpan<float3> results = attribute_result.as_span<float3>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluate3F(cumap, results[i], attribute_in[i]); } @@ -160,11 +158,10 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } case CD_PROP_COLOR: { const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb; - GVArray_Typed<ColorGeometry4f> attribute_in = - component.attribute_get_for_read<ColorGeometry4f>( - input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); + VArray<ColorGeometry4f> attribute_in = component.attribute_get_for_read<ColorGeometry4f>( + input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>(); - threading::parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) { + threading::parallel_for(attribute_in.index_range(), 512, [&](IndexRange range) { for (const int i : range) { BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]); } @@ -180,7 +177,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &bnode = params.node(); NodeAttributeCurveMap *data = (NodeAttributeCurveMap *)bnode.storage; @@ -204,23 +201,23 @@ static void geo_node_attribute_curve_map_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_curve_map_cc void register_node_type_geo_attribute_curve_map() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_curve_map_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_CURVE_MAP, "Attribute Curve Map", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_curve_map_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_curve_map_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_storage(&ntype, - "NodeAttributeCurveMap", - blender::nodes::geo_node_attribute_curve_map_free_storage, - blender::nodes::geo_node_attribute_curve_map_copy_storage); - ntype.declare = blender::nodes::geo_node_attribute_curve_map_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_curve_map_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_curve_map_layout; + node_type_storage( + &ntype, "NodeAttributeCurveMap", file_ns::node_free_storage, file_ns::node_copy_storage); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc index 5cb49dd83d0..e84c35eeada 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_fill.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_fill.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_fill_cc { -static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).is_attribute_name(); @@ -33,7 +33,7 @@ static void geo_node_attribute_fill_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -41,13 +41,13 @@ static void geo_node_attribute_fill_layout(uiLayout *layout, bContext *UNUSED(C) uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_fill_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_AUTO; } -static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_value_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *socket_value_float = socket_value_vector->next; @@ -57,11 +57,11 @@ static void geo_node_attribute_fill_update(bNodeTree *UNUSED(ntree), bNode *node const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); } static AttributeDomain get_result_domain(const GeometryComponent &component, const StringRef name) @@ -127,7 +127,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams attribute.save(); } -static void geo_node_attribute_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -146,18 +146,20 @@ static void geo_node_attribute_fill_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_fill_cc void register_node_type_geo_attribute_fill() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_fill_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_FILL, "Attribute Fill", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_fill_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_fill_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_fill_layout; - ntype.declare = blender::nodes::geo_node_attribute_fill_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc index 978c75187fe..8ebcf34ad0b 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_map_range.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_map_range.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_map_range_cc { -static void geo_node_attribute_map_range_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -49,7 +49,7 @@ static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); } -static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), __func__); @@ -58,7 +58,7 @@ static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; @@ -78,23 +78,26 @@ static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); - nodeSetSocketAvailability(sock_clamp, + nodeSetSocketAvailability(ntree, + sock_clamp, node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR || node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_steps_float, + nodeSetSocketAvailability(ntree, sock_from_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_from_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_to_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, + sock_steps_float, data_type == CD_PROP_FLOAT && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); - nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_steps_vector, + nodeSetSocketAvailability(ntree, sock_from_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_from_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_to_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, + sock_steps_vector, data_type == CD_PROP_FLOAT3 && node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); } @@ -362,7 +365,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP const AttributeDomain domain = get_result_domain(component, input_name, result_name); - GVArrayPtr attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); + GVArray attribute_input = component.attribute_try_get_for_read(input_name, domain, data_type); if (!attribute_input) { params.error_message_add(NodeWarningType::Error, @@ -381,12 +384,12 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP switch (data_type) { case CD_PROP_FLOAT: { - map_range_float(attribute_input->typed<float>(), attribute_result.as_span<float>(), params); + map_range_float(attribute_input.typed<float>(), attribute_result.as_span<float>(), params); break; } case CD_PROP_FLOAT3: { map_range_float3( - attribute_input->typed<float3>(), attribute_result.as_span<float3>(), params); + attribute_input.typed<float3>(), attribute_result.as_span<float3>(), params); break; } default: @@ -396,7 +399,7 @@ static void map_range_attribute(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -413,20 +416,22 @@ static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_map_range_cc void register_node_type_geo_attribute_map_range() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_map_range_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec; - node_type_init(&ntype, blender::nodes::geo_node_attribute_map_range_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_map_range_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_map_range_declare; - ntype.draw_buttons = blender::nodes::fn_attribute_map_range_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::fn_attribute_map_range_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc index 55d35f87cda..11f06adcf50 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_math.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_math_cc { -static void geo_node_attribute_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -100,7 +100,7 @@ static bool operation_use_input_b(const NodeMathOperation operation) return false; } -static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; @@ -119,7 +119,7 @@ static void geo_node_attribute_math_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), __func__); @@ -141,19 +141,21 @@ static void geo_node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *lab BLI_strncpy(label, IFACE_(name), maxlen); } -static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage.input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage.input_type_c, @@ -250,7 +252,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP return; } - GVArray_Typed<float> attribute_a = params.get_input_attribute<float>( + VArray<float> attribute_a = params.get_input_attribute<float>( "A", component, result_domain, 0.0f); MutableSpan<float> result_span = attribute_result.as_span(); @@ -258,10 +260,10 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP /* Note that passing the data with `get_internal_span<float>()` works * because the attributes were accessed with #CD_PROP_FLOAT. */ if (operation_use_input_b(operation)) { - GVArray_Typed<float> attribute_b = params.get_input_attribute<float>( + VArray<float> attribute_b = params.get_input_attribute<float>( "B", component, result_domain, 0.0f); if (operation_use_input_c(operation)) { - GVArray_Typed<float> attribute_c = params.get_input_attribute<float>( + VArray<float> attribute_c = params.get_input_attribute<float>( "C", component, result_domain, 0.0f); do_math_operation(attribute_a, attribute_b, attribute_c, result_span, operation); } @@ -276,7 +278,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP attribute_result.save(); } -static void geo_node_attribute_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -295,20 +297,22 @@ static void geo_node_attribute_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_math_cc void register_node_type_geo_attribute_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_math_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MATH, "Attribute Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_label(&ntype, file_ns::geo_node_math_label); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeMath", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc index b4205bc91b7..e99c75dbd68 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_mix.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_mix.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_mix_cc { -static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -48,7 +48,7 @@ static void geo_node_mix_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -59,7 +59,7 @@ static void geo_node_attribute_mix_layout(uiLayout *layout, bContext *UNUSED(C), uiItemR(col, ptr, "input_type_b", 0, IFACE_("B"), ICON_NONE); } -static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeMix *data = (NodeAttributeMix *)MEM_callocN(sizeof(NodeAttributeMix), "attribute mix node"); @@ -70,15 +70,15 @@ static void geo_node_attribute_mix_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_attribute_mix_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeMix *node_storage = (NodeAttributeMix *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage->input_type_factor); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); } static void do_mix_operation_float(const int blend_mode, @@ -144,25 +144,28 @@ static void do_mix_operation(const CustomDataType result_type, GVMutableArray &attribute_result) { if (result_type == CD_PROP_FLOAT) { + VMutableArray<float> result = attribute_result.typed<float>(); do_mix_operation_float(blend_mode, attribute_factor, attribute_a.typed<float>(), attribute_b.typed<float>(), - attribute_result.typed<float>()); + result); } else if (result_type == CD_PROP_FLOAT3) { + VMutableArray<float3> result = attribute_result.typed<float3>(); do_mix_operation_float3(blend_mode, attribute_factor, attribute_a.typed<float3>(), attribute_b.typed<float3>(), - attribute_result.typed<float3>()); + result); } else if (result_type == CD_PROP_COLOR) { + VMutableArray<ColorGeometry4f> result = attribute_result.typed<ColorGeometry4f>(); do_mix_operation_color4f(blend_mode, attribute_factor, attribute_a.typed<ColorGeometry4f>(), attribute_b.typed<ColorGeometry4f>(), - attribute_result.typed<ColorGeometry4f>()); + result); } } @@ -203,23 +206,23 @@ static void attribute_mix_calc(GeometryComponent &component, const GeoNodeExecPa return; } - GVArray_Typed<float> attribute_factor = params.get_input_attribute<float>( + VArray<float> attribute_factor = params.get_input_attribute<float>( "Factor", component, result_domain, 0.5f); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - GVArrayPtr attribute_b = params.get_input_attribute( + GVArray attribute_b = params.get_input_attribute( "B", component, result_domain, result_type, nullptr); do_mix_operation(result_type, node_storage->blend_type, attribute_factor, - *attribute_a, - *attribute_b, - *attribute_result); + attribute_a, + attribute_b, + attribute_result.varray()); attribute_result.save(); } -static void geo_node_attribute_mix_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -238,19 +241,21 @@ static void geo_node_attribute_mix_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_mix_cc void register_node_type_geo_attribute_mix() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_mix_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_MIX, "Attribute Mix", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_mix_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_mix_update); - ntype.declare = blender::nodes::geo_node_mix_attribute_declare; - ntype.draw_buttons = blender::nodes::geo_node_attribute_mix_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeMix", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_mix_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc index 9e3a7984c53..9090503924e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_proximity.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_proximity.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_proximity_cc { -static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target")); @@ -37,14 +37,12 @@ static void geo_node_attribute_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_proximity_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_geometry_element", 0, "", ICON_NONE); } -static void geo_attribute_proximity_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryAttributeProximity *node_storage = (NodeGeometryAttributeProximity *)MEM_callocN( sizeof(NodeGeometryAttributeProximity), __func__); @@ -153,7 +151,7 @@ static void attribute_calc_proximity(GeometryComponent &component, if (!position_attribute || (!distance_attribute && !location_attribute)) { return; } - GVArray_Typed<float3> positions{*position_attribute.varray}; + VArray<float3> positions = position_attribute.varray.typed<float3>(); const NodeGeometryAttributeProximity &storage = *(const NodeGeometryAttributeProximity *)params.node().storage; @@ -203,7 +201,7 @@ static void attribute_calc_proximity(GeometryComponent &component, } } -static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); @@ -230,22 +228,24 @@ static void geo_node_attribute_proximity_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_proximity_cc void register_node_type_geo_legacy_attribute_proximity() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_proximity_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_PROXIMITY, "Attribute Proximity", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_attribute_proximity_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc index 2901472d661..8fb05d031a6 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_randomize.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_randomize.cc @@ -25,7 +25,41 @@ namespace blender::nodes { -static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder &b) +Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, + const AttributeDomain domain) +{ + const int domain_size = component.attribute_domain_size(domain); + + /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ + GVArray hash_attribute = component.attribute_try_get_for_read("id", domain); + Array<uint32_t> hashes(domain_size); + if (hash_attribute) { + BLI_assert(hashes.size() == hash_attribute.size()); + const CPPType &cpp_type = hash_attribute.type(); + BLI_assert(cpp_type.is_hashable()); + GVArray_GSpan items{hash_attribute}; + threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { + for (const int i : range) { + hashes[i] = cpp_type.hash(items[i]); + } + }); + } + else { + /* If there is no "id" attribute for per-point variation, just create it here. */ + RandomNumberGenerator rng(0); + for (const int i : hashes.index_range()) { + hashes[i] = rng.get_uint32(); + } + } + + return hashes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_attribute_randomize_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")); @@ -39,15 +73,13 @@ static void geo_node_legacy_attribute_randomize_declare(NodeDeclarationBuilder & b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_legacy_attribute_random_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeRandomize *data = (NodeAttributeRandomize *)MEM_callocN( sizeof(NodeAttributeRandomize), __func__); @@ -57,7 +89,7 @@ static void geo_node_legacy_attribute_randomize_init(bNodeTree *UNUSED(tree), bN node->storage = data; } -static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_max_vector = sock_min_vector->next; @@ -68,12 +100,12 @@ static void geo_node_legacy_attribute_randomize_update(bNodeTree *UNUSED(ntree), const NodeAttributeRandomize &storage = *(const NodeAttributeRandomize *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); - nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, sock_max_int, data_type == CD_PROP_INT32); } template<typename T> @@ -174,36 +206,6 @@ static void randomize_attribute_bool(MutableSpan<bool> span, }); } -Array<uint32_t> get_geometry_element_ids_as_uints(const GeometryComponent &component, - const AttributeDomain domain) -{ - const int domain_size = component.attribute_domain_size(domain); - - /* Hash the reserved name attribute "id" as a (hopefully) stable seed for each point. */ - GVArrayPtr hash_attribute = component.attribute_try_get_for_read("id", domain); - Array<uint32_t> hashes(domain_size); - if (hash_attribute) { - BLI_assert(hashes.size() == hash_attribute->size()); - const CPPType &cpp_type = hash_attribute->type(); - BLI_assert(cpp_type.is_hashable()); - GVArray_GSpan items{*hash_attribute}; - threading::parallel_for(hashes.index_range(), 512, [&](IndexRange range) { - for (const int i : range) { - hashes[i] = cpp_type.hash(items[i]); - } - }); - } - else { - /* If there is no "id" attribute for per-point variation, just create it here. */ - RandomNumberGenerator rng(0); - for (const int i : hashes.index_range()) { - hashes[i] = rng.get_uint32(); - } - } - - return hashes; -} - static AttributeDomain get_result_domain(const GeometryComponent &component, const GeoNodeExecParams ¶ms, const StringRef name) @@ -280,7 +282,7 @@ static void randomize_attribute_on_component(GeometryComponent &component, attribute.save(); } -static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const std::string attribute_name = params.get_input<std::string>("Attribute"); @@ -324,20 +326,22 @@ static void geo_node_legacy_random_attribute_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_randomize_cc void register_node_type_geo_legacy_attribute_randomize() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_randomize_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_RANDOMIZE, "Attribute Randomize", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_init); - node_type_update(&ntype, blender::nodes::geo_node_legacy_attribute_randomize_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); - ntype.declare = blender::nodes::geo_node_legacy_attribute_randomize_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_random_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_legacy_attribute_random_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeAttributeRandomize", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc index 19d6ced6eb6..70fa0af956f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_sample_texture.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_sample_texture.cc @@ -28,9 +28,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc { -static void geo_node_attribute_sample_texture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Texture>(N_("Texture")).hide_label(); @@ -82,7 +82,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec return; } - GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>( + VArray<float3> mapping_attribute = component.attribute_get_for_read<float3>( mapping_name, result_domain, {0, 0, 0}); MutableSpan<ColorGeometry4f> colors = attribute_out.as_span(); @@ -100,7 +100,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec attribute_out.save(); } -static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -119,10 +119,12 @@ static void geo_node_attribute_sample_texture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_sample_texture_cc void register_node_type_geo_sample_texture() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_sample_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -131,7 +133,7 @@ void register_node_type_geo_sample_texture() NODE_CLASS_ATTRIBUTE, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.declare = blender::nodes::geo_node_attribute_sample_texture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_sample_texture_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc index 809e75e73a3..04de44446af 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_separate_xyz.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_separate_xyz.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc { -static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -32,16 +32,14 @@ static void geo_node_attribute_separate_xyz_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_separate_xyz_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeSeparateXYZ *data = (NodeAttributeSeparateXYZ *)MEM_callocN( sizeof(NodeAttributeSeparateXYZ), __func__); @@ -49,11 +47,11 @@ static void geo_node_attribute_separate_xyz_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_attribute_separate_xyz_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeAttributeSeparateXYZ *node_storage = (NodeAttributeSeparateXYZ *)node->storage; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type); } static void extract_input(const int index, const Span<float3> &input, MutableSpan<float> result) @@ -106,9 +104,9 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa const AttributeDomain result_domain = get_result_domain( component, params, result_name_x, result_name_y, result_name_z); - GVArray_Typed<float3> attribute_input = params.get_input_attribute<float3>( + VArray<float3> attribute_input = params.get_input_attribute<float3>( "Vector", component, result_domain, {0, 0, 0}); - VArray_Span<float3> input_span{*attribute_input}; + VArray_Span<float3> input_span{attribute_input}; OutputAttribute_Typed<float> attribute_result_x = component.attribute_try_get_for_output_only<float>(result_name_x, result_domain); @@ -132,7 +130,7 @@ static void separate_attribute(GeometryComponent &component, const GeoNodeExecPa } } -static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -151,10 +149,12 @@ static void geo_node_attribute_separate_xyz_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_separate_xyz_cc void register_node_type_geo_attribute_separate_xyz() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_separate_xyz_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -162,12 +162,12 @@ void register_node_type_geo_attribute_separate_xyz() "Attribute Separate XYZ", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_separate_xyz_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_separate_xyz_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_separate_xyz_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeAttributeSeparateXYZ", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_separate_xyz_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_separate_xyz_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc index 3a9cd52661a..afdadee97c7 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_transfer.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_transfer.cc @@ -29,9 +29,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_transfer_cc { -static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Source Geometry")); @@ -40,9 +40,7 @@ static void geo_node_attribute_transfer_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_transfer_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +48,7 @@ static void geo_node_attribute_transfer_layout(uiLayout *layout, uiItemR(layout, ptr, "mapping", 0, IFACE_("Mapping"), ICON_NONE); } -static void geo_node_attribute_transfer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeTransfer *data = (NodeGeometryAttributeTransfer *)MEM_callocN( sizeof(NodeGeometryAttributeTransfer), __func__); @@ -407,13 +405,13 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, if (pointcloud_distances_sq[i] < mesh_distances_sq[i]) { /* Point-cloud point is closer. */ const int index = pointcloud_indices[i]; - pointcloud_src_attribute.varray->get(index, buffer); + pointcloud_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } else { /* Mesh element is closer. */ const int index = mesh_indices[i]; - mesh_src_attribute.varray->get(index, buffer); + mesh_src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -424,7 +422,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, src_name, data_type); for (const int i : IndexRange(tot_samples)) { const int index = pointcloud_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -434,7 +432,7 @@ static void transfer_attribute_nearest(const GeometrySet &src_geometry, data_type); for (const int i : IndexRange(tot_samples)) { const int index = mesh_indices[i]; - src_attribute.varray->get(index, buffer); + src_attribute.varray.get(index, buffer); dst_attribute->set_by_relocate(i, buffer); } } @@ -460,7 +458,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, const AttributeDomain dst_domain = (input_domain == ATTR_DOMAIN_AUTO) ? auto_domain : input_domain; - GVArray_Typed<float3> dst_positions = dst_component.attribute_get_for_read<float3>( + VArray<float3> dst_positions = dst_component.attribute_get_for_read<float3>( "position", dst_domain, {0, 0, 0}); switch (mapping) { @@ -477,7 +475,7 @@ static void transfer_attribute(const GeoNodeExecParams ¶ms, } } -static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet dst_geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet src_geometry_set = params.extract_input<GeometrySet>("Source Geometry"); @@ -510,21 +508,23 @@ static void geo_node_attribute_transfer_exec(GeoNodeExecParams params) params.set_output("Geometry", dst_geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_transfer_cc void register_node_type_geo_legacy_attribute_transfer() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_transfer_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_ATTRIBUTE_TRANSFER, "Attribute Transfer", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_attribute_transfer_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryAttributeTransfer", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_attribute_transfer_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_transfer_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_transfer_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc index 4c351846243..1bd1712f22d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_math.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_math.cc @@ -26,9 +26,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc { -static void geo_node_attribute_vector_math_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("A")); @@ -66,9 +66,7 @@ static bool operation_use_input_c(const NodeVectorMathOperation operation) NODE_VECTOR_MATH_MULTIPLY_ADD); } -static void geo_node_attribute_vector_math_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorMath &node_storage = *(NodeAttributeVectorMath *)node->storage; @@ -103,7 +101,7 @@ static CustomDataType operation_get_read_type_c(const NodeVectorMathOperation op return CD_PROP_FLOAT3; } -static void geo_node_attribute_vector_math_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeAttributeVectorMath *data = (NodeAttributeVectorMath *)MEM_callocN( sizeof(NodeAttributeVectorMath), __func__); @@ -166,19 +164,21 @@ static void geo_node_vector_math_label(bNodeTree *UNUSED(ntree), BLI_snprintf(label, maxlen, IFACE_("Vector %s"), IFACE_(name)); } -static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorMath *node_storage = (NodeAttributeVectorMath *)node->storage; const NodeVectorMathOperation operation = (const NodeVectorMathOperation)node_storage->operation; update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *ntree, *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); update_attribute_input_socket_availabilities( + *ntree, *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b, operation_use_input_b(operation)); update_attribute_input_socket_availabilities( + *ntree, *node, "C", (GeometryNodeAttributeInputMode)node_storage->input_type_c, @@ -187,7 +187,7 @@ static void geo_node_attribute_vector_math_update(bNodeTree *UNUSED(ntree), bNod static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -218,7 +218,7 @@ static void do_math_operation_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float3> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -251,7 +251,7 @@ static void do_math_operation_fl3_fl3_fl3_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float3> &input_b, const VArray<float> &input_c, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -283,7 +283,7 @@ static void do_math_operation_fl3_fl3_fl_to_fl3(const VArray<float3> &input_a, static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, const VArray<float3> &input_b, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -313,7 +313,7 @@ static void do_math_operation_fl3_fl3_to_fl(const VArray<float3> &input_a, static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, const VArray<float> &input_b, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -342,7 +342,7 @@ static void do_math_operation_fl3_fl_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, - VMutableArray<float3> &result, + const VMutableArray<float3> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -369,7 +369,7 @@ static void do_math_operation_fl3_to_fl3(const VArray<float3> &input_a, } static void do_math_operation_fl3_to_fl(const VArray<float3> &input_a, - VMutableArray<float> &result, + const VMutableArray<float> &result, const NodeVectorMathOperation operation) { const int size = input_a.size(); @@ -437,13 +437,13 @@ static void attribute_vector_math_calc(GeometryComponent &component, const AttributeDomain result_domain = get_result_domain( component, params, operation, result_name); - GVArrayPtr attribute_a = params.get_input_attribute( + GVArray attribute_a = params.get_input_attribute( "A", component, result_domain, read_type_a, nullptr); if (!attribute_a) { return; } - GVArrayPtr attribute_b; - GVArrayPtr attribute_c; + GVArray attribute_b; + GVArray attribute_c; if (use_input_b) { attribute_b = params.get_input_attribute("B", component, result_domain, read_type_b, nullptr); if (!attribute_b) { @@ -476,26 +476,26 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_MODULO: case NODE_VECTOR_MATH_MINIMUM: case NODE_VECTOR_MATH_MAXIMUM: - do_math_operation_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_DOT_PRODUCT: case NODE_VECTOR_MATH_DISTANCE: - do_math_operation_fl3_fl3_to_fl(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_result->typed<float>(), + do_math_operation_fl3_fl3_to_fl(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_LENGTH: do_math_operation_fl3_to_fl( - attribute_a->typed<float3>(), attribute_result->typed<float>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float>(), operation); break; case NODE_VECTOR_MATH_SCALE: - do_math_operation_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_NORMALIZE: @@ -507,29 +507,29 @@ static void attribute_vector_math_calc(GeometryComponent &component, case NODE_VECTOR_MATH_COSINE: case NODE_VECTOR_MATH_TANGENT: do_math_operation_fl3_to_fl3( - attribute_a->typed<float3>(), attribute_result->typed<float3>(), operation); + attribute_a.typed<float3>(), attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_WRAP: case NODE_VECTOR_MATH_FACEFORWARD: case NODE_VECTOR_MATH_MULTIPLY_ADD: - do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float3>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float3>(), + attribute_result.varray().typed<float3>(), operation); break; case NODE_VECTOR_MATH_REFRACT: - do_math_operation_fl3_fl3_fl_to_fl3(attribute_a->typed<float3>(), - attribute_b->typed<float3>(), - attribute_c->typed<float>(), - attribute_result->typed<float3>(), + do_math_operation_fl3_fl3_fl_to_fl3(attribute_a.typed<float3>(), + attribute_b.typed<float3>(), + attribute_c.typed<float>(), + attribute_result.varray().typed<float3>(), operation); break; } attribute_result.save(); } -static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -549,10 +549,12 @@ static void geo_node_attribute_vector_math_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_math_cc void register_node_type_geo_attribute_vector_math() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_math_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -560,12 +562,12 @@ void register_node_type_geo_attribute_vector_math() "Attribute Vector Math", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_vector_math_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_math_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_math_layout; - node_type_label(&ntype, blender::nodes::geo_node_vector_math_label); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_math_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_math_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_label(&ntype, file_ns::geo_node_vector_math_label); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeAttributeVectorMath", node_free_standard_storage, node_copy_standard_storage); diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc index 9ab8ec25fb6..309518e58ce 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_attribute_vector_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_attribute_vector_rotate.cc @@ -21,9 +21,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc { -static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Vector")); @@ -42,9 +42,7 @@ static void geo_node_attribute_vector_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; const NodeAttributeVectorRotate &node_storage = *(NodeAttributeVectorRotate *)node->storage; @@ -70,27 +68,30 @@ static void geo_node_attribute_vector_rotate_layout(uiLayout *layout, } } -static void geo_node_attribute_vector_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)node->storage; const GeometryNodeAttributeVectorRotateMode mode = (const GeometryNodeAttributeVectorRotateMode) node_storage->mode; update_attribute_input_socket_availabilities( - *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); + *ntree, *node, "Vector", (GeometryNodeAttributeInputMode)node_storage->input_type_vector); update_attribute_input_socket_availabilities( - *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); + *ntree, *node, "Center", (GeometryNodeAttributeInputMode)node_storage->input_type_center); update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, (mode == GEO_NODE_VECTOR_ROTATE_TYPE_AXIS)); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, (mode != GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -109,7 +110,7 @@ static float3 vector_rotate_around_axis(const float3 vector, return result + center; } -static void geo_node_attribute_vector_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeAttributeVectorRotate *node_storage = (NodeAttributeVectorRotate *)MEM_callocN( sizeof(NodeAttributeVectorRotate), __func__); @@ -220,12 +221,12 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon const AttributeDomain result_domain = get_result_domain(component, params, result_name); const bool invert = params.get_input<bool>("Invert"); - GVArrayPtr attribute_vector = params.get_input_attribute( + GVArray attribute_vector = params.get_input_attribute( "Vector", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_vector) { return; } - GVArrayPtr attribute_center = params.get_input_attribute( + GVArray attribute_center = params.get_input_attribute( "Center", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_center) { return; @@ -238,21 +239,21 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon } if (mode == GEO_NODE_VECTOR_ROTATE_TYPE_EULER_XYZ) { - GVArrayPtr attribute_rotation = params.get_input_attribute( + GVArray attribute_rotation = params.get_input_attribute( "Rotation", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_rotation) { return; } - do_vector_rotate_euler(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_rotation->typed<float3>(), + do_vector_rotate_euler(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_rotation.typed<float3>(), attribute_result.as_span<float3>(), invert); attribute_result.save(); return; } - GVArrayPtr attribute_angle = params.get_input_attribute( + GVArray attribute_angle = params.get_input_attribute( "Angle", component, result_domain, CD_PROP_FLOAT, nullptr); if (!attribute_angle) { return; @@ -260,40 +261,40 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon switch (mode) { case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS: { - GVArrayPtr attribute_axis = params.get_input_attribute( + GVArray attribute_axis = params.get_input_attribute( "Axis", component, result_domain, CD_PROP_FLOAT3, nullptr); if (!attribute_axis) { return; } - do_vector_rotate_around_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), - attribute_axis->typed<float3>(), - attribute_angle->typed<float>(), + do_vector_rotate_around_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), + attribute_axis.typed<float3>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); } break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_X: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(1.0f, 0.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Y: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 1.0f, 0.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); break; case GEO_NODE_VECTOR_ROTATE_TYPE_AXIS_Z: - do_vector_rotate_around_fixed_axis(attribute_vector->typed<float3>(), - attribute_center->typed<float3>(), + do_vector_rotate_around_fixed_axis(attribute_vector.typed<float3>(), + attribute_center.typed<float3>(), float3(0.0f, 0.0f, 1.0f), - attribute_angle->typed<float>(), + attribute_angle.typed<float>(), attribute_result.as_span<float3>(), invert); @@ -306,7 +307,7 @@ static void execute_on_component(const GeoNodeExecParams ¶ms, GeometryCompon attribute_result.save(); } -static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -325,10 +326,12 @@ static void geo_node_attribute_vector_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_attribute_vector_rotate_cc void register_node_type_geo_attribute_vector_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_attribute_vector_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -336,13 +339,13 @@ void register_node_type_geo_attribute_vector_rotate() "Attribute Vector Rotate", NODE_CLASS_ATTRIBUTE, 0); - node_type_update(&ntype, blender::nodes::geo_node_attribute_vector_rotate_update); - node_type_init(&ntype, blender::nodes::geo_node_attribute_vector_rotate_init); + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_size(&ntype, 165, 100, 600); node_type_storage( &ntype, "NodeAttributeVectorRotate", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_vector_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_vector_rotate_layout; - ntype.declare = blender::nodes::geo_node_attribute_vector_rotate_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc index 8b81008ff34..184f39ba094 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_endpoints.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_endpoints.cc @@ -25,9 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_endpoints_cc { -static void geo_node_curve_endpoints_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Start Points")); @@ -61,7 +61,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( @@ -70,7 +70,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, /* Only copy the attributes of splines in the offsets. */ for (const int i : offsets.index_range()) { - spline_attribute->get(offsets[i], result[i]); + spline_attribute.get(offsets[i], result[i]); } result_attribute.save(); @@ -130,7 +130,7 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]); + spline_span.type().copy_assign(spline_span[0], point_span[i]); } for (const auto item : end_data.point_attributes.items()) { @@ -139,13 +139,13 @@ static void copy_endpoint_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]); + spline_span.type().copy_assign(spline_span[spline.size() - 1], point_span[i]); } } }); } -static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -206,16 +206,18 @@ static void geo_node_curve_endpoints_exec(GeoNodeExecParams params) params.set_output("End Points", std::move(end_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_endpoints_cc void register_node_type_geo_legacy_curve_endpoints() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_endpoints_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoints_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc index ba76fafe3e6..cfc67e13a8d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_reverse.cc @@ -20,16 +20,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); geometry_set = bke::geometry_set_realize_instances(geometry_set); @@ -44,7 +44,7 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { @@ -58,14 +58,16 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_reverse_cc void register_node_type_geo_legacy_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_REVERSE, "Curve Reverse", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc index 40d827ae141..a839c53c855 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_select_by_handle_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_select_by_handle_type.cc @@ -23,24 +23,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc { -static void geo_node_select_by_handle_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_select_by_handle_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_select_by_handle_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -94,7 +92,7 @@ static void select_curve_by_handle_type(const CurveEval &curve, }); } -static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSelectHandles *storage = (const NodeGeometryCurveSelectHandles *)params.node().storage; @@ -121,10 +119,12 @@ static void geo_node_select_by_handle_type_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc void register_node_type_geo_legacy_select_by_handle_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_select_by_handle_type_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -132,14 +132,14 @@ void register_node_type_geo_legacy_select_by_handle_type() "Select by Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_select_by_handle_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_select_by_handle_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_select_by_handle_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_select_by_handle_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc index 4bac9cb976e..fbc56adf44c 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_set_handles.cc @@ -21,24 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_set_handles_cc { -static void geo_node_curve_set_handles_decalre(NodeDeclarationBuilder &b) +static void node_decalre(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSetHandles *node_storage = (NodeGeometryCurveSetHandles *)params.node().storage; @@ -84,7 +82,7 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) MutableSpan<SplinePtr> splines = curve.splines(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component.attribute_get_for_read( + VArray<bool> selection = curve_component.attribute_get_for_read( selection_name, ATTR_DOMAIN_POINT, true); const BezierSpline::HandleType new_handle_type = handle_type_from_input_type(type); @@ -124,21 +122,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_set_handles_cc void register_node_type_geo_legacy_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_decalre; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_decalre; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc index df53c96e6ca..7c76f97c97f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_spline_type.cc @@ -23,23 +23,21 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_curve_spline_type_cc { -static void geo_node_legacy_curve_spline_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_legacy_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,7 +236,7 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType *storage = (const NodeGeometryCurveSplineType *)params.node().storage; @@ -255,7 +253,7 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) const CurveEval &curve = *curve_component->get_for_read(); const std::string selection_name = params.extract_input<std::string>("Selection"); - GVArray_Typed<bool> selection = curve_component->attribute_get_for_read( + VArray<bool> selection = curve_component->attribute_get_for_read( selection_name, ATTR_DOMAIN_CURVE, true); std::unique_ptr<CurveEval> new_curve = std::make_unique<CurveEval>(); @@ -282,21 +280,23 @@ static void geo_node_legacy_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(new_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_spline_type_cc void register_node_type_geo_legacy_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_legacy_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_legacy_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc index f9b0a9d128e..b7cddb927f8 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_subdivide.cc @@ -25,13 +25,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_legacy_curve_subdivide_cc { -namespace blender::nodes { - -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Cuts")); @@ -39,14 +35,14 @@ static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_subdivide_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "cuts_type", 0, IFACE_("Cuts"), ICON_NONE); } -static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSubdivide *data = (NodeGeometryCurveSubdivide *)MEM_callocN( sizeof(NodeGeometryCurveSubdivide), __func__); @@ -55,12 +51,12 @@ static void geo_node_curve_subdivide_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_subdivide_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Cuts", (GeometryNodeAttributeInputMode)node_storage.input_type); } static Array<int> get_subdivided_offsets(const Spline &spline, @@ -351,7 +347,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -363,34 +359,35 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) } const CurveComponent &component = *geometry_set.get_component_for_read<CurveComponent>(); - GVArray_Typed<int> cuts = params.get_input_attribute<int>( - "Cuts", component, ATTR_DOMAIN_POINT, 0); - if (cuts->is_single() && cuts->get_internal_single() < 1) { + VArray<int> cuts = params.get_input_attribute<int>("Cuts", component, ATTR_DOMAIN_POINT, 0); + if (cuts.is_single() && cuts.get_internal_single() < 1) { params.set_output("Geometry", geometry_set); return; } - std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), *cuts); + std::unique_ptr<CurveEval> output_curve = subdivide_curve(*component.get_for_read(), cuts); params.set_output("Geometry", GeometrySet::create_with_curve(output_curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_subdivide_cc void register_node_type_geo_legacy_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_SUBDIVIDE, "Curve Subdivide", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_subdivide_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage(&ntype, "NodeGeometryCurveSubdivide", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_subdivide_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_subdivide_update); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc index c171d485a6a..a64443261ae 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_curve_to_points.cc @@ -28,7 +28,59 @@ namespace blender::nodes { -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id, + const CustomDataType data_type) +{ + points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); + WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); + BLI_assert(attribute); + return attribute.varray.get_internal_span(); +} + +template<typename T> +static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, + const AttributeIDRef &attribute_id) +{ + GMutableSpan attribute = create_attribute_and_retrieve_span( + points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); + return attribute.typed<T>(); +} + +CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, + const CurveEval &curve) +{ + CurveToPointsResults attributes; + + attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); + + attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); + attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); + attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); + + /* Because of the invariants of the curve component, we use the attributes of the + * first spline as a representative for the attribute meta data all splines. */ + curve.splines().first()->attributes.foreach_attribute( + [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { + attributes.point_attributes.add_new( + attribute_id, + create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); + return true; + }, + ATTR_DOMAIN_POINT); + + attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); + attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); + attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); + + return attributes; +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_curve_to_points_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); @@ -36,12 +88,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -50,7 +102,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -58,8 +110,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } /** @@ -114,54 +166,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, return {0}; } -static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id, - const CustomDataType data_type) -{ - points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); - WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); - BLI_assert(attribute); - return attribute.varray->get_internal_span(); -} - -template<typename T> -static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &points, - const AttributeIDRef &attribute_id) -{ - GMutableSpan attribute = create_attribute_and_retrieve_span( - points, attribute_id, bke::cpp_type_to_custom_data_type(CPPType::get<T>())); - return attribute.typed<T>(); -} - -CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points, - const CurveEval &curve) -{ - CurveToPointsResults attributes; - - attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT); - - attributes.positions = create_attribute_and_retrieve_span<float3>(points, "position"); - attributes.radii = create_attribute_and_retrieve_span<float>(points, "radius"); - attributes.tilts = create_attribute_and_retrieve_span<float>(points, "tilt"); - - /* Because of the invariants of the curve component, we use the attributes of the - * first spline as a representative for the attribute meta data all splines. */ - curve.splines().first()->attributes.foreach_attribute( - [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { - attributes.point_attributes.add_new( - attribute_id, - create_attribute_and_retrieve_span(points, attribute_id, meta_data.data_type)); - return true; - }, - ATTR_DOMAIN_POINT); - - attributes.tangents = create_attribute_and_retrieve_span<float3>(points, "tangent"); - attributes.normals = create_attribute_and_retrieve_span<float3>(points, "normal"); - attributes.rotations = create_attribute_and_retrieve_span<float3>(points, "rotation"); - - return attributes; -} - /** * TODO: For non-poly splines, this has double copies that could be avoided as part * of a general look at optimizing uses of #Spline::interpolate_to_evaluated. @@ -177,8 +181,8 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); - spline.interpolate_to_evaluated(spline.tilts())->materialize(data.tilts.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.tilts()).materialize(data.tilts.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -188,7 +192,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines, GSpan spline_span = *spline.attributes.get_for_read(attribute_id); spline.interpolate_to_evaluated(spline_span) - ->materialize(point_span.slice(offset, size).data()); + .materialize(point_span.slice(offset, size).data()); } data.tangents.slice(offset, size).copy_from(spline.evaluated_tangents()); @@ -230,7 +234,7 @@ static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, point_span.slice(offset, size)); } @@ -263,20 +267,20 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, if (meta_data.domain != ATTR_DOMAIN_CURVE) { return true; } - GVArrayPtr spline_attribute = curve_component.attribute_get_for_read( + GVArray spline_attribute = curve_component.attribute_get_for_read( attribute_id, ATTR_DOMAIN_CURVE, meta_data.data_type); - const CPPType &type = spline_attribute->type(); + const CPPType &type = spline_attribute.type(); OutputAttribute result_attribute = points.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, meta_data.data_type); GMutableSpan result = result_attribute.as_span(); - for (const int i : IndexRange(spline_attribute->size())) { + for (const int i : spline_attribute.index_range()) { const int offset = offsets[i]; const int size = offsets[i + 1] - offsets[i]; if (size != 0) { BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - spline_attribute->get(i, buffer); + spline_attribute.get(i, buffer); type.fill_assign_n(buffer, result[offset], size); } } @@ -286,7 +290,7 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component, }); } -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -340,21 +344,23 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_curve_to_points_cc void register_node_type_geo_legacy_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_legacy_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc index 1d76a0532a1..0ae5766a27d 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_delete_geometry.cc @@ -29,23 +29,23 @@ using blender::bke::CustomDataAttributes; /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); - -namespace blender::nodes { - -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); + +namespace blender::nodes::node_geo_legacy_delete_geometry_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Selection")); @@ -137,7 +137,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, Vector<int64_t> copied_splines; if (input_curve.attributes.get_for_read(name)) { - GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = input_curve.attributes.get_for_read<bool>(name, false); for (const int i : input_splines.index_range()) { if (selection[i] == invert) { output_curve->add_spline(input_splines[i]->copy()); @@ -151,7 +151,7 @@ static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve, for (const int i : input_splines.index_range()) { const Spline &spline = *input_splines[i]; - GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false); + VArray<bool> selection = spline.attributes.get_for_read<bool>(name, false); indices_to_copy.clear(); for (const int i_point : IndexRange(spline.size())) { @@ -202,7 +202,7 @@ static void delete_point_cloud_selection(const PointCloudComponent &in_component const StringRef selection_name, const bool invert) { - const GVArray_Typed<bool> selection_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> selection_attribute = in_component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> selection{selection_attribute}; @@ -590,7 +590,7 @@ static void delete_mesh_selection(MeshComponent &component, const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name); /* This already checks if the attribute exists, and displays a warning in that case. */ - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, selection_domain, false); /* Check if there is anything to delete. */ @@ -627,7 +627,7 @@ static void delete_mesh_selection(MeshComponent &component, component.replace(mesh_out); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); geometry_set = bke::geometry_set_realize_instances(geometry_set); @@ -662,16 +662,18 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(out_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_delete_geometry_cc void register_node_type_geo_legacy_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_legacy_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc index 8f2bf05d2b4..0a510105f5f 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_edge_split.cc @@ -22,9 +22,9 @@ extern "C" { Mesh *doEdgeSplit(const Mesh *mesh, EdgeSplitModifierData *emd); } -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Edge Angle")).default_value(true); @@ -37,7 +37,7 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -76,14 +76,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_edge_split_cc void register_node_type_geo_legacy_edge_split() { + namespace file_ns = blender::nodes::node_geo_legacy_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_EDGE_SPLIT, "Edge Split", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc index 333a17aa4e9..00833e81c29 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_material_assign.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_material_assign.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_material_assign_cc { -static void geo_node_legacy_material_assign_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(true); @@ -59,7 +59,7 @@ static void assign_material_to_faces(Mesh &mesh, const VArray<bool> &face_mask, } } -static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string mask_name = params.extract_input<std::string>("Selection"); @@ -72,7 +72,7 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>(); Mesh *mesh = mesh_component.get_for_write(); if (mesh != nullptr) { - GVArray_Typed<bool> face_mask = mesh_component.attribute_get_for_read<bool>( + VArray<bool> face_mask = mesh_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_FACE, true); assign_material_to_faces(*mesh, face_mask, material); } @@ -81,15 +81,17 @@ static void geo_node_legacy_material_assign_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_material_assign_cc void register_node_type_geo_legacy_material_assign() { + namespace file_ns = blender::nodes::node_geo_legacy_material_assign_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MATERIAL_ASSIGN, "Material Assign", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_material_assign_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_material_assign_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc index 9167096fd3d..e384124d3e1 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_mesh_to_curve.cc @@ -18,16 +18,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")); b.add_input<decl::String>(N_("Selection")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -44,7 +44,7 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + selection_name + "\""); } - GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>( + VArray<bool> selection = component.attribute_get_for_read<bool>( selection_name, ATTR_DOMAIN_EDGE, true); Vector<int64_t> selected_edge_indices; @@ -65,15 +65,17 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_mesh_to_curve_cc void register_node_type_geo_legacy_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_legacy_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc index 210757f986d..d62f3536680 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_distribute.cc @@ -36,11 +36,11 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_legacy_point_distribute_cc { -namespace blender::nodes { +using blender::bke::GeometryInstanceGroup; -static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Distance Min")).min(0.0f).max(100000.0f).subtype(PROP_DISTANCE); @@ -54,18 +54,17 @@ static void geo_node_point_distribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_distribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_min_dist = (bNodeSocket *)BLI_findlink(&node->inputs, 1); - nodeSetSocketAvailability(sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); + nodeSetSocketAvailability( + ntree, sock_min_dist, ELEM(node->custom1, GEO_NODE_POINT_DISTRIBUTE_POISSON)); } /** @@ -106,9 +105,9 @@ static void sample_mesh_surface(const Mesh &mesh, float looptri_density_factor = 1.0f; if (density_factors != nullptr) { - const float v0_density_factor = std::max(0.0f, density_factors->get(v0_loop)); - const float v1_density_factor = std::max(0.0f, density_factors->get(v1_loop)); - const float v2_density_factor = std::max(0.0f, density_factors->get(v2_loop)); + const float v0_density_factor = std::max(0.0f, (*density_factors)[v0_loop]); + const float v1_density_factor = std::max(0.0f, (*density_factors)[v1_loop]); + const float v2_density_factor = std::max(0.0f, (*density_factors)[v2_loop]); looptri_density_factor = (v0_density_factor + v1_density_factor + v2_density_factor) / 3.0f; } const float area = area_tri_v3(v0_pos, v1_pos, v2_pos); @@ -315,7 +314,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( } const AttributeDomain source_domain = attribute_info->domain; - GVArrayPtr source_attribute = source_component.attribute_get_for_read( + GVArray source_attribute = source_component.attribute_get_for_read( attribute_id, source_domain, output_data_type, nullptr); if (!source_attribute) { i_instance += set_group.transforms.size(); @@ -329,7 +328,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( GMutableSpan instance_span = out_span.slice(offset, bary_coords.size()); interpolate_attribute( - mesh, bary_coords, looptri_indices, source_domain, *source_attribute, instance_span); + mesh, bary_coords, looptri_indices, source_domain, source_attribute, instance_span); i_instance++; } @@ -337,7 +336,7 @@ BLI_NOINLINE static void interpolate_existing_attributes( attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> source_span{*source_attribute}; + VArray_Span source_span{source_attribute.typed<T>()}; }); } @@ -445,7 +444,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, for (const GeometryInstanceGroup &set_group : set_groups) { const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); const Mesh &mesh = *component.get_for_read(); for (const float4x4 &transform : set_group.transforms) { @@ -455,7 +454,7 @@ static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, sample_mesh_surface(mesh, transform, density, - &*density_factors, + &density_factors, seed, positions, bary_coords, @@ -514,7 +513,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group const GeometrySet &set = set_group.geometry_set; const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); const Mesh &mesh = *component.get_for_read(); - const GVArray_Typed<float> density_factors = component.attribute_get_for_read<float>( + const VArray<float> density_factors = component.attribute_get_for_read<float>( density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { @@ -540,7 +539,7 @@ static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_group } } -static void geo_node_point_distribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -654,17 +653,19 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_distribute_cc void register_node_type_geo_point_distribute() { + namespace file_ns = blender::nodes::node_geo_legacy_point_distribute_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_DISTRIBUTE, "Point Distribute", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_update); - ntype.declare = blender::nodes::geo_node_point_distribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_layout; + node_type_update(&ntype, file_ns::node_point_distribute_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc index ffb2a0dd7ac..be8294cda90 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_instance.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_instance_cc { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Object>(N_("Object")).hide_label(); @@ -36,7 +36,7 @@ static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "instance_type", 0, "", ICON_NONE); if (RNA_enum_get(ptr, "instance_type") == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION) { @@ -44,7 +44,7 @@ static void geo_node_point_instance_layout(uiLayout *layout, bContext *UNUSED(C) } } -static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointInstance *data = (NodeGeometryPointInstance *)MEM_callocN( sizeof(NodeGeometryPointInstance), __func__); @@ -53,7 +53,7 @@ static void geo_node_point_instance_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *object_socket = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *collection_socket = object_socket->next; @@ -65,12 +65,15 @@ static void geo_node_point_instance_update(bNodeTree *UNUSED(tree), bNode *node) const bool use_whole_collection = (node_storage->flag & GEO_NODE_POINT_INSTANCE_WHOLE_COLLECTION) != 0; - nodeSetSocketAvailability(object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); - nodeSetSocketAvailability(collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); - nodeSetSocketAvailability(instance_geometry_socket, - type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, object_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_OBJECT); nodeSetSocketAvailability( - seed_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && !use_whole_collection); + ntree, collection_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION); + nodeSetSocketAvailability( + ntree, instance_geometry_socket, type == GEO_NODE_POINT_INSTANCE_TYPE_GEOMETRY); + nodeSetSocketAvailability(ntree, + seed_socket, + type == GEO_NODE_POINT_INSTANCE_TYPE_COLLECTION && + !use_whole_collection); } static Vector<InstanceReference> get_instance_references__object(GeoNodeExecParams ¶ms) @@ -171,13 +174,12 @@ static void add_instances_from_component(InstancesComponent &instances, const int domain_size = src_geometry.attribute_domain_size(domain); - GVArray_Typed<float3> positions = src_geometry.attribute_get_for_read<float3>( + VArray<float3> positions = src_geometry.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); - GVArray_Typed<float3> rotations = src_geometry.attribute_get_for_read<float3>( + VArray<float3> rotations = src_geometry.attribute_get_for_read<float3>( "rotation", domain, {0, 0, 0}); - GVArray_Typed<float3> scales = src_geometry.attribute_get_for_read<float3>( - "scale", domain, {1, 1, 1}); - GVArray_Typed<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); + VArray<float3> scales = src_geometry.attribute_get_for_read<float3>("scale", domain, {1, 1, 1}); + VArray<int> id_attribute = src_geometry.attribute_get_for_read<int>("id", domain, -1); /* The initial size of the component might be non-zero if there are two component types. */ const int start_len = instances.instances_amount(); @@ -213,7 +215,7 @@ static void add_instances_from_component(InstancesComponent &instances, } } -static void geo_node_point_instance_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -253,20 +255,22 @@ static void geo_node_point_instance_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_instance_cc void register_node_type_geo_point_instance() { + namespace file_ns = blender::nodes::node_geo_legacy_point_instance_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_INSTANCE, "Point Instance", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_instance_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryPointInstance", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.draw_buttons = blender::nodes::geo_node_point_instance_layout; - node_type_update(&ntype, blender::nodes::geo_node_point_instance_update); - ntype.geometry_node_execute = blender::nodes::geo_node_point_instance_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc index 54d36dab98d..7cdd03baa02 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_rotate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_rotate.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_rotate_cc { -static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Axis")); @@ -37,7 +37,7 @@ static void geo_node_point_rotate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { NodeGeometryRotatePoints *storage = (NodeGeometryRotatePoints *)((bNode *)ptr->data)->storage; @@ -57,7 +57,7 @@ static void geo_node_point_rotate_layout(uiLayout *layout, bContext *UNUSED(C), } } -static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)MEM_callocN( sizeof(NodeGeometryRotatePoints), __func__); @@ -71,20 +71,23 @@ static void geo_node_point_rotate_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = node_storage; } -static void geo_node_point_rotate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRotatePoints *node_storage = (NodeGeometryRotatePoints *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Axis", (GeometryNodeAttributeInputMode)node_storage->input_type_axis, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Angle", (GeometryNodeAttributeInputMode)node_storage->input_type_angle, node_storage->type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE); update_attribute_input_socket_availabilities( + *ntree, *node, "Rotation", (GeometryNodeAttributeInputMode)node_storage->input_type_rotation, @@ -169,9 +172,9 @@ static void point_rotate_on_component(GeometryComponent &component, const int domain_size = rotations.size(); if (storage.type == GEO_NODE_POINT_ROTATE_TYPE_AXIS_ANGLE) { - GVArray_Typed<float3> axis = params.get_input_attribute<float3>( + VArray<float3> axis = params.get_input_attribute<float3>( "Axis", component, ATTR_DOMAIN_POINT, {0, 0, 1}); - GVArray_Typed<float> angles = params.get_input_attribute<float>( + VArray<float> angles = params.get_input_attribute<float>( "Angle", component, ATTR_DOMAIN_POINT, 0); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -182,7 +185,7 @@ static void point_rotate_on_component(GeometryComponent &component, } } else { - GVArray_Typed<float3> eulers = params.get_input_attribute<float3>( + VArray<float3> eulers = params.get_input_attribute<float3>( "Rotation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); if (storage.space == GEO_NODE_POINT_ROTATE_SPACE_OBJECT) { @@ -196,7 +199,7 @@ static void point_rotate_on_component(GeometryComponent &component, rotation_attribute.save(); } -static void geo_node_point_rotate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -215,19 +218,21 @@ static void geo_node_point_rotate_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_rotate_cc void register_node_type_geo_point_rotate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_rotate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_ROTATE, "Point Rotate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_rotate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_rotate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRotatePoints", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_rotate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_rotate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_rotate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc index 934442ee8a3..4a6f19b8ed2 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_scale.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_scale.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_scale_cc { -static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Factor")); @@ -34,14 +34,14 @@ static void geo_node_point_scale_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_scale_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "input_type", 0, IFACE_("Type"), ICON_NONE); } -static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointScale *data = (NodeGeometryPointScale *)MEM_callocN( sizeof(NodeGeometryPointScale), __func__); @@ -50,12 +50,12 @@ static void geo_node_point_scale_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_scale_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointScale &node_storage = *(NodeGeometryPointScale *)node->storage; update_attribute_input_socket_availabilities( - *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Factor", (GeometryNodeAttributeInputMode)node_storage.input_type); } static void execute_on_component(GeoNodeExecParams params, GeometryComponent &component) @@ -78,7 +78,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co const CustomDataType data_type = (input_type == GEO_NODE_ATTRIBUTE_INPUT_FLOAT) ? CD_PROP_FLOAT : CD_PROP_FLOAT3; - GVArrayPtr attribute = params.get_input_attribute( + GVArray attribute = params.get_input_attribute( "Factor", component, ATTR_DOMAIN_POINT, data_type, nullptr); if (!attribute) { return; @@ -86,13 +86,13 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co MutableSpan<float3> scale_span = scale_attribute.as_span(); if (data_type == CD_PROP_FLOAT) { - GVArray_Typed<float> factors{*attribute}; + VArray<float> factors = attribute.typed<float>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } } else if (data_type == CD_PROP_FLOAT3) { - GVArray_Typed<float3> factors{*attribute}; + VArray<float3> factors = attribute.typed<float3>(); for (const int i : scale_span.index_range()) { scale_span[i] = scale_span[i] * factors[i]; } @@ -101,7 +101,7 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co scale_attribute.save(); } -static void geo_node_point_scale_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -120,20 +120,22 @@ static void geo_node_point_scale_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_scale_cc void register_node_type_geo_point_scale() { + namespace file_ns = blender::nodes::node_geo_legacy_point_scale_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_POINT_SCALE, "Point Scale", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_scale_declare; - node_type_init(&ntype, blender::nodes::geo_node_point_scale_init); - node_type_update(&ntype, blender::nodes::geo_node_point_scale_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryPointScale", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_point_scale_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_scale_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc index accdaf78439..5d18abbc828 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_separate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_separate.cc @@ -25,14 +25,6 @@ namespace blender::nodes { -static void geo_node_point_instance_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::String>(N_("Mask")); - b.add_output<decl::Geometry>(N_("Geometry 1")); - b.add_output<decl::Geometry>(N_("Geometry 2")); -} - template<typename T> static void copy_data_based_on_mask(Span<T> data, Span<bool> masks, @@ -55,7 +47,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, { for (const AttributeIDRef &attribute_id : in_component.attribute_ids()) { ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(attribute_id); - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); /* Only copy point attributes. Theoretically this could interpolate attributes on other * domains to the point domain, but that would conflict with attributes that are built-in @@ -69,7 +61,7 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data_based_on_mask(span, masks, invert, out_span); }); @@ -78,6 +70,18 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component, } } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_legacy_point_separate_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::String>(N_("Mask")); + b.add_output<decl::Geometry>(N_("Geometry 1")); + b.add_output<decl::Geometry>(N_("Geometry 2")); +} + static void create_component_points(GeometryComponent &component, const int total) { switch (component.type()) { @@ -103,7 +107,7 @@ static void separate_points_from_component(const GeometryComponent &in_component return; } - const GVArray_Typed<bool> mask_attribute = in_component.attribute_get_for_read<bool>( + const VArray<bool> mask_attribute = in_component.attribute_get_for_read<bool>( mask_name, ATTR_DOMAIN_POINT, false); VArray_Span<bool> masks{mask_attribute}; @@ -133,7 +137,7 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in, return set_out; } -static void geo_node_point_separate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { bool wait_for_inputs = false; wait_for_inputs |= params.lazy_require_input("Geometry"); @@ -158,16 +162,18 @@ static void geo_node_point_separate_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_separate_cc void register_node_type_geo_point_separate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_separate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_point_instance_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc index 34f7641995f..4e18c650199 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_point_translate.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_point_translate_cc { -static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Translation")); @@ -29,7 +29,7 @@ static void geo_node_point_translate_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_point_translate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -43,17 +43,17 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co if (!position_attribute) { return; } - GVArray_Typed<float3> attribute = params.get_input_attribute<float3>( + VArray<float3> attribute = params.get_input_attribute<float3>( "Translation", component, ATTR_DOMAIN_POINT, {0, 0, 0}); - for (const int i : IndexRange(attribute.size())) { + for (const int i : attribute.index_range()) { position_attribute->set(i, position_attribute->get(i) + attribute[i]); } position_attribute.save(); } -static void geo_node_point_translate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -72,7 +72,7 @@ static void geo_node_point_translate_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryPointTranslate *data = (NodeGeometryPointTranslate *)MEM_callocN( sizeof(NodeGeometryPointTranslate), __func__); @@ -81,30 +81,32 @@ static void geo_node_point_translate_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_point_translate_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryPointTranslate &node_storage = *(NodeGeometryPointTranslate *)node->storage; update_attribute_input_socket_availabilities( - *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); + *ntree, *node, "Translation", (GeometryNodeAttributeInputMode)node_storage.input_type); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_point_translate_cc void register_node_type_geo_point_translate() { + namespace file_ns = blender::nodes::node_geo_legacy_point_translate_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_POINT_TRANSLATE, "Point Translate", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_point_translate_init); - node_type_update(&ntype, blender::nodes::geo_node_point_translate_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryPointTranslate", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_point_translate_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_translate_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_translate_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc index cf7f466c2a6..2c34d0d781e 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_points_to_volume.cc @@ -28,9 +28,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); @@ -41,9 +41,7 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -51,7 +49,7 @@ static void geo_node_points_to_volume_layout(uiLayout *layout, uiItemR(layout, ptr, "input_type_radius", 0, IFACE_("Radius"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -65,19 +63,22 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node STRNCPY(radius_attribute_socket_value->value, "radius"); } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *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, + nodeSetSocketAvailability(ntree, + 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); + nodeSetSocketAvailability(ntree, + 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); + *ntree, *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); } #ifdef WITH_OPENVDB @@ -172,12 +173,12 @@ static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - GVArray_Typed<float> radii = params.get_input_attribute<float>( + VArray<float> radii = params.get_input_attribute<float>( "Radius", component, ATTR_DOMAIN_POINT, 0.0f); - for (const int i : IndexRange(positions.size())) { + for (const int i : positions.index_range()) { r_positions.append(positions[i]); r_radii.append(radii[i]); } @@ -241,7 +242,7 @@ static void initialize_volume_component_from_points(const GeometrySet &geometry_ } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -256,10 +257,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_points_to_volume_cc void register_node_type_geo_legacy_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_legacy_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -269,10 +272,10 @@ void register_node_type_geo_legacy_points_to_volume() 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.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc index e6a81fc9627..83081933c64 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_raycast.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_raycast_cc { -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Geometry>(N_("Target Geometry")); @@ -47,7 +47,7 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -56,7 +56,7 @@ static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), Point uiItemR(layout, ptr, "input_type_ray_length", 0, IFACE_("Ray Length"), ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -65,15 +65,19 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryRaycast *node_storage = (NodeGeometryRaycast *)node->storage; update_attribute_input_socket_availabilities( + *ntree, *node, "Ray Direction", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_direction); update_attribute_input_socket_availabilities( - *node, "Ray Length", (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); + *ntree, + *node, + "Ray Length", + (GeometryNodeAttributeInputMode)node_storage->input_type_ray_length); } static void raycast_to_mesh(const Mesh &mesh, @@ -197,11 +201,11 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, (GeometryNodeRaycastMapMode)storage.mapping); const AttributeDomain result_domain = ATTR_DOMAIN_POINT; - GVArray_Typed<float3> ray_origins = dst_component.attribute_get_for_read<float3>( + VArray<float3> ray_origins = dst_component.attribute_get_for_read<float3>( "position", result_domain, {0, 0, 0}); - GVArray_Typed<float3> ray_directions = params.get_input_attribute<float3>( + VArray<float3> ray_directions = params.get_input_attribute<float3>( "Ray Direction", dst_component, result_domain, {0, 0, 0}); - GVArray_Typed<float> ray_lengths = params.get_input_attribute<float>( + VArray<float> ray_lengths = params.get_input_attribute<float>( "Ray Length", dst_component, result_domain, 0); OutputAttribute_Typed<bool> hit_attribute = @@ -218,10 +222,10 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, Array<int> hit_indices; Array<float3> hit_positions_internal; if (!hit_attribute_names.is_empty()) { - hit_indices.reinitialize(ray_origins->size()); + hit_indices.reinitialize(ray_origins.size()); if (!hit_position_attribute) { - hit_positions_internal.reinitialize(ray_origins->size()); + hit_positions_internal.reinitialize(ray_origins.size()); } } const MutableSpan<bool> is_hit = hit_attribute ? hit_attribute.as_span() : MutableSpan<bool>(); @@ -268,7 +272,7 @@ static void raycast_from_points(const GeoNodeExecParams ¶ms, } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); GeometrySet target_geometry_set = params.extract_input<GeometrySet>("Target Geometry"); @@ -303,20 +307,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_raycast_cc void register_node_type_geo_legacy_raycast() { + namespace file_ns = blender::nodes::node_geo_legacy_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_LEGACY_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc index a8d6f33a5fd..0119570b199 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_select_by_material.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_select_by_material.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_select_by_material_cc { -static void geo_node_legacy_select_by_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Material>(N_("Material")).hide_label(); @@ -54,7 +54,7 @@ static void select_mesh_by_material(const Mesh &mesh, }); } -static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const std::string selection_name = params.extract_input<std::string>("Selection"); @@ -78,15 +78,17 @@ static void geo_node_legacy_select_by_material_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_select_by_material_cc void register_node_type_geo_legacy_select_by_material() { + namespace file_ns = blender::nodes::node_geo_legacy_select_by_material_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SELECT_BY_MATERIAL, "Select by Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_select_by_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_select_by_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc index 295cd05fd01..dd9c26f3790 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_subdivision_surface.cc @@ -23,9 +23,9 @@ #include "UI_resources.h" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -33,9 +33,7 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { #ifdef WITH_OPENSUBDIV uiLayoutSetPropSep(layout, true); @@ -47,7 +45,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout, #endif } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -56,7 +54,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -126,18 +124,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_subdivision_surface_cc void register_node_type_geo_legacy_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_legacy_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc index 39af5bf1fd2..acff0be7126 100644 --- a/source/blender/nodes/geometry/nodes/legacy/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/legacy/node_geo_legacy_volume_to_mesh.cc @@ -35,9 +35,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Density")); @@ -48,14 +48,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -68,15 +68,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)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, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } @@ -138,7 +140,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in, #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Geometry"); GeometrySet geometry_set_out; @@ -153,21 +155,23 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_legacy_volume_to_mesh_cc void register_node_type_geo_legacy_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_legacy_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_LEGACY_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc index 5cc8f1476f8..7229fda7a5c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_capture.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_capture_cc { -static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Vector>(N_("Value")).supports_field(); @@ -40,9 +40,7 @@ static void geo_node_attribute_capture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").field_source(); } -static void geo_node_attribute_capture_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +48,7 @@ static void geo_node_attribute_capture_layout(uiLayout *layout, uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } -static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryAttributeCapture *data = (NodeGeometryAttributeCapture *)MEM_callocN( sizeof(NodeGeometryAttributeCapture), __func__); @@ -60,7 +58,7 @@ static void geo_node_attribute_capture_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryAttributeCapture &storage = *(const NodeGeometryAttributeCapture *) node->storage; @@ -73,11 +71,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *socket_value_boolean = socket_value_color4f->next; bNodeSocket *socket_value_int32 = socket_value_boolean->next; - nodeSetSocketAvailability(socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_value_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_value_geometry = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_value_vector = out_socket_value_geometry->next; @@ -86,11 +84,11 @@ static void geo_node_attribute_capture_update(bNodeTree *UNUSED(ntree), bNode *n bNodeSocket *out_socket_value_boolean = out_socket_value_color4f->next; bNodeSocket *out_socket_value_int32 = out_socket_value_boolean->next; - nodeSetSocketAvailability(out_socket_value_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_value_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_value_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_value_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_value_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_value_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_value_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_value_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_value_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_value_int32, data_type == CD_PROP_INT32); } static void try_capture_field_on_geometry(GeometryComponent &component, @@ -113,7 +111,7 @@ static void try_capture_field_on_geometry(GeometryComponent &component, output_attribute.save(); } -static void geo_node_attribute_capture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -147,16 +145,27 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) WeakAnonymousAttributeID anonymous_id{"Attribute"}; const CPPType &type = field.cpp_type(); - static const Array<GeometryComponentType> types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; - geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { - for (const GeometryComponentType type : types) { - if (geometry_set.has(type)) { - GeometryComponent &component = geometry_set.get_component_for_write(type); - try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); - } + /* Run on the instances component separately to only affect the top level of instances. */ + if (domain == ATTR_DOMAIN_INSTANCE) { + if (geometry_set.has_instances()) { + GeometryComponent &component = geometry_set.get_component_for_write( + GEO_COMPONENT_TYPE_INSTANCES); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); } - }); + } + else { + static const Array<GeometryComponentType> types = { + GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { + for (const GeometryComponentType type : types) { + if (geometry_set.has(type)) { + GeometryComponent &component = geometry_set.get_component_for_write(type); + try_capture_field_on_geometry(component, anonymous_id.get(), domain, field); + } + } + }); + } GField output_field{std::make_shared<bke::AnonymousAttributeFieldInput>( std::move(anonymous_id), type, params.attribute_producer_name())}; @@ -189,10 +198,12 @@ static void geo_node_attribute_capture_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_capture_cc void register_node_type_geo_attribute_capture() { + namespace file_ns = blender::nodes::node_geo_attribute_capture_cc; + static bNodeType ntype; geo_node_type_base( @@ -201,10 +212,10 @@ void register_node_type_geo_attribute_capture() "NodeGeometryAttributeCapture", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_attribute_capture_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_capture_update); - ntype.declare = blender::nodes::geo_node_attribute_capture_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_capture_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_capture_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc index f80b8ccc971..6f26b2c756b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_remove.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_remove_cc { -static void geo_node_attribute_remove_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::String>(N_("Attribute")).multi_input(); @@ -42,7 +42,7 @@ static void remove_attribute(GeometryComponent &component, } } -static void geo_node_attribute_remove_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Vector<std::string> attribute_names = params.extract_multi_input<std::string>("Attribute"); @@ -66,15 +66,17 @@ static void geo_node_attribute_remove_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_remove_cc void register_node_type_geo_attribute_remove() { + namespace file_ns = blender::nodes::node_geo_attribute_remove_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_REMOVE, "Attribute Remove", NODE_CLASS_ATTRIBUTE, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_remove_exec; - ntype.declare = blender::nodes::geo_node_attribute_remove_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc index 155bd8c8c28..c84031f4c6b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_statistic.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_attribute_statistic_cc { -static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Attribute")).hide_value().supports_field(); @@ -51,21 +51,19 @@ static void geo_node_attribute_statistic_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Variance"), "Variance_001"); } -static void geo_node_attribute_statistic_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } -static void geo_node_attribute_statistic_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = CD_PROP_FLOAT; node->custom2 = ATTR_DOMAIN_POINT; } -static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *socket_geo = (bNodeSocket *)node->inputs.first; bNodeSocket *socket_float_attr = socket_geo->next; @@ -91,25 +89,25 @@ static void geo_node_attribute_statistic_update(bNodeTree *UNUSED(ntree), bNode const CustomDataType data_type = static_cast<CustomDataType>(node->custom1); - nodeSetSocketAvailability(socket_float_attr, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_mean, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_median, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_sum, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_min, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_max, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_range, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_std, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_float_variance, data_type == CD_PROP_FLOAT); - - nodeSetSocketAvailability(socket_float3_attr, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_mean, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_median, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_sum, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_min, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_max, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_range, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_std, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_vector_variance, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float_attr, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_mean, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_median, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_sum, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_min, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_max, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_range, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_std, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_float_variance, data_type == CD_PROP_FLOAT); + + nodeSetSocketAvailability(ntree, socket_float3_attr, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_mean, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_median, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_sum, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_min, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_max, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_range, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_std, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_vector_variance, data_type == CD_PROP_FLOAT3); } template<typename T> static T compute_sum(const Span<T> data) @@ -170,7 +168,7 @@ static void set_empty(CustomDataType data_type, GeoNodeExecParams ¶ms) } } -static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.get_input<GeometrySet>("Geometry"); @@ -360,19 +358,21 @@ static void geo_node_attribute_statistic_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_attribute_statistic_cc void register_node_type_geo_attribute_statistic() { + namespace file_ns = blender::nodes::node_geo_attribute_statistic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ATTRIBUTE_STATISTIC, "Attribute Statistic", NODE_CLASS_ATTRIBUTE, 0); - ntype.declare = blender::nodes::geo_node_attribute_statistic_declare; - node_type_init(&ntype, blender::nodes::geo_node_attribute_statistic_init); - node_type_update(&ntype, blender::nodes::geo_node_attribute_statistic_update); - ntype.geometry_node_execute = blender::nodes::geo_node_attribute_statistic_exec; - ntype.draw_buttons = blender::nodes::geo_node_attribute_statistic_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 516f07b7ad3..0947632cc09 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_boolean_cc { -static void geo_node_boolean_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh 1")) .only_realized_data() @@ -36,12 +36,12 @@ static void geo_node_boolean_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_boolean_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); } -static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)node->custom1; @@ -51,24 +51,24 @@ static void geo_node_boolean_update(bNodeTree *UNUSED(ntree), bNode *node) switch (operation) { case GEO_NODE_BOOLEAN_INTERSECT: case GEO_NODE_BOOLEAN_UNION: - nodeSetSocketAvailability(geometry_1_socket, false); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, false); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh")); break; case GEO_NODE_BOOLEAN_DIFFERENCE: - nodeSetSocketAvailability(geometry_1_socket, true); - nodeSetSocketAvailability(geometry_2_socket, true); + nodeSetSocketAvailability(ntree, geometry_1_socket, true); + nodeSetSocketAvailability(ntree, geometry_2_socket, true); node_sock_label(geometry_2_socket, N_("Mesh 2")); break; } } -static void geo_node_boolean_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { node->custom1 = GEO_NODE_BOOLEAN_DIFFERENCE; } -static void geo_node_boolean_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometryNodeBooleanOperation operation = (GeometryNodeBooleanOperation)params.node().custom1; const bool use_self = params.get_input<bool>("Self Intersection"); @@ -119,17 +119,19 @@ static void geo_node_boolean_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_boolean_cc void register_node_type_geo_boolean() { + namespace file_ns = blender::nodes::node_geo_boolean_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_BOOLEAN, "Mesh Boolean", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_boolean_declare; - ntype.draw_buttons = blender::nodes::geo_node_boolean_layout; - ntype.updatefunc = blender::nodes::geo_node_boolean_update; - node_type_init(&ntype, blender::nodes::geo_node_boolean_init); - ntype.geometry_node_execute = blender::nodes::geo_node_boolean_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.updatefunc = file_ns::node_update; + node_type_init(&ntype, file_ns::node_init); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc index e7c9715934a..da1f9a00c69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_bounding_box.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_bounding_box_cc { -static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Bounding Box")); @@ -26,7 +26,7 @@ static void geo_node_bounding_box_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Max")); } -static void geo_node_bounding_box_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -78,14 +78,16 @@ static void geo_node_bounding_box_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_bounding_box_cc void register_node_type_geo_bounding_box() { + namespace file_ns = blender::nodes::node_geo_bounding_box_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_BOUNDING_BOX, "Bounding Box", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_bounding_box_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_bounding_box_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc index f068e621596..1cd5f396ee5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_collection_info.cc @@ -27,9 +27,9 @@ #include <algorithm> -namespace blender::nodes { +namespace blender::nodes::node_geo_collection_info_cc { -static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Collection>(N_("Collection")).hide_label(); b.add_input<decl::Bool>(N_("Separate Children")) @@ -38,16 +38,16 @@ static void geo_node_collection_info_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Reset Children")) .description( N_("Reset the transforms of every child instance in the output. Only used when Separate " - "Children is enabled")); + "Children is enabled")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_collection_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_collection_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCollectionInfo *data = (NodeGeometryCollectionInfo *)MEM_callocN( sizeof(NodeGeometryCollectionInfo), __func__); @@ -61,7 +61,7 @@ struct InstanceListEntry { float4x4 transform; }; -static void geo_node_collection_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Collection *collection = params.get_input<Collection *>("Collection"); @@ -155,20 +155,22 @@ static void geo_node_collection_info_exec(GeoNodeExecParams params) params.set_output("Geometry", geometry_set_out); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_collection_info_cc void register_node_type_geo_collection_info() { + namespace file_ns = blender::nodes::node_geo_collection_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_COLLECTION_INFO, "Collection Info", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_collection_info_declare; - node_type_init(&ntype, blender::nodes::geo_node_collection_info_node_init); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_node_init); node_type_storage(&ntype, "NodeGeometryCollectionInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_collection_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_collection_info_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc index e2bb7e9f939..9ebbdd349de 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_common.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc @@ -31,7 +31,6 @@ void register_node_type_geo_group(void) ntype.poll = geo_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup"); BLI_assert(ntype.rna_ext.srna != nullptr); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -53,7 +52,4 @@ void register_node_type_geo_custom_group(bNodeType *ntype) if (ntype->insert_link == nullptr) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == nullptr) { - ntype->update_internal_links = node_update_internal_links_default; - } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc index 3cf682e161c..5222e2055b1 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc @@ -28,9 +28,9 @@ # include "RBI_hull_api.h" #endif -namespace blender::nodes { +namespace blender::nodes::node_geo_convex_hull_cc { -static void geo_node_convex_hull_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Convex Hull")); @@ -169,10 +169,10 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) span_count++; const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - total_size += varray->size(); - positions_span = varray->get_internal_span(); + total_size += varray.size(); + positions_span = varray.get_internal_span(); } if (geometry_set.has_curve()) { @@ -200,18 +200,18 @@ static Mesh *compute_hull(const GeometrySet &geometry_set) if (geometry_set.has_mesh()) { const MeshComponent *component = geometry_set.get_component_for_read<MeshComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } if (geometry_set.has_pointcloud()) { const PointCloudComponent *component = geometry_set.get_component_for_read<PointCloudComponent>(); - GVArray_Typed<float3> varray = component->attribute_get_for_read<float3>( + VArray<float3> varray = component->attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); - varray->materialize(positions.as_mutable_span().slice(offset, varray.size())); + varray.materialize(positions.as_mutable_span().slice(offset, varray.size())); offset += varray.size(); } @@ -235,16 +235,16 @@ static void read_positions(const GeometryComponent &component, Span<float4x4> transforms, Vector<float3> *r_coords) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); /* NOTE: could use convex hull operation here to * cut out some vertices, before accumulating, * but can also be done by the user beforehand. */ - r_coords->reserve(r_coords->size() + positions.size() * transforms.size()); + r_coords->reserve(r_coords->size() + positions->size() * transforms.size()); for (const float4x4 &transform : transforms) { - for (const int i : positions.index_range()) { + for (const int i : positions->index_range()) { const float3 position = positions[i]; const float3 transformed_position = transform * position; r_coords->append(transformed_position); @@ -296,7 +296,7 @@ static Mesh *convex_hull_from_instances(const GeometrySet &geometry_set) #endif /* WITH_BULLET */ -static void geo_node_convex_hull_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -316,14 +316,16 @@ static void geo_node_convex_hull_exec(GeoNodeExecParams params) #endif /* WITH_BULLET */ } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_convex_hull_cc void register_node_type_geo_convex_hull() { + namespace file_ns = blender::nodes::node_geo_convex_hull_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CONVEX_HULL, "Convex Hull", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_convex_hull_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_convex_hull_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc index 42d88cdb1e7..c756185e4ed 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoint_selection.cc @@ -21,9 +21,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_endpoint_select_cc { -static void geo_node_curve_endpoint_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Start Size")) .min(0) @@ -64,9 +64,9 @@ class EndpointFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -111,9 +111,9 @@ class EndpointFieldInput final : public fn::FieldInput { } current_point += spline->size(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } - return nullptr; + return {}; }; uint64_t hash() const override @@ -131,23 +131,25 @@ class EndpointFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_endpoint_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> start_size = params.extract_input<Field<int>>("Start Size"); Field<int> end_size = params.extract_input<Field<int>>("End Size"); Field<bool> selection_field{std::make_shared<EndpointFieldInput>(start_size, end_size)}; params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_endpoint_select_cc void register_node_type_geo_curve_endpoint_selection() { + namespace file_ns = blender::nodes::node_geo_curve_endpoint_select_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_ENDPOINT_SELECTION, "Endpoint Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_endpoint_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoint_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc index 219effadec4..4130cf99516 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fill.cc @@ -31,20 +31,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fill_cc { -static void geo_node_curve_fill_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_curve_fill_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fill_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryCurveFill *data = (NodeGeometryCurveFill *)MEM_callocN(sizeof(NodeGeometryCurveFill), __func__); @@ -147,7 +147,7 @@ static void curve_fill_calculate(GeometrySet &geometry_set, const GeometryNodeCu geometry_set.replace_curve(nullptr); } -static void geo_node_curve_fill_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -160,19 +160,21 @@ static void geo_node_curve_fill_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fill_cc void register_node_type_geo_curve_fill() { + namespace file_ns = blender::nodes::node_geo_curve_fill_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILL_CURVE, "Fill Curve", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_fill_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryCurveFill", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fill_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_fill_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_fill_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc index 27d7d22b106..ed5c9e1bc98 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_fillet.cc @@ -25,9 +25,9 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_fillet_cc { -static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Count")).default_value(1).min(1).max(1000).supports_field(); @@ -41,12 +41,12 @@ static void geo_node_curve_fillet_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_fillet_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_fillet_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveFillet *data = (NodeGeometryCurveFillet *)MEM_callocN( sizeof(NodeGeometryCurveFillet), __func__); @@ -59,10 +59,10 @@ struct FilletParam { GeometryNodeCurveFilletMode mode; /* Number of points to be added. */ - const VArray<int> *counts; + VArray<int> counts; /* Radii for fillet arc at all vertices. */ - const VArray<float> *radii; + VArray<float> radii; /* Whether or not fillets are allowed to overlap. */ bool limit_radius; @@ -76,14 +76,14 @@ struct FilletData { Array<int> counts; }; -static void geo_node_curve_fillet_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveFillet &node_storage = *(NodeGeometryCurveFillet *)node->storage; const GeometryNodeCurveFilletMode mode = (GeometryNodeCurveFilletMode)node_storage.mode; bNodeSocket *poly_socket = ((bNodeSocket *)node->inputs.first)->next; - nodeSetSocketAvailability(poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); + nodeSetSocketAvailability(ntree, poly_socket, mode == GEO_NODE_CURVE_FILLET_POLY); } /* Function to get the center of a fillet. */ @@ -160,7 +160,7 @@ static Array<int> calculate_counts(const FilletParam &fillet_param, Array<int> counts(size, 1); if (fillet_param.mode == GEO_NODE_CURVE_FILLET_POLY) { for (const int i : IndexRange(size)) { - counts[i] = (*fillet_param.counts)[spline_offset + i]; + counts[i] = fillet_param.counts[spline_offset + i]; } } if (!cyclic) { @@ -178,12 +178,12 @@ static Array<float> calculate_radii(const FilletParam &fillet_param, Array<float> radii(size, 0.0f); if (fillet_param.limit_radius) { for (const int i : IndexRange(size)) { - radii[i] = std::max((*fillet_param.radii)[spline_offset + i], 0.0f); + radii[i] = std::max(fillet_param.radii[spline_offset + i], 0.0f); } } else { for (const int i : IndexRange(size)) { - radii[i] = (*fillet_param.radii)[spline_offset + i]; + radii[i] = fillet_param.radii[spline_offset + i]; } } @@ -590,13 +590,13 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, field_evaluator.evaluate(); - fillet_param.radii = &field_evaluator.get_evaluated<float>(0); - if (fillet_param.radii->is_single() && fillet_param.radii->get_internal_single() < 0.0f) { + fillet_param.radii = field_evaluator.get_evaluated<float>(0); + if (fillet_param.radii.is_single() && fillet_param.radii.get_internal_single() < 0.0f) { return; } if (mode == GEO_NODE_CURVE_FILLET_POLY) { - fillet_param.counts = &field_evaluator.get_evaluated<int>(1); + fillet_param.counts = field_evaluator.get_evaluated<int>(1); } fillet_param.limit_radius = limit_radius; @@ -607,7 +607,7 @@ static void calculate_curve_fillet(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_fillet_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -629,19 +629,21 @@ static void geo_node_fillet_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_fillet_cc void register_node_type_geo_curve_fillet() { + namespace file_ns = blender::nodes::node_geo_curve_fillet_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_FILLET_CURVE, "Fillet Curve", NODE_CLASS_GEOMETRY, 0); - ntype.draw_buttons = blender::nodes::geo_node_curve_fillet_layout; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveFillet", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_fillet_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_fillet_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_fillet_update); - ntype.geometry_node_execute = blender::nodes::geo_node_fillet_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc index e48c72b68d9..2a53f7a3f82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_handle_type_selection.cc @@ -21,22 +21,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_handle_type_selection_cc { -static void geo_node_curve_handle_type_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Selection")).field_source(); } -static void geo_node_curve_handle_type_selection_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_handle_type_selection_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSelectHandles *data = (NodeGeometryCurveSelectHandles *)MEM_callocN( sizeof(NodeGeometryCurveSelectHandles), __func__); @@ -96,9 +94,9 @@ class HandleTypeFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -106,22 +104,22 @@ class HandleTypeFieldInput final : public fn::FieldInput { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_CURVE) { - return nullptr; + return {}; } const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_POINT) { Array<bool> selection(mask.min_array_size()); select_by_handle_type(*curve, type_, mode_, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } } - return nullptr; + return {}; }; uint64_t hash() const override @@ -140,7 +138,7 @@ class HandleTypeFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSelectHandles *storage = (const NodeGeometryCurveSelectHandles *)params.node().storage; @@ -152,22 +150,24 @@ static void geo_node_curve_handle_type_selection_exec(GeoNodeExecParams params) params.set_output("Selection", std::move(selection_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_handle_type_selection_cc void register_node_type_geo_curve_handle_type_selection() { + namespace file_ns = blender::nodes::node_geo_curve_handle_type_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_HANDLE_TYPE_SELECTION, "Handle Type Selection", NODE_CLASS_INPUT, 0); - ntype.declare = blender::nodes::geo_node_curve_handle_type_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_handle_type_selection_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_handle_type_selection_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSelectHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_handle_type_selection_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc index 0d0dc0ec89c..33e9b11ec0c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc @@ -17,15 +17,15 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_length_cc { -static void geo_node_curve_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_output<decl::Float>(N_("Length")); } -static void geo_node_curve_length_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); if (!curve_set.has_curve()) { @@ -40,14 +40,16 @@ static void geo_node_curve_length_exec(GeoNodeExecParams params) params.set_output("Length", length); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_length_cc void register_node_type_geo_curve_length() { + namespace file_ns = blender::nodes::node_geo_curve_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_length_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc index 4c89aba2e6d..27b2590546b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_parameter.cc @@ -20,11 +20,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_parameter_cc { -static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_output<decl::Float>(N_("Factor")).field_source(); + b.add_output<decl::Float>(N_("Factor")) + .field_source() + .description( + N_("For points, the portion of the spline's total length at the control point. For " + "Splines, the factor of that spline within the entire curve")); + b.add_output<decl::Float>(N_("Length")) + .field_source() + .description( + N_("For points, the distance along the control point's spline, For splines, the " + "distance along the entire curve")); } /** @@ -32,47 +41,42 @@ static void geo_node_curve_parameter_declare(NodeDeclarationBuilder &b) * average parameter for each spline would just be 0.5, or close to it. Instead, the parameter for * each spline is the portion of the total length at the start of the spline. */ -static Array<float> curve_parameter_spline_domain(const CurveEval &curve, const IndexMask mask) +static Array<float> curve_length_spline_domain(const CurveEval &curve, + const IndexMask UNUSED(mask)) { Span<SplinePtr> splines = curve.splines(); float length = 0.0f; - Array<float> parameters(splines.size()); + Array<float> lengths(splines.size()); for (const int i : splines.index_range()) { - parameters[i] = length; + lengths[i] = length; length += splines[i]->length(); } - const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length; - mask.foreach_index([&](const int64_t i) { parameters[i] *= total_length_inverse; }); - - return parameters; + return lengths; } /** * The parameter at each control point is the factor at the corresponding evaluated point. */ -static void calculate_bezier_parameters(const BezierSpline &spline, MutableSpan<float> parameters) +static void calculate_bezier_lengths(const BezierSpline &spline, MutableSpan<float> lengths) { Span<int> offsets = spline.control_point_offsets(); - Span<float> lengths = spline.evaluated_lengths(); - const float total_length = spline.length(); - const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length; - + Span<float> lengths_eval = spline.evaluated_lengths(); for (const int i : IndexRange(1, spline.size() - 1)) { - parameters[i] = lengths[offsets[i] - 1] * total_length_inverse; + lengths[i] = lengths_eval[offsets[i] - 1]; } } /** * The parameter for poly splines is simply the evaluated lengths divided by the total length. */ -static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<float> parameters) +static void calculate_poly_length(const PolySpline &spline, MutableSpan<float> lengths) { - Span<float> lengths = spline.evaluated_lengths(); - const float total_length = spline.length(); - const float total_length_inverse = total_length == 0.0f ? 0.0f : 1.0f / total_length; - - for (const int i : IndexRange(1, spline.size() - 1)) { - parameters[i] = lengths[i - 1] * total_length_inverse; + Span<float> lengths_eval = spline.evaluated_lengths(); + if (spline.is_cyclic()) { + lengths.drop_front(1).copy_from(lengths_eval.drop_back(1)); + } + else { + lengths.drop_front(1).copy_from(lengths_eval); } } @@ -82,70 +86,100 @@ static void calculate_poly_parameters(const PolySpline &spline, MutableSpan<floa * each point is not well defined. So instead, treat the control points as if they were a poly * spline. */ -static void calculate_nurbs_parameters(const NURBSpline &spline, MutableSpan<float> parameters) +static void calculate_nurbs_lengths(const NURBSpline &spline, MutableSpan<float> lengths) { Span<float3> positions = spline.positions(); Array<float> control_point_lengths(spline.size()); - float length = 0.0f; for (const int i : IndexRange(positions.size() - 1)) { - parameters[i] = length; + lengths[i] = length; length += float3::distance(positions[i], positions[i + 1]); } - - const float total_length_inverse = length == 0.0f ? 0.0f : 1.0f / length; - for (float ¶meter : parameters) { - parameter *= total_length_inverse; - } + lengths.last() = length; } -static Array<float> curve_parameter_point_domain(const CurveEval &curve) +static Array<float> curve_length_point_domain(const CurveEval &curve) { Span<SplinePtr> splines = curve.splines(); Array<int> offsets = curve.control_point_offsets(); const int total_size = offsets.last(); - Array<float> parameters(total_size); + Array<float> lengths(total_size); threading::parallel_for(splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { const Spline &spline = *splines[i]; - MutableSpan spline_factors{parameters.as_mutable_span().slice(offsets[i], spline.size())}; + MutableSpan spline_factors{lengths.as_mutable_span().slice(offsets[i], spline.size())}; spline_factors.first() = 0.0f; switch (splines[i]->type()) { case Spline::Type::Bezier: { - calculate_bezier_parameters(static_cast<const BezierSpline &>(spline), spline_factors); + calculate_bezier_lengths(static_cast<const BezierSpline &>(spline), spline_factors); break; } case Spline::Type::Poly: { - calculate_poly_parameters(static_cast<const PolySpline &>(spline), spline_factors); + calculate_poly_length(static_cast<const PolySpline &>(spline), spline_factors); break; } case Spline::Type::NURBS: { - calculate_nurbs_parameters(static_cast<const NURBSpline &>(spline), spline_factors); + calculate_nurbs_lengths(static_cast<const NURBSpline &>(spline), spline_factors); break; } } } }); - return parameters; + return lengths; } -static const GVArray *construct_curve_parameter_gvarray(const CurveEval &curve, - const IndexMask mask, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_curve_parameter_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) { if (domain == ATTR_DOMAIN_POINT) { - Array<float> parameters = curve_parameter_point_domain(curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters)); + Span<SplinePtr> splines = curve.splines(); + Array<float> values = curve_length_point_domain(curve); + + const Array<int> offsets = curve.control_point_offsets(); + for (const int i_spline : curve.splines().index_range()) { + const Spline &spline = *splines[i_spline]; + const float spline_length = spline.length(); + const float spline_length_inv = spline_length == 0.0f ? 0.0f : 1.0f / spline_length; + for (const int i : IndexRange(spline.size())) { + values[offsets[i_spline] + i] *= spline_length_inv; + } + } + return VArray<float>::ForContainer(std::move(values)); } if (domain == ATTR_DOMAIN_CURVE) { - Array<float> parameters = curve_parameter_spline_domain(curve, mask); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float>>>(std::move(parameters)); + Array<float> values = curve.accumulated_spline_lengths(); + const float total_length_inv = values.last() == 0.0f ? 0.0f : 1.0f / values.last(); + for (const int i : mask) { + values[i] *= total_length_inv; + } + return VArray<float>::ForContainer(std::move(values)); } + return {}; +} - return nullptr; +static VArray<float> construct_curve_length_varray(const CurveEval &curve, + const IndexMask mask, + const AttributeDomain domain) +{ + if (domain == ATTR_DOMAIN_POINT) { + Array<float> lengths = curve_length_point_domain(curve); + return VArray<float>::ForContainer(std::move(lengths)); + } + + if (domain == ATTR_DOMAIN_CURVE) { + if (curve.splines().size() == 1) { + Array<float> lengths(1, 0.0f); + return VArray<float>::ForContainer(std::move(lengths)); + } + + Array<float> lengths = curve_length_spline_domain(curve, mask); + return VArray<float>::ForContainer(std::move(lengths)); + } + + return {}; } class CurveParameterFieldInput final : public fn::FieldInput { @@ -155,9 +189,9 @@ class CurveParameterFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -169,11 +203,11 @@ class CurveParameterFieldInput final : public fn::FieldInput { const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); const CurveEval *curve = curve_component.get_for_read(); if (curve) { - return construct_curve_parameter_gvarray(*curve, mask, domain, scope); + return construct_curve_parameter_varray(*curve, mask, domain); } } } - return nullptr; + return {}; } uint64_t hash() const override @@ -188,20 +222,62 @@ class CurveParameterFieldInput final : public fn::FieldInput { } }; -static void geo_node_curve_parameter_exec(GeoNodeExecParams params) +class CurveLengthFieldInput final : public fn::FieldInput { + public: + CurveLengthFieldInput() : fn::FieldInput(CPPType::get<float>(), "Curve Length node") + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final + { + if (const GeometryComponentFieldContext *geometry_context = + dynamic_cast<const GeometryComponentFieldContext *>(&context)) { + + const GeometryComponent &component = geometry_context->geometry_component(); + const AttributeDomain domain = geometry_context->domain(); + if (component.type() == GEO_COMPONENT_TYPE_CURVE) { + const CurveComponent &curve_component = static_cast<const CurveComponent &>(component); + const CurveEval *curve = curve_component.get_for_read(); + if (curve) { + return construct_curve_length_varray(*curve, mask, domain); + } + } + } + return {}; + } + + uint64_t hash() const override + { + /* Some random constant hash. */ + return 345634563454; + } + + bool is_equal_to(const fn::FieldNode &other) const override + { + return dynamic_cast<const CurveLengthFieldInput *>(&other) != nullptr; + } +}; + +static void node_geo_exec(GeoNodeExecParams params) { Field<float> parameter_field{std::make_shared<CurveParameterFieldInput>()}; + Field<float> length_field{std::make_shared<CurveLengthFieldInput>()}; params.set_output("Factor", std::move(parameter_field)); + params.set_output("Length", std::move(length_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_parameter_cc void register_node_type_geo_curve_parameter() { - static bNodeType ntype; + namespace file_ns = blender::nodes::node_geo_curve_parameter_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PARAMETER, "Curve Parameter", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_parameter_exec; - ntype.declare = blender::nodes::geo_node_curve_parameter_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc index a755d47cc6a..a2ca41d8e19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_bezier_segment.cc @@ -21,34 +21,44 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc { -static void geo_node_curve_primitive_bezier_segment_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) .min(1) .max(256) - .subtype(PROP_UNSIGNED); + .subtype(PROP_UNSIGNED) + .description(N_("The number of evaluated points on the curve")); b.add_input<decl::Vector>(N_("Start")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the start control point of the curve")); b.add_input<decl::Vector>(N_("Start Handle")) .default_value({-0.5f, 0.5f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End Handle")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("Position of the start handle used to define the shape of the curve. In Offset mode, " + "relative to Start point")); + b.add_input<decl::Vector>(N_("End Handle")) + .subtype(PROP_TRANSLATION) + .description( + N_("Position of the end handle used to define the shape of the curve. In Offset mode, " + "relative to End point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({1.0f, 0.0f, 0.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the end control point of the curve")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_bezier_segment_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_bezier_segment_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveBezierSegment *data = (NodeGeometryCurvePrimitiveBezierSegment *) MEM_callocN(sizeof(NodeGeometryCurvePrimitiveBezierSegment), __func__); @@ -108,7 +118,7 @@ static std::unique_ptr<CurveEval> create_bezier_segment_curve( return curve; } -static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveBezierSegment *node_storage = (NodeGeometryCurvePrimitiveBezierSegment *)params.node().storage; @@ -125,20 +135,22 @@ static void geo_node_curve_primitive_bezier_segment_exec(GeoNodeExecParams param params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_bezier_segment_cc void register_node_type_geo_curve_primitive_bezier_segment() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_bezier_segment_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, "Bezier Segment", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_bezier_segment_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveBezierSegment", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_bezier_segment_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_bezier_segment_layout; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_bezier_segment_exec; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc index bf4f22d6578..f56571241f9 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc @@ -21,33 +21,48 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_circle_cc { -static void geo_node_curve_primitive_circle_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Resolution")).default_value(32).min(3).max(512); + b.add_input<decl::Int>(N_("Resolution")) + .default_value(32) + .min(3) + .max(512) + .description(N_("Number of points on the circle")); b.add_input<decl::Vector>(N_("Point 1")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); b.add_input<decl::Vector>(N_("Point 2")) .default_value({0.0f, 1.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); b.add_input<decl::Vector>(N_("Point 3")) .default_value({1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + .subtype(PROP_TRANSLATION) + .description( + N_("One of the three points on the circle. The point order determines the circle's " + "direction")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance of the points from the origin")); b.add_output<decl::Geometry>(N_("Curve")); b.add_output<decl::Vector>(N_("Center")); } -static void geo_node_curve_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveCircle *data = (NodeGeometryCurvePrimitiveCircle *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveCircle), __func__); @@ -56,7 +71,7 @@ static void geo_node_curve_primitive_circle_init(bNodeTree *UNUSED(tree), bNode node->storage = data; } -static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *) node->storage; @@ -70,11 +85,16 @@ static void geo_node_curve_primitive_circle_update(bNodeTree *UNUSED(ntree), bNo bNodeSocket *center_socket = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); - nodeSetSocketAvailability(radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); + nodeSetSocketAvailability( + ntree, start_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, middle_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, end_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, center_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS); + nodeSetSocketAvailability( + ntree, radius_socket, mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS); } static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3) @@ -173,7 +193,7 @@ static std::unique_ptr<CurveEval> create_radius_circle_curve(const int resolutio return curve; } -static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveCircle *node_storage = (NodeGeometryCurvePrimitiveCircle *)params.node().storage; @@ -204,22 +224,24 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_circle_cc void register_node_type_geo_curve_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_circle_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_circle_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_circle_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_circle_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc index 5b215797052..321fe6f2a9e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc @@ -21,25 +21,34 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_line_cc { -static void geo_node_curve_primitive_line_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Vector>(N_("Start")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({0.0f, 0.0f, 1.0f}).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("Direction")).default_value({0.0f, 0.0f, 1.0f}); - b.add_input<decl::Float>(N_("Length")).default_value(1.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Vector>(N_("Start")) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first control point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({0.0f, 0.0f, 1.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the second control point")); + b.add_input<decl::Vector>(N_("Direction")) + .default_value({0.0f, 0.0f, 1.0f}) + .description( + N_("Direction the line is going in. The length of this vector does not matter")); + b.add_input<decl::Float>(N_("Length")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance between the two points")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveLine), __func__); @@ -48,7 +57,7 @@ static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *n node->storage = data; } -static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *) node->storage; @@ -59,10 +68,11 @@ static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode bNodeSocket *direction_socket = p2_socket->next; bNodeSocket *length_socket = direction_socket->next; - nodeSetSocketAvailability(p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); - nodeSetSocketAvailability(direction_socket, - mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability(ntree, p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS); + nodeSetSocketAvailability( + ntree, direction_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); + nodeSetSocketAvailability( + ntree, length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION); } static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end) @@ -100,7 +110,7 @@ static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start return curve; } -static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveLine *node_storage = @@ -122,20 +132,22 @@ static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_line_cc void register_node_type_geo_curve_primitive_line() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveLine", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_curve_primitive_line_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_line_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc index 6041ddee02d..92a9b1b4966 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc @@ -17,22 +17,28 @@ #include "BKE_spline.hh" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc { -static void geo_node_curve_primitive_quadratic_bezier_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(16) .min(3) .max(256) - .subtype(PROP_UNSIGNED); + .subtype(PROP_UNSIGNED) + .description(N_("The number of edges on the curve")); b.add_input<decl::Vector>(N_("Start")) .default_value({-1.0f, 0.0f, 0.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first control point")); b.add_input<decl::Vector>(N_("Middle")) .default_value({0.0f, 2.0f, 0.0f}) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("End")).default_value({1.0f, 0.0f, 0.0f}).subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_("Position of the middle control point")); + b.add_input<decl::Vector>(N_("End")) + .default_value({1.0f, 0.0f, 0.0f}) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the last control point")); b.add_output<decl::Geometry>(N_("Curve")); } @@ -58,7 +64,7 @@ static std::unique_ptr<CurveEval> create_quadratic_bezier_curve(const float3 p1, return curve; } -static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_quadratic_bezier_curve( params.extract_input<float3>("Start"), @@ -68,17 +74,19 @@ static void geo_node_curve_primitive_quadratic_bezier_exec(GeoNodeExecParams par params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc void register_node_type_geo_curve_primitive_quadratic_bezier() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadratic_bezier_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, "Quadratic Bezier", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadratic_bezier_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadratic_bezier_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc index 7260da05a8d..53e301ecad7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc @@ -19,46 +19,70 @@ #include "UI_resources.h" #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc { -static void geo_node_curve_primitive_quadrilateral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Height")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Float>(N_("Width")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Height")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The Y axis size of the shape")); b.add_input<decl::Float>(N_("Bottom Width")) .default_value(4.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Top Width")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Offset")).default_value(1.0f).subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Top Width")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("The X axis size of the shape")); + b.add_input<decl::Float>(N_("Offset")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description( + N_("For Parallelogram, the relative X difference between the top and bottom edges. For " + "Trapezoid, the amount to move the top edge in the positive X axis")); b.add_input<decl::Float>(N_("Bottom Height")) .default_value(3.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Top Height")).default_value(1.0f).subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The distance between the bottom point and the X axis")); + b.add_input<decl::Float>(N_("Top Height")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("The distance between the top point and the X axis")); b.add_input<decl::Vector>(N_("Point 1")) .default_value({-1.0f, -1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 2")) .default_value({1.0f, -1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 3")) .default_value({1.0f, 1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_input<decl::Vector>(N_("Point 4")) .default_value({-1.0f, 1.0f, 0.0f}) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("The exact location of the point to use")); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN( sizeof(NodeGeometryCurvePrimitiveQuad), __func__); @@ -66,7 +90,7 @@ static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), node->storage = data; } -static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage; GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>( @@ -85,34 +109,34 @@ static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntre bNodeSocket *p4 = p3->next; LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) { - nodeSetSocketAvailability(sock, false); + nodeSetSocketAvailability(ntree, sock, false); } if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(height, true); - nodeSetSocketAvailability(offset, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, height, true); + nodeSetSocketAvailability(ntree, offset, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) { - nodeSetSocketAvailability(bottom, true); - nodeSetSocketAvailability(top, true); - nodeSetSocketAvailability(offset, true); - nodeSetSocketAvailability(height, true); + nodeSetSocketAvailability(ntree, bottom, true); + nodeSetSocketAvailability(ntree, top, true); + nodeSetSocketAvailability(ntree, offset, true); + nodeSetSocketAvailability(ntree, height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) { - nodeSetSocketAvailability(width, true); - nodeSetSocketAvailability(bottom_height, true); - nodeSetSocketAvailability(top_height, true); + nodeSetSocketAvailability(ntree, width, true); + nodeSetSocketAvailability(ntree, bottom_height, true); + nodeSetSocketAvailability(ntree, top_height, true); } else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) { - nodeSetSocketAvailability(p1, true); - nodeSetSocketAvailability(p2, true); - nodeSetSocketAvailability(p3, true); - nodeSetSocketAvailability(p4, true); + nodeSetSocketAvailability(ntree, p1, true); + nodeSetSocketAvailability(ntree, p2, true); + nodeSetSocketAvailability(ntree, p3, true); + nodeSetSocketAvailability(ntree, p4, true); } } @@ -171,7 +195,7 @@ static void create_kite_curve(MutableSpan<float3> positions, positions[3] = float3(-width / 2.0f, 0, 0); } -static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage; @@ -229,18 +253,20 @@ static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_quadrilaterial_cc void register_node_type_geo_curve_primitive_quadrilateral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_quadrilaterial_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_quadrilateral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_primitive_quadrilateral_layout; - node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update); - node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurvePrimitiveQuad", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc index 1dc9cd7f107..3be119a073f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_spiral.cc @@ -18,20 +18,34 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_spiral_cc { -static void geo_node_curve_primitive_spiral_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Resolution")) .default_value(32) .min(1) .max(1024) - .subtype(PROP_UNSIGNED); - b.add_input<decl::Float>(N_("Rotations")).default_value(2.0f).min(0.0f); - b.add_input<decl::Float>(N_("Start Radius")).default_value(1.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("End Radius")).default_value(2.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Height")).default_value(2.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Bool>(N_("Reverse")); + .subtype(PROP_UNSIGNED) + .description(N_("Number of points in one rotation of the spiral")); + b.add_input<decl::Float>(N_("Rotations")) + .default_value(2.0f) + .min(0.0f) + .description(N_("Number of times the spiral makes a full rotation")); + b.add_input<decl::Float>(N_("Start Radius")) + .default_value(1.0f) + .subtype(PROP_DISTANCE) + .description(N_("Horizontal Distance from the Z axis at the start of the spiral")); + b.add_input<decl::Float>(N_("End Radius")) + .default_value(2.0f) + .subtype(PROP_DISTANCE) + .description(N_("Horizontal Distance from the Z axis at the end of the spiral")); + b.add_input<decl::Float>(N_("Height")) + .default_value(2.0f) + .subtype(PROP_DISTANCE) + .description(N_("The height perpendicular to the base of the spiral")); + b.add_input<decl::Bool>(N_("Reverse")) + .description(N_("Switch the direction from clockwise to counterclockwise")); b.add_output<decl::Geometry>(N_("Curve")); } @@ -67,7 +81,7 @@ static std::unique_ptr<CurveEval> create_spiral_curve(const float rotations, return curve; } -static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float rotations = std::max(params.extract_input<float>("Rotations"), 0.0f); if (rotations == 0.0f) { @@ -85,14 +99,16 @@ static void geo_node_curve_primitive_spiral_exec(GeoNodeExecParams params) params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_primitive_spiral_cc void register_node_type_geo_curve_primitive_spiral() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_spiral_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, "Spiral", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_spiral_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_spiral_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc index b5bafce17c6..731be0f0f49 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc @@ -18,21 +18,33 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_primitive_star_cc { -static void geo_node_curve_primitive_star_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Points")).default_value(8).min(3).max(256).subtype(PROP_UNSIGNED); + b.add_input<decl::Int>(N_("Points")) + .default_value(8) + .min(3) + .max(256) + .subtype(PROP_UNSIGNED) + .description(N_("Number of points on each of the circles")); b.add_input<decl::Float>(N_("Inner Radius")) .default_value(1.0f) .min(0.0f) - .subtype(PROP_DISTANCE); + .subtype(PROP_DISTANCE) + .description(N_("Radius of the inner circle; can be larger than outer radius")); b.add_input<decl::Float>(N_("Outer Radius")) .default_value(2.0f) .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Twist")).subtype(PROP_ANGLE); + .subtype(PROP_DISTANCE) + .description(N_("Radius of the outer circle; can be smaller than inner radius")); + b.add_input<decl::Float>(N_("Twist")) + .subtype(PROP_ANGLE) + .description(N_("The counterclockwise rotation of the inner set of points")); b.add_output<decl::Geometry>(N_("Curve")); + b.add_output<decl::Bool>(N_("Outer Points")) + .field_source() + .description(N_("An attribute field with a selection of the outer points")); } static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, @@ -57,26 +69,49 @@ static std::unique_ptr<CurveEval> create_star_curve(const float inner_radius, spline->attributes.reallocate(spline->size()); curve->add_spline(std::move(spline)); curve->attributes.reallocate(curve->splines().size()); + return curve; } -static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params) +static void create_selection_output(CurveComponent &component, + StrongAnonymousAttributeID &r_attribute) +{ + OutputAttribute_Typed<bool> attribute = component.attribute_try_get_for_output_only<bool>( + r_attribute.get(), ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + for (int i : selection.index_range()) { + selection[i] = i % 2 == 0; + } + attribute.save(); +} + +static void node_geo_exec(GeoNodeExecParams params) { std::unique_ptr<CurveEval> curve = create_star_curve( std::max(params.extract_input<float>("Inner Radius"), 0.0f), std::max(params.extract_input<float>("Outer Radius"), 0.0f), params.extract_input<float>("Twist"), std::max(params.extract_input<int>("Points"), 3)); - params.set_output("Curve", GeometrySet::create_with_curve(curve.release())); -} + GeometrySet output = GeometrySet::create_with_curve(curve.release()); -} // namespace blender::nodes + if (params.output_is_required("Outer Points")) { + StrongAnonymousAttributeID attribute_output("Outer Points"); + create_selection_output(output.get_component_for_write<CurveComponent>(), attribute_output); + params.set_output("Outer Points", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_output), params.attribute_producer_name())); + } + params.set_output("Curve", std::move(output)); +} +} // namespace blender::nodes::node_geo_curve_primitive_star_cc void register_node_type_geo_curve_primitive_star() { + namespace file_ns = blender::nodes::node_geo_curve_primitive_star_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_STAR, "Star", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_primitive_star_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_star_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc index 945dac5650b..dec72eb61bb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc @@ -26,15 +26,12 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_curve_resample_cc { -namespace blender::nodes { - -static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); + b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(100000).supports_field(); b.add_input<decl::Float>(N_("Length")) .default_value(0.1f) @@ -44,12 +41,12 @@ static void geo_node_curve_resample_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_resample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveResample *data = (NodeGeometryCurveResample *)MEM_callocN( sizeof(NodeGeometryCurveResample), __func__); @@ -58,22 +55,23 @@ static void geo_node_curve_resample_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_resample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveResample &node_storage = *(NodeGeometryCurveResample *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; - bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; + bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } struct SampleModeParam { GeometryNodeCurveResampleMode mode; std::optional<Field<float>> length; std::optional<Field<int>> count; + Field<bool> selection; }; static SplinePtr resample_spline(const Spline &src, const int count) @@ -122,7 +120,7 @@ static SplinePtr resample_spline(const Spline &src, const int count) std::optional<GMutableSpan> output_attribute = dst->attributes.get_for_write( attribute_id); if (output_attribute) { - src.sample_with_index_factors(*src.interpolate_to_evaluated(*input_attribute), + src.sample_with_index_factors(src.interpolate_to_evaluated(*input_attribute), uniform_samples, *output_attribute); return true; @@ -145,8 +143,8 @@ static SplinePtr resample_spline_evaluated(const Spline &src) dst->positions().copy_from(src.evaluated_positions()); dst->positions().copy_from(src.evaluated_positions()); - src.interpolate_to_evaluated(src.radii())->materialize(dst->radii()); - src.interpolate_to_evaluated(src.tilts())->materialize(dst->tilts()); + src.interpolate_to_evaluated(src.radii()).materialize(dst->radii()); + src.interpolate_to_evaluated(src.tilts()).materialize(dst->tilts()); src.attributes.foreach_attribute( [&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) { @@ -154,7 +152,7 @@ static SplinePtr resample_spline_evaluated(const Spline &src) if (dst->attributes.create(attribute_id, meta_data.data_type)) { std::optional<GMutableSpan> dst_attribute = dst->attributes.get_for_write(attribute_id); if (dst_attribute) { - src.interpolate_to_evaluated(*src_attribute)->materialize(dst_attribute->data()); + src.interpolate_to_evaluated(*src_attribute).materialize(dst_attribute->data()); return true; } } @@ -183,42 +181,64 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveComponent *component if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_COUNT) { fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(*mode_param.count); + evaluator.add(mode_param.selection); evaluator.evaluate(); const VArray<int> &cuts = evaluator.get_evaluated<int>(0); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(1); threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { BLI_assert(mode_param.count); - output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1)); + if (selections[i]) { + output_splines[i] = resample_spline(*input_splines[i], std::max(cuts[i], 1)); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_LENGTH) { fn::FieldEvaluator evaluator{field_context, domain_size}; evaluator.add(*mode_param.length); + evaluator.add(mode_param.selection); evaluator.evaluate(); const VArray<float> &lengths = evaluator.get_evaluated<float>(0); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(1); threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - /* Don't allow asymptotic count increase for low resolution values. */ - const float divide_length = std::max(lengths[i], 0.0001f); - const float spline_length = input_splines[i]->length(); - const int count = std::max(int(spline_length / divide_length) + 1, 1); - output_splines[i] = resample_spline(*input_splines[i], count); + if (selections[i]) { + /* Don't allow asymptotic count increase for low resolution values. */ + const float divide_length = std::max(lengths[i], 0.0001f); + const float spline_length = input_splines[i]->length(); + const int count = std::max(int(spline_length / divide_length) + 1, 1); + output_splines[i] = resample_spline(*input_splines[i], count); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } else if (mode_param.mode == GEO_NODE_CURVE_RESAMPLE_EVALUATED) { + fn::FieldEvaluator evaluator{field_context, domain_size}; + evaluator.add(mode_param.selection); + evaluator.evaluate(); + const VArray<bool> &selections = evaluator.get_evaluated<bool>(0); + threading::parallel_for(input_splines.index_range(), 128, [&](IndexRange range) { for (const int i : range) { - output_splines[i] = resample_spline_evaluated(*input_splines[i]); + if (selections[i]) { + output_splines[i] = resample_spline_evaluated(*input_splines[i]); + } + else { + output_splines[i] = input_splines[i]->copy(); + } } }); } - output_curve->attributes = input_curve->attributes; - return output_curve; } @@ -235,7 +255,7 @@ static void geometry_set_curve_resample(GeometrySet &geometry_set, geometry_set.replace_curve(output_curve.release()); } -static void geo_node_resample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -244,6 +264,8 @@ static void geo_node_resample_exec(GeoNodeExecParams params) SampleModeParam mode_param; mode_param.mode = mode; + mode_param.selection = params.extract_input<Field<bool>>("Selection"); + if (mode == GEO_NODE_CURVE_RESAMPLE_COUNT) { Field<int> count = params.extract_input<Field<int>>("Count"); if (count < 1) { @@ -263,19 +285,21 @@ static void geo_node_resample_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_resample_cc void register_node_type_geo_curve_resample() { + namespace file_ns = blender::nodes::node_geo_curve_resample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RESAMPLE_CURVE, "Resample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_resample_declare; - ntype.draw_buttons = blender::nodes::geo_node_curve_resample_layout; + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveResample", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_resample_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_resample_update); - ntype.geometry_node_execute = blender::nodes::geo_node_resample_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc index b1dc45a426a..d07e89ec7f2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_reverse.cc @@ -20,16 +20,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_reverse_cc { -static void geo_node_curve_reverse_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_reverse_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -60,13 +60,15 @@ static void geo_node_curve_reverse_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_reverse_cc void register_node_type_geo_curve_reverse() { + namespace file_ns = blender::nodes::node_geo_curve_reverse_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_REVERSE_CURVE, "Reverse Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_reverse_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_reverse_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc index 31b38c0dce7..b81860ca9b3 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_sample.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_sample_cc { -static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")) .only_realized_data() @@ -38,12 +38,12 @@ static void geo_node_curve_sample_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Normal")).dependent_field(); } -static void geo_node_curve_sample_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_type_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSample *data = (NodeGeometryCurveSample *)MEM_callocN( sizeof(NodeGeometryCurveSample), __func__); @@ -51,7 +51,7 @@ static void geo_node_curve_sample_type_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveSample &node_storage = *(NodeGeometryCurveSample *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -59,8 +59,8 @@ static void geo_node_curve_sample_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *factor = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length = factor->next; - nodeSetSocketAvailability(factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, factor, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, length, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } template<typename T> static T sample_with_lookup(const Spline::LookupResult lookup, Span<T> data) @@ -229,7 +229,7 @@ static Field<float> get_length_input_field(const GeoNodeExecParams ¶ms, return Field<float>(std::move(process_op), 0); } -static void geo_node_curve_sample_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); @@ -271,20 +271,22 @@ static void geo_node_curve_sample_exec(GeoNodeExecParams params) params.set_output("Normal", Field<float3>(sample_op, 2)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_sample_cc void register_node_type_geo_curve_sample() { + namespace file_ns = blender::nodes::node_geo_curve_sample_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SAMPLE_CURVE, " Sample Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_sample_exec; - ntype.declare = blender::nodes::geo_node_curve_sample_declare; - node_type_init(&ntype, blender::nodes::geo_node_curve_sample_type_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_sample_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_type_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryCurveSample", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_sample_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc index 8b0a6ca840c..d769228f9e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_set_handles.cc @@ -21,24 +21,22 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_set_handles_cc { -static void geo_node_curve_set_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_set_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); uiItemR(layout, ptr, "handle_type", 0, "", ICON_NONE); } -static void geo_node_curve_set_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSetHandles *data = (NodeGeometryCurveSetHandles *)MEM_callocN( sizeof(NodeGeometryCurveSetHandles), __func__); @@ -64,7 +62,7 @@ static BezierSpline::HandleType handle_type_from_input_type(GeometryNodeCurveHan return BezierSpline::HandleType::Auto; } -static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSetHandles *node_storage = (NodeGeometryCurveSetHandles *)params.node().storage; @@ -130,21 +128,23 @@ static void geo_node_curve_set_handles_exec(GeoNodeExecParams params) } params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_set_handles_cc void register_node_type_geo_curve_set_handles() { + namespace file_ns = blender::nodes::node_geo_curve_set_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SET_HANDLES, "Set Handle Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_set_handles_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_set_handles_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_set_handles_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSetHandles", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_set_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc index ae4453929ac..1d859c8555f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_spline_type.cc @@ -23,23 +23,21 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_spline_type_cc { -static void geo_node_curve_spline_type_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_spline_type_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "spline_type", 0, "", ICON_NONE); } -static void geo_node_curve_spline_type_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveSplineType *data = (NodeGeometryCurveSplineType *)MEM_callocN( sizeof(NodeGeometryCurveSplineType), __func__); @@ -238,7 +236,7 @@ static SplinePtr convert_to_nurbs(const Spline &input) return {}; } -static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveSplineType *storage = (const NodeGeometryCurveSplineType *)params.node().storage; @@ -288,21 +286,23 @@ static void geo_node_curve_spline_type_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_spline_type_cc void register_node_type_geo_curve_spline_type() { + namespace file_ns = blender::nodes::node_geo_curve_spline_type_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_CURVE_SPLINE_TYPE, "Set Spline Type", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_spline_type_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_spline_type_exec; - node_type_init(&ntype, blender::nodes::geo_node_curve_spline_type_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometryCurveSplineType", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_curve_spline_type_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc index b52de822c22..6de188fc1c4 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc @@ -25,13 +25,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; -using blender::fn::GVArray_For_Span; -using blender::fn::GVArray_Typed; +namespace blender::nodes::node_geo_curve_subdivide_cc { -namespace blender::nodes { - -static void geo_node_curve_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Cuts")).default_value(1).min(0).max(1000).supports_field(); @@ -326,7 +322,7 @@ static std::unique_ptr<CurveEval> subdivide_curve(const CurveEval &input_curve, return output_curve; } -static void geo_node_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<int> cuts_field = params.extract_input<Field<int>>("Cuts"); @@ -355,14 +351,16 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params) params.set_output("Curve", geometry_set); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_subdivide_cc void register_node_type_geo_curve_subdivide() { + namespace file_ns = blender::nodes::node_geo_curve_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_CURVE, "Subdivide Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc index 1977b465de4..ff3e85cb6b7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_curve_to_mesh_cc { -static void geo_node_curve_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Geometry>(N_("Profile Curve")) @@ -54,7 +54,7 @@ static void geometry_set_curve_to_mesh(GeometrySet &geometry_set, } } -static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet curve_set = params.extract_input<GeometrySet>("Curve"); GeometrySet profile_set = params.extract_input<GeometrySet>("Profile Curve"); @@ -72,14 +72,16 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(curve_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_mesh_cc void register_node_type_geo_curve_to_mesh() { + namespace file_ns = blender::nodes::node_geo_curve_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_MESH, "Curve to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_mesh_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_mesh_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc index 38d7fb99e87..1901097c369 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc @@ -27,8 +27,22 @@ #include "node_geometry_util.hh" namespace blender::nodes { +void curve_create_default_rotation_attribute(Span<float3> tangents, + Span<float3> normals, + MutableSpan<float3> rotations) +{ + threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { + for (const int i : range) { + rotations[i] = + float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); + } + }); +} +} // namespace blender::nodes + +namespace blender::nodes::node_geo_curve_to_points_cc { -static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Int>(N_("Count")).default_value(10).min(2).max(100000); @@ -39,12 +53,12 @@ static void geo_node_curve_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Vector>(N_("Rotation")).field_source(); } -static void geo_node_curve_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveToPoints *data = (NodeGeometryCurveToPoints *)MEM_callocN( sizeof(NodeGeometryCurveToPoints), __func__); @@ -53,7 +67,7 @@ static void geo_node_curve_to_points_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)node->storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -61,8 +75,8 @@ static void geo_node_curve_to_points_update(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *count_socket = ((bNodeSocket *)node->inputs.first)->next; bNodeSocket *length_socket = count_socket->next; - nodeSetSocketAvailability(count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); - nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, count_socket, mode == GEO_NODE_CURVE_RESAMPLE_COUNT); + nodeSetSocketAvailability(ntree, length_socket, mode == GEO_NODE_CURVE_RESAMPLE_LENGTH); } static Array<int> calculate_spline_point_offsets(GeoNodeExecParams ¶ms, @@ -113,7 +127,7 @@ static GMutableSpan ensure_point_attribute(PointCloudComponent &points, points.attribute_try_create(attribute_id, ATTR_DOMAIN_POINT, data_type, AttributeInitDefault()); WriteAttributeLookup attribute = points.attribute_try_get_for_write(attribute_id); BLI_assert(attribute); - return attribute.varray->get_internal_span(); + return attribute.varray.get_internal_span(); } template<typename T> @@ -194,7 +208,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, const int size = offsets[i + 1] - offsets[i]; data.positions.slice(offset, size).copy_from(spline.evaluated_positions()); - spline.interpolate_to_evaluated(spline.radii())->materialize(data.radii.slice(offset, size)); + spline.interpolate_to_evaluated(spline.radii()).materialize(data.radii.slice(offset, size)); for (const Map<AttributeIDRef, GMutableSpan>::Item item : data.point_attributes.items()) { const AttributeIDRef attribute_id = item.key; @@ -203,7 +217,7 @@ static void copy_evaluated_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.interpolate_to_evaluated(spline_span)->materialize(dst.slice(offset, size).data()); + spline.interpolate_to_evaluated(spline_span).materialize(dst.slice(offset, size).data()); } if (!data.tangents.is_empty()) { @@ -233,7 +247,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, spline.sample_with_index_factors<float3>( spline.evaluated_positions(), uniform_samples, data.positions.slice(offset, size)); - spline.sample_with_index_factors<float>(*spline.interpolate_to_evaluated(spline.radii()), + spline.sample_with_index_factors<float>(spline.interpolate_to_evaluated(spline.radii()), uniform_samples, data.radii.slice(offset, size)); @@ -244,7 +258,7 @@ static void copy_uniform_sample_point_attributes(const Span<SplinePtr> splines, BLI_assert(spline.attributes.get_for_read(attribute_id)); GSpan spline_span = *spline.attributes.get_for_read(attribute_id); - spline.sample_with_index_factors(*spline.interpolate_to_evaluated(spline_span), + spline.sample_with_index_factors(spline.interpolate_to_evaluated(spline_span), uniform_samples, dst.slice(offset, size)); } @@ -289,19 +303,7 @@ static void copy_spline_domain_attributes(const CurveEval &curve, ATTR_DOMAIN_CURVE); } -void curve_create_default_rotation_attribute(Span<float3> tangents, - Span<float3> normals, - MutableSpan<float3> rotations) -{ - threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) { - for (const int i : range) { - rotations[i] = - float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler(); - } - }); -} - -static void geo_node_curve_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { NodeGeometryCurveToPoints &node_storage = *(NodeGeometryCurveToPoints *)params.node().storage; const GeometryNodeCurveResampleMode mode = (GeometryNodeCurveResampleMode)node_storage.mode; @@ -374,20 +376,22 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_to_points_cc void register_node_type_geo_curve_to_points() { + namespace file_ns = blender::nodes::node_geo_curve_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_CURVE_TO_POINTS, "Curve to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_curve_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_curve_to_points_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryCurveToPoints", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_to_points_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_to_points_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc index 4e1a2910c7c..127164b0ab0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_curve_trim.cc @@ -22,11 +22,11 @@ #include "node_geometry_util.hh" -using blender::attribute_math::mix2; +namespace blender::nodes::node_geo_curve_trim_cc { -namespace blender::nodes { +using blender::attribute_math::mix2; -static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Float>(N_("Start")).min(0.0f).max(1.0f).subtype(PROP_FACTOR).supports_field(); @@ -48,12 +48,12 @@ static void geo_node_curve_trim_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_curve_trim_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryCurveTrim *data = (NodeGeometryCurveTrim *)MEM_callocN(sizeof(NodeGeometryCurveTrim), __func__); @@ -62,7 +62,7 @@ static void geo_node_curve_trim_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)node->storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -72,10 +72,10 @@ static void geo_node_curve_trim_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *start_len = end_fac->next; bNodeSocket *end_len = start_len->next; - nodeSetSocketAvailability(start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); - nodeSetSocketAvailability(start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); - nodeSetSocketAvailability(end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, start_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, end_fac, mode == GEO_NODE_CURVE_SAMPLE_FACTOR); + nodeSetSocketAvailability(ntree, start_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); + nodeSetSocketAvailability(ntree, end_len, mode == GEO_NODE_CURVE_SAMPLE_LENGTH); } struct TrimLocation { @@ -216,9 +216,9 @@ static PolySpline trim_nurbs_spline(const Spline &spline, attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); linear_trim_to_output_data<T>( - start, end, eval_data->get_internal_span(), dst->typed<T>()); + start, end, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -227,13 +227,13 @@ static PolySpline trim_nurbs_spline(const Spline &spline, linear_trim_to_output_data<float3>( start, end, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); linear_trim_to_output_data<float>( - start, end, evaluated_radii->get_internal_span(), new_spline.radii()); + start, end, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); linear_trim_to_output_data<float>( - start, end, evaluated_tilts->get_internal_span(), new_spline.tilts()); + start, end, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } @@ -427,8 +427,8 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look std::optional<GMutableSpan> dst = new_spline.attributes.get_for_write(attribute_id); attribute_math::convert_to_static_type(src->type(), [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); - to_single_point_data<T>(trim, eval_data->get_internal_span(), dst->typed<T>()); + VArray<T> eval_data = spline.interpolate_to_evaluated<T>(src->typed<T>()); + to_single_point_data<T>(trim, eval_data.get_internal_span(), dst->typed<T>()); }); return true; }, @@ -436,11 +436,11 @@ static PolySpline to_single_point_nurbs(const Spline &spline, const Spline::Look to_single_point_data<float3>(trim, spline.evaluated_positions(), new_spline.positions()); - GVArray_Typed<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); - to_single_point_data<float>(trim, evaluated_radii->get_internal_span(), new_spline.radii()); + VArray<float> evaluated_radii = spline.interpolate_to_evaluated(spline.radii()); + to_single_point_data<float>(trim, evaluated_radii.get_internal_span(), new_spline.radii()); - GVArray_Typed<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); - to_single_point_data<float>(trim, evaluated_tilts->get_internal_span(), new_spline.tilts()); + VArray<float> evaluated_tilts = spline.interpolate_to_evaluated(spline.tilts()); + to_single_point_data<float>(trim, evaluated_tilts.get_internal_span(), new_spline.tilts()); return new_spline; } @@ -532,7 +532,7 @@ static void geometry_set_curve_trim(GeometrySet &geometry_set, }); } -static void geo_node_curve_trim_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryCurveTrim &node_storage = *(NodeGeometryCurveTrim *)params.node().storage; const GeometryNodeCurveSampleMode mode = (GeometryNodeCurveSampleMode)node_storage.mode; @@ -557,18 +557,20 @@ static void geo_node_curve_trim_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_curve_trim_cc void register_node_type_geo_curve_trim() { + namespace file_ns = blender::nodes::node_geo_curve_trim_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIM_CURVE, "Trim Curve", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_curve_trim_exec; - ntype.draw_buttons = blender::nodes::geo_node_curve_trim_layout; - ntype.declare = blender::nodes::geo_node_curve_trim_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryCurveTrim", node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_curve_trim_init); - node_type_update(&ntype, blender::nodes::geo_node_curve_trim_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc index b0df6428a06..055e44998cb 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc @@ -29,58 +29,24 @@ #include "node_geometry_util.hh" -using blender::bke::CustomDataAttributes; - /* Code from the mask modifier in MOD_mask.cc. */ -extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map); -extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map); -extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, - Mesh &dst_mesh, - blender::Span<int> vertex_map, - blender::Span<int> edge_map, - blender::Span<int> masked_poly_indices, - blender::Span<int> new_loop_starts); +void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map); +void copy_masked_edges_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map); +void copy_masked_polys_to_new_mesh(const Mesh &src_mesh, + Mesh &dst_mesh, + blender::Span<int> vertex_map, + blender::Span<int> edge_map, + blender::Span<int> masked_poly_indices, + blender::Span<int> new_loop_starts); namespace blender::nodes { -static void geo_node_delete_geometry_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Bool>(N_("Selection")) - .default_value(true) - .hide_value() - .supports_field() - .description(N_("The parts of the geometry to be deleted")); - b.add_output<decl::Geometry>(N_("Geometry")); -} - -static void geo_node_delete_geometry_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - const bNode *node = static_cast<bNode *>(ptr->data); - const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; - const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); - - uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); - /* Only show the mode when it is relevant. */ - if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { - uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); - } -} - -static void geo_node_delete_geometry_init(bNodeTree *UNUSED(tree), bNode *node) -{ - NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( - sizeof(NodeGeometryDeleteGeometry), __func__); - data->domain = ATTR_DOMAIN_POINT; - data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; - - node->storage = data; -} +using blender::bke::CustomDataAttributes; template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask) { @@ -138,7 +104,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes if (!domains.contains(attribute.domain)) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -149,7 +115,7 @@ static void copy_attributes(const Map<AttributeIDRef, AttributeKind> &attributes attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); out_span.copy_from(span); }); @@ -178,7 +144,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin if (domain != attribute.domain) { continue; } - const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray->type()); + const CustomDataType data_type = bke::cpp_type_to_custom_data_type(attribute.varray.type()); OutputAttribute result_attribute = result_component.attribute_try_get_for_output_only( attribute_id, attribute.domain, data_type); @@ -189,7 +155,7 @@ static void copy_attributes_based_on_mask(const Map<AttributeIDRef, AttributeKin attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Span<T> span{*attribute.varray}; + VArray_Span<T> span{attribute.varray.typed<T>()}; MutableSpan<T> out_span = result_attribute.as_span<T>(); copy_data(span, out_span, mask); }); @@ -1209,7 +1175,45 @@ void separate_geometry(GeometrySet &geometry_set, r_is_error = !some_valid_domain && geometry_set.has_realized_data(); } -static void geo_node_delete_geometry_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_delete_geometry_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Bool>(N_("Selection")) + .default_value(true) + .hide_value() + .supports_field() + .description(N_("The parts of the geometry to be deleted")); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + const bNode *node = static_cast<bNode *>(ptr->data); + const NodeGeometryDeleteGeometry &storage = *(const NodeGeometryDeleteGeometry *)node->storage; + const AttributeDomain domain = static_cast<AttributeDomain>(storage.domain); + + uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); + /* Only show the mode when it is relevant. */ + if (ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_EDGE, ATTR_DOMAIN_FACE)) { + uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); + } +} + +static void node_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeGeometryDeleteGeometry *data = (NodeGeometryDeleteGeometry *)MEM_callocN( + sizeof(NodeGeometryDeleteGeometry), __func__); + data->domain = ATTR_DOMAIN_POINT; + data->mode = GEO_NODE_DELETE_GEOMETRY_MODE_ALL; + + node->storage = data; +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -1236,10 +1240,12 @@ static void geo_node_delete_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_delete_geometry_cc void register_node_type_geo_delete_geometry() { + namespace file_ns = blender::nodes::node_geo_delete_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0); @@ -1249,10 +1255,10 @@ void register_node_type_geo_delete_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_delete_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_delete_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_delete_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc index 115ad09a9e6..adb698b8f7a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_on_faces.cc @@ -36,11 +36,9 @@ #include "node_geometry_util.hh" -using blender::bke::GeometryInstanceGroup; +namespace blender::nodes::node_geo_distribute_points_on_faces_cc { -namespace blender::nodes { - -static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -60,26 +58,26 @@ static void geo_node_point_distribute_points_on_faces_declare(NodeDeclarationBui b.add_output<decl::Vector>(N_("Rotation")).subtype(PROP_EULER).field_source(); } -static void geo_node_point_distribute_points_on_faces_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribute_method", 0, "", ICON_NONE); } -static void node_point_distribute_points_on_faces_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_point_distribute_points_on_faces_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_distance_min = (bNodeSocket *)BLI_findlink(&node->inputs, 2); bNodeSocket *sock_density_max = (bNodeSocket *)sock_distance_min->next; bNodeSocket *sock_density = sock_density_max->next; bNodeSocket *sock_density_factor = sock_density->next; - nodeSetSocketAvailability(sock_distance_min, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density_max, + nodeSetSocketAvailability(ntree, + sock_distance_min, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); - nodeSetSocketAvailability(sock_density, - node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); - nodeSetSocketAvailability(sock_density_factor, + nodeSetSocketAvailability( + ntree, sock_density_max, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); + nodeSetSocketAvailability( + ntree, sock_density, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_RANDOM); + nodeSetSocketAvailability(ntree, + sock_density_factor, node->custom1 == GEO_NODE_POINT_DISTRIBUTE_POINTS_ON_FACES_POISSON); } @@ -313,7 +311,7 @@ BLI_NOINLINE static void propagate_existing_attributes( bary_coords, looptri_indices, source_attribute.domain, - *source_attribute.varray, + source_attribute.varray, out_span); attribute_out.save(); } @@ -526,7 +524,7 @@ static void point_distribution_calculate(GeometrySet &geometry_set, mesh_component, point_component, bary_coords, looptri_indices, attribute_outputs); } -static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -568,10 +566,12 @@ static void geo_node_point_distribute_points_on_faces_exec(GeoNodeExecParams par } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_distribute_points_on_faces_cc void register_node_type_geo_distribute_points_on_faces() { + namespace file_ns = blender::nodes::node_geo_distribute_points_on_faces_cc; + static bNodeType ntype; geo_node_type_base(&ntype, @@ -579,10 +579,10 @@ void register_node_type_geo_distribute_points_on_faces() "Distribute Points on Faces", NODE_CLASS_GEOMETRY, 0); - node_type_update(&ntype, blender::nodes::node_point_distribute_points_on_faces_update); + node_type_update(&ntype, file_ns::node_point_distribute_points_on_faces_update); node_type_size(&ntype, 170, 100, 320); - ntype.declare = blender::nodes::geo_node_point_distribute_points_on_faces_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_point_distribute_points_on_faces_exec; - ntype.draw_buttons = blender::nodes::geo_node_point_distribute_points_on_faces_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc index f562fb29e90..d23a18ba37b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc @@ -22,9 +22,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_edge_split_cc { -static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -33,12 +33,13 @@ static void geo_node_edge_split_declare(NodeDeclarationBuilder &b) static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection) { - const BMeshCreateParams bmcp = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; const BMAllocTemplate allocsize = {0, 0, 0, 0}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); - BMeshFromMeshParams params{}; - BM_mesh_bm_from_me(bm, &mesh, ¶ms); + BMeshFromMeshParams bmesh_from_mesh_params{}; + BM_mesh_bm_from_me(bm, &mesh, &bmesh_from_mesh_params); BM_mesh_elem_table_ensure(bm, BM_EDGE); for (const int i : selection) { @@ -56,7 +57,7 @@ static Mesh *mesh_edge_split(const Mesh &mesh, const IndexMask selection) return result; } -static void geo_node_edge_split_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -81,14 +82,16 @@ static void geo_node_edge_split_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_edge_split_cc void register_node_type_geo_edge_split() { + namespace file_ns = blender::nodes::node_geo_edge_split_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SPLIT_EDGES, "Split Edges", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_edge_split_exec; - ntype.declare = blender::nodes::geo_node_edge_split_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc index e1c72fbd438..c56d920fac5 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_image_texture.cc @@ -32,9 +32,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_image_texture_cc { -static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Image>(N_("Image")).hide_label(); b.add_input<decl::Vector>(N_("Vector")) @@ -45,13 +45,13 @@ static void geo_node_image_texture_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Alpha")).no_muted_links().dependent_field(); } -static void geo_node_image_texture_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "interpolation", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); uiItemR(layout, ptr, "extension", UI_ITEM_R_SPLIT_EMPTY_NAME, "", ICON_NONE); } -static void geo_node_image_texture_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryImageTexture *tex = (NodeGeometryImageTexture *)MEM_callocN( sizeof(NodeGeometryImageTexture), __func__); @@ -82,7 +82,7 @@ class ImageFieldsFunction : public fn::MultiFunction { image_buffer_ = BKE_image_acquire_ibuf(&image_, &image_user_, &image_lock_); if (image_buffer_ == nullptr) { - throw std::runtime_error("cannot aquire image buffer"); + throw std::runtime_error("cannot acquire image buffer"); } if (image_buffer_->rect_float == nullptr) { @@ -370,7 +370,7 @@ class ImageFieldsFunction : public fn::MultiFunction { } }; -static void geo_node_image_texture_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { auto return_default = [&]() { params.set_output("Color", ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f)); @@ -410,20 +410,22 @@ static void geo_node_image_texture_exec(GeoNodeExecParams params) params.set_output("Alpha", Field<float>(image_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_image_texture_cc void register_node_type_geo_image_texture(void) { + namespace file_ns = blender::nodes::node_geo_image_texture_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IMAGE_TEXTURE, "Image Texture", NODE_CLASS_TEXTURE, 0); - ntype.declare = blender::nodes::geo_node_image_texture_declare; - ntype.draw_buttons = blender::nodes::geo_node_image_texture_layout; - node_type_init(&ntype, blender::nodes::geo_node_image_texture_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryImageTexture", node_free_standard_storage, node_copy_standard_storage); node_type_size_preset(&ntype, NODE_SIZE_LARGE); - ntype.geometry_node_execute = blender::nodes::geo_node_image_texture_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc index b8df545d073..dae8fda2099 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_handles.cc @@ -16,15 +16,15 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_handles_cc { -static void geo_node_input_curve_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Left")).field_source(); b.add_output<decl::Vector>(N_("Right")).field_source(); } -static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> left_field = AttributeFieldInput::Create<float3>("handle_left"); Field<float3> right_field = AttributeFieldInput::Create<float3>("handle_right"); @@ -32,15 +32,17 @@ static void geo_node_input_curve_handles_exec(GeoNodeExecParams params) params.set_output("Right", std::move(right_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_handles_cc void register_node_type_geo_input_curve_handles() { + namespace file_ns = blender::nodes::node_geo_input_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_CURVE_HANDLES, "Curve Handle Positions", NODE_CLASS_INPUT, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_input_curve_handles_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc index f32db3842db..5ba85b6f34e 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_curve_tilt.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_curve_tilt_cc { -static void geo_node_input_curve_tilt_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Tilt")).field_source(); } -static void geo_node_input_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> tilt_field = AttributeFieldInput::Create<float>("tilt"); params.set_output("Tilt", std::move(tilt_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_curve_tilt_cc void register_node_type_geo_input_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_input_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_CURVE_TILT, "Curve Tilt", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_input_curve_tilt_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc index 37d5bac0325..d2e103a093a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_id.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_id_cc { -static void geo_node_input_id_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("ID")).field_source(); } -static void geo_node_input_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> position_field{std::make_shared<bke::IDAttributeFieldInput>()}; params.set_output("ID", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_id_cc void register_node_type_geo_input_id() { + namespace file_ns = blender::nodes::node_geo_input_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_ID, "ID", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_id_exec; - ntype.declare = blender::nodes::geo_node_input_id_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc index 6200ac5e7a8..74cddfc6a4a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_index_cc { -static void geo_node_input_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Index")).field_source(); } -static void geo_node_input_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> index_field{std::make_shared<fn::IndexFieldInput>()}; params.set_output("Index", std::move(index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_index_cc void register_node_type_geo_input_index() { + namespace file_ns = blender::nodes::node_geo_input_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_INDEX, "Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_index_exec; - ntype.declare = blender::nodes::geo_node_input_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc index fc41188dee5..1b6e3c8fc68 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material.cc @@ -19,33 +19,35 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_cc { -static void geo_node_input_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Material>(N_("Material")); } -static void geo_node_input_material_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "material", 0, "", ICON_NONE); } -static void geo_node_input_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = (Material *)params.node().id; params.set_output("Material", material); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_cc void register_node_type_geo_input_material() { + namespace file_ns = blender::nodes::node_geo_input_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL, "Material", NODE_CLASS_INPUT, 0); - ntype.draw_buttons = blender::nodes::geo_node_input_material_layout; - ntype.declare = blender::nodes::geo_node_input_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc index 5d5d9e40032..4df218eb669 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_material_index.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_material_index_cc { -static void geo_node_input_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Material Index")).field_source(); } -static void geo_node_input_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> material_index_field = AttributeFieldInput::Create<int>("material_index"); params.set_output("Material Index", std::move(material_index_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_material_index_cc void register_node_type_geo_input_material_index() { + namespace file_ns = blender::nodes::node_geo_input_material_index_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_MATERIAL_INDEX, "Material Index", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_material_index_exec; - ntype.declare = blender::nodes::geo_node_input_material_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc index 92b89313d23..6e63354a31a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_normal.cc @@ -24,26 +24,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_normal_cc { -static void geo_node_input_normal_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Normal")).field_source(); } -static GVArrayPtr mesh_face_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_face_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_poly & CD_MASK_NORMAL) && CustomData_has_layer(&mesh.pdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, polys.size())); + return VArray<float3>::ForSpan({(const float3 *)data, polys.size()}); } auto normal_fn = [verts, polys, loops](const int i) -> float3 { @@ -53,24 +52,21 @@ static GVArrayPtr mesh_face_normals(const Mesh &mesh, return normal; }; - return std::make_unique< - fn::GVArray_For_EmbeddedVArray<float3, VArray_For_Func<float3, decltype(normal_fn)>>>( - mask.min_array_size(), mask.min_array_size(), normal_fn); + return VArray<float3>::ForFunc(mask.min_array_size(), normal_fn); } -static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, - const Span<MVert> verts, - const Span<MPoly> polys, - const Span<MLoop> loops, - const IndexMask mask) +static VArray<float3> mesh_vertex_normals(const Mesh &mesh, + const Span<MVert> verts, + const Span<MPoly> polys, + const Span<MLoop> loops, + const IndexMask mask) { /* Use existing normals to avoid unnecessarily recalculating them, if possible. */ if (!(mesh.runtime.cd_dirty_vert & CD_MASK_NORMAL) && CustomData_has_layer(&mesh.vdata, CD_NORMAL)) { const void *data = CustomData_get_layer(&mesh.pdata, CD_NORMAL); - return std::make_unique<fn::GVArray_For_Span<float3>>( - Span<float3>((const float3 *)data, mesh.totvert)); + return VArray<float3>::ForSpan({(const float3 *)data, mesh.totvert}); } /* If the normals are dirty, they must be recalculated for the output of this node's field @@ -91,14 +87,14 @@ static GVArrayPtr mesh_vertex_normals(const Mesh &mesh, nullptr, (float(*)[3])normals.data()); - return std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } -static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_component, +static VArray<float3> construct_mesh_normals_gvarray(const MeshComponent &mesh_component, const Mesh &mesh, const IndexMask mask, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { Span<MVert> verts{mesh.mvert, mesh.totvert}; Span<MEdge> edges{mesh.medge, mesh.totedge}; @@ -107,18 +103,18 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c switch (domain) { case ATTR_DOMAIN_FACE: { - return scope.add_value(mesh_face_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_face_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_POINT: { - return scope.add_value(mesh_vertex_normals(mesh, verts, polys, loops, mask)).get(); + return mesh_vertex_normals(mesh, verts, polys, loops, mask); } case ATTR_DOMAIN_EDGE: { /* In this case, start with vertex normals and convert to the edge domain, since the * conversion from edges to vertices is very simple. Use the full mask since the edges * might use the vertex normal from any index. */ - GVArrayPtr vert_normals = mesh_vertex_normals( + GVArray vert_normals = mesh_vertex_normals( mesh, verts, polys, loops, IndexRange(verts.size())); - Span<float3> vert_normals_span = vert_normals->get_internal_span().typed<float3>(); + Span<float3> vert_normals_span = vert_normals.get_internal_span().typed<float3>(); Array<float3> edge_normals(mask.min_array_size()); /* Use "manual" domain interpolation instead of the GeometryComponent API to avoid @@ -130,23 +126,21 @@ static const GVArray *construct_mesh_normals_gvarray(const MeshComponent &mesh_c .normalized(); } - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(edge_normals)); + return VArray<float3>::ForContainer(std::move(edge_normals)); } case ATTR_DOMAIN_CORNER: { /* The normals on corners are just the mesh's face normals, so start with the face normal * array and copy the face normal for each of its corners. */ - GVArrayPtr face_normals = mesh_face_normals( + VArray<float3> face_normals = mesh_face_normals( mesh, verts, polys, loops, IndexRange(polys.size())); /* In this case using the mesh component's generic domain interpolation is fine, the data * will still be normalized, since the face normal is just copied to every corner. */ - GVArrayPtr loop_normals = mesh_component.attribute_try_adapt_domain( + return mesh_component.attribute_try_adapt_domain<float3>( std::move(face_normals), ATTR_DOMAIN_FACE, ATTR_DOMAIN_CORNER); - return scope.add_value(std::move(loop_normals)).get(); } default: - return nullptr; + return {}; } } @@ -204,9 +198,9 @@ static Array<float3> curve_normal_point_domain(const CurveEval &curve) return normals; } -static const GVArray *construct_curve_normal_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_normal_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -220,20 +214,18 @@ static const GVArray *construct_curve_normal_gvarray(const CurveComponent &compo * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_normals()); + return VArray<float3>::ForSpan(spline.evaluated_normals()); } Array<float3> normals = curve_normal_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(normals)); + return VArray<float3>::ForContainer(std::move(normals)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_normals = curve_normal_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_normals)); - GVArrayPtr spline_normals = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_normals)).get(); + VArray<float3> varray = VArray<float3>::ForContainer(std::move(point_normals)); + return component.attribute_try_adapt_domain<float3>( + std::move(varray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); } return nullptr; @@ -246,9 +238,9 @@ class NormalFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -260,7 +252,7 @@ class NormalFieldInput final : public fn::FieldInput { const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } return construct_mesh_normals_gvarray(mesh_component, *mesh, mask, domain, scope); @@ -270,7 +262,7 @@ class NormalFieldInput final : public fn::FieldInput { return construct_curve_normal_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -285,20 +277,22 @@ class NormalFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_normal_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> normal_field{std::make_shared<NormalFieldInput>()}; params.set_output("Normal", std::move(normal_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_normal_cc void register_node_type_geo_input_normal() { + namespace file_ns = blender::nodes::node_geo_input_normal_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_NORMAL, "Normal", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_normal_exec; - ntype.declare = blender::nodes::geo_node_input_normal_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc index a8477d4bc4f..8322831a871 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_position.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_position_cc { -static void geo_node_input_position_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Position")).field_source(); } -static void geo_node_input_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> position_field{AttributeFieldInput::Create<float3>("position")}; params.set_output("Position", std::move(position_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_position_cc void register_node_type_geo_input_position() { + namespace file_ns = blender::nodes::node_geo_input_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_POSITION, "Position", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_position_exec; - ntype.declare = blender::nodes::geo_node_input_position_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc index 6d2c4c38cbe..26fb74f5a5b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_radius.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_radius_cc { -static void geo_node_input_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).field_source(); } -static void geo_node_input_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> radius_field = AttributeFieldInput::Create<float>("radius"); params.set_output("Radius", std::move(radius_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_radius_cc void register_node_type_geo_input_radius() { + namespace file_ns = blender::nodes::node_geo_input_radius_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_RADIUS, "Radius", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_radius_exec; - ntype.declare = blender::nodes::geo_node_input_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc index dcd14b1c054..3efe8577e51 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_shade_smooth.cc @@ -16,27 +16,29 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_shade_smooth_cc { -static void geo_node_input_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Smooth")).field_source(); } -static void geo_node_input_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> shade_smooth_field = AttributeFieldInput::Create<bool>("shade_smooth"); params.set_output("Smooth", std::move(shade_smooth_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_shade_smooth_cc void register_node_type_geo_input_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_input_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SHADE_SMOOTH, "Is Shade Smooth", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_input_shade_smooth_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc index a8ee6dd8b12..5f833445a76 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_cyclic.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_cyclic_cc { -static void geo_node_input_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Cyclic")).field_source(); } -static void geo_node_input_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<bool> cyclic_field = AttributeFieldInput::Create<bool>("cyclic"); params.set_output("Cyclic", std::move(cyclic_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_cyclic_cc void register_node_type_geo_input_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_input_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_CYCLIC, "Is Spline Cyclic", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_input_spline_cyclic_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc index 895efa6f0ed..998fce5841b 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_length.cc @@ -18,38 +18,32 @@ #include "BKE_spline.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_length_cc { -static void geo_node_input_spline_length_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Float>(N_("Length")).field_source(); } -static const GVArray *construct_spline_length_gvarray(const CurveComponent &component, - const AttributeDomain domain, - ResourceScope &scope) +static VArray<float> construct_spline_length_gvarray(const CurveComponent &component, + const AttributeDomain domain, + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { - return nullptr; + return {}; } Span<SplinePtr> splines = curve->splines(); auto length_fn = [splines](int i) { return splines[i]->length(); }; if (domain == ATTR_DOMAIN_CURVE) { - return &scope.construct< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); + return VArray<float>::ForFunc(splines.size(), length_fn); } if (domain == ATTR_DOMAIN_POINT) { - GVArrayPtr length = std::make_unique< - fn::GVArray_For_EmbeddedVArray<float, VArray_For_Func<float, decltype(length_fn)>>>( - splines.size(), splines.size(), length_fn); - return scope - .add_value(component.attribute_try_adapt_domain( - std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT)) - .get(); + VArray<float> length = VArray<float>::ForFunc(splines.size(), length_fn); + return component.attribute_try_adapt_domain<float>( + std::move(length), ATTR_DOMAIN_CURVE, ATTR_DOMAIN_POINT); } return nullptr; @@ -62,9 +56,9 @@ class SplineLengthFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -76,7 +70,7 @@ class SplineLengthFieldInput final : public fn::FieldInput { return construct_spline_length_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -91,20 +85,22 @@ class SplineLengthFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_spline_length_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float> length_field{std::make_shared<SplineLengthFieldInput>()}; params.set_output("Length", std::move(length_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_length_cc void register_node_type_geo_input_spline_length() { + namespace file_ns = blender::nodes::node_geo_input_spline_length_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_SPLINE_LENGTH, "Spline Length", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_length_exec; - ntype.declare = blender::nodes::geo_node_input_spline_length_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc index 75fb8a13d38..77b6e27e6a2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_spline_resolution.cc @@ -16,28 +16,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_spline_resolution_cc { -static void geo_node_input_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Int>(N_("Resolution")).field_source(); } -static void geo_node_input_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<int> resolution_field = AttributeFieldInput::Create<int>("resolution"); params.set_output("Resolution", std::move(resolution_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_spline_resolution_cc void register_node_type_geo_input_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_input_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INPUT_SPLINE_RESOLUTION, "Spline Resolution", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_input_spline_resolution_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc index 6b1736fe2ac..0502f64ecb7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_input_tangent.cc @@ -20,9 +20,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_input_tangent_cc { -static void geo_node_input_tangent_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Vector>(N_("Tangent")).field_source(); } @@ -84,9 +84,9 @@ static Array<float3> curve_tangent_point_domain(const CurveEval &curve) return tangents; } -static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &component, +static VArray<float3> construct_curve_tangent_gvarray(const CurveComponent &component, const AttributeDomain domain, - ResourceScope &scope) + ResourceScope &UNUSED(scope)) { const CurveEval *curve = component.get_for_read(); if (curve == nullptr) { @@ -100,20 +100,19 @@ static const GVArray *construct_curve_tangent_gvarray(const CurveComponent &comp * This is only possible when there is only one poly spline. */ if (splines.size() == 1 && splines.first()->type() == Spline::Type::Poly) { const PolySpline &spline = static_cast<PolySpline &>(*splines.first()); - return &scope.construct<fn::GVArray_For_Span<float3>>(spline.evaluated_tangents()); + return VArray<float3>::ForSpan(spline.evaluated_tangents()); } Array<float3> tangents = curve_tangent_point_domain(*curve); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<float3>>>(std::move(tangents)); + return VArray<float3>::ForContainer(std::move(tangents)); } if (domain == ATTR_DOMAIN_CURVE) { Array<float3> point_tangents = curve_tangent_point_domain(*curve); - GVArrayPtr gvarray = std::make_unique<fn::GVArray_For_ArrayContainer<Array<float3>>>( - std::move(point_tangents)); - GVArrayPtr spline_tangents = component.attribute_try_adapt_domain( - std::move(gvarray), ATTR_DOMAIN_POINT, ATTR_DOMAIN_CURVE); - return scope.add_value(std::move(spline_tangents)).get(); + return component.attribute_try_adapt_domain<float3>( + VArray<float3>::ForContainer(std::move(point_tangents)), + ATTR_DOMAIN_POINT, + ATTR_DOMAIN_CURVE); } return nullptr; @@ -126,9 +125,9 @@ class TangentFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask UNUSED(mask), - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask UNUSED(mask), + ResourceScope &scope) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { @@ -141,7 +140,7 @@ class TangentFieldInput final : public fn::FieldInput { return construct_curve_tangent_gvarray(curve_component, domain, scope); } } - return nullptr; + return {}; } uint64_t hash() const override @@ -156,20 +155,22 @@ class TangentFieldInput final : public fn::FieldInput { } }; -static void geo_node_input_tangent_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Field<float3> tangent_field{std::make_shared<TangentFieldInput>()}; params.set_output("Tangent", std::move(tangent_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_input_tangent_cc void register_node_type_geo_input_tangent() { + namespace file_ns = blender::nodes::node_geo_input_tangent_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_INPUT_TANGENT, "Curve Tangent", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_input_tangent_exec; - ntype.declare = blender::nodes::geo_node_input_tangent_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc index aff29d973d4..d859289fc59 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instance_on_points.cc @@ -24,9 +24,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instance_on_points_cc { -static void geo_node_instance_on_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).description(N_("Points to instance on")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -80,10 +80,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, select_len); FieldEvaluator field_evaluator{field_context, domain_size}; - const VArray<bool> *pick_instance = nullptr; - const VArray<int> *indices = nullptr; - const VArray<float3> *rotations = nullptr; - const VArray<float3> *scales = nullptr; + VArray<bool> pick_instance; + VArray<int> indices; + VArray<float3> rotations; + VArray<float3> scales; /* The evaluator could use the component's stable IDs as a destination directly, but only the * selected indices should be copied. */ field_evaluator.add(params.get_input<Field<bool>>("Pick Instance"), &pick_instance); @@ -92,7 +92,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, field_evaluator.add(params.get_input<Field<float3>>("Scale"), &scales); field_evaluator.evaluate(); - GVArray_Typed<float3> positions = src_component.attribute_get_for_read<float3>( + VArray<float3> positions = src_component.attribute_get_for_read<float3>( "position", domain, {0, 0, 0}); const InstancesComponent *src_instances = instance.get_component_for_read<InstancesComponent>(); @@ -101,7 +101,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, Array<int> handle_mapping; /* Only fill #handle_mapping when it may be used below. */ if (src_instances != nullptr && - (!pick_instance->is_single() || pick_instance->get_internal_single())) { + (!pick_instance.is_single() || pick_instance.get_internal_single())) { Span<InstanceReference> src_references = src_instances->references(); handle_mapping.reinitialize(src_references.size()); for (const int src_instance_handle : src_references.index_range()) { @@ -121,17 +121,16 @@ static void add_instances_from_component(InstancesComponent &dst_component, /* Compute base transform for every instances. */ float4x4 &dst_transform = dst_transforms[range_i]; - dst_transform = float4x4::from_loc_eul_scale( - positions[i], rotations->get(i), scales->get(i)); + dst_transform = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]); /* Reference that will be used by this new instance. */ int dst_handle = empty_reference_handle; - const bool use_individual_instance = pick_instance->get(i); + const bool use_individual_instance = pick_instance[i]; if (use_individual_instance) { if (src_instances != nullptr) { const int src_instances_amount = src_instances->instances_amount(); - const int original_index = indices->get(i); + const int original_index = indices[i]; /* Use #mod_i instead of `%` to get the desirable wrap around behavior where -1 * refers to the last element. */ const int index = mod_i(original_index, std::max(src_instances_amount, 1)); @@ -155,10 +154,10 @@ static void add_instances_from_component(InstancesComponent &dst_component, } }); - GVArrayPtr id_attribute = src_component.attribute_try_get_for_read( - "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); - if (id_attribute) { - GVArray_Typed<int> ids{*id_attribute}; + VArray<int> ids = src_component + .attribute_try_get_for_read("id", ATTR_DOMAIN_POINT, CD_PROP_INT32) + .typed<int>(); + if (ids) { VArray_Span<int> ids_span{ids}; MutableSpan<int> dst_ids = dst_component.instance_ids_ensure(); for (const int64_t i : selection.index_range()) { @@ -166,8 +165,8 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } - if (pick_instance->is_single()) { - if (pick_instance->get_internal_single()) { + if (pick_instance.is_single()) { + if (pick_instance.get_internal_single()) { if (instance.has_realized_data()) { params.error_message_add( NodeWarningType::Info, @@ -177,7 +176,7 @@ static void add_instances_from_component(InstancesComponent &dst_component, } } -static void geo_node_instance_on_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); GeometrySet instance = params.get_input<GeometrySet>("Instance"); @@ -215,15 +214,17 @@ static void geo_node_instance_on_points_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instance_on_points_cc void register_node_type_geo_instance_on_points() { + namespace file_ns = blender::nodes::node_geo_instance_on_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCE_ON_POINTS, "Instance on Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instance_on_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instance_on_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc index c3955426e69..71e4a69911c 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_instances_to_points.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_instances_to_points_cc { -static void geo_node_instances_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -51,9 +51,8 @@ static void convert_instances_to_points(GeometrySet &geometry_set, { const InstancesComponent &instances = *geometry_set.get_component_for_read<InstancesComponent>(); - const AttributeDomain attribute_domain = ATTR_DOMAIN_POINT; - GeometryComponentFieldContext field_context{instances, attribute_domain}; - const int domain_size = instances.attribute_domain_size(attribute_domain); + GeometryComponentFieldContext field_context{instances, ATTR_DOMAIN_INSTANCE}; + const int domain_size = instances.attribute_domain_size(ATTR_DOMAIN_INSTANCE); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; selection_evaluator.add(std::move(selection_field)); @@ -88,7 +87,7 @@ static void convert_instances_to_points(GeometrySet &geometry_set, } } -static void geo_node_instances_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); @@ -105,15 +104,17 @@ static void geo_node_instances_to_points_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_instances_to_points_cc void register_node_type_geo_instances_to_points() { + namespace file_ns = blender::nodes::node_geo_instances_to_points_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_INSTANCES_TO_POINTS, "Instances to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_instances_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_instances_to_points_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc index 8e0e98f7bd5..5925d440317 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_is_viewport.cc @@ -18,14 +18,14 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_is_viewport_cc { -static void geo_node_is_viewport_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_output<decl::Bool>(N_("Is Viewport")); } -static void geo_node_is_viewport_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const Depsgraph *depsgraph = params.depsgraph(); const eEvaluationMode mode = DEG_get_mode(depsgraph); @@ -34,14 +34,16 @@ static void geo_node_is_viewport_exec(GeoNodeExecParams params) params.set_output("Is Viewport", is_viewport); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_is_viewport_cc void register_node_type_geo_is_viewport() { + namespace file_ns = blender::nodes::node_geo_is_viewport_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_IS_VIEWPORT, "Is Viewport", NODE_CLASS_INPUT, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_is_viewport_exec; - ntype.declare = blender::nodes::geo_node_is_viewport_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 9d363bd1af4..53f7d968644 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -27,11 +27,9 @@ #include "node_geometry_util.hh" -using blender::fn::GVArray_For_GSpan; +namespace blender::nodes::node_geo_join_geometry_cc { -namespace blender::nodes { - -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).multi_input(); b.add_output<decl::Geometry>(N_("Geometry")); @@ -190,10 +188,10 @@ static void fill_new_attribute(Span<const GeometryComponent *> src_components, if (domain_size == 0) { continue; } - GVArrayPtr read_attribute = component->attribute_get_for_read( + GVArray read_attribute = component->attribute_get_for_read( attribute_id, domain, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); void *dst_buffer = dst_span[offset]; cpp_type->copy_assign_n(src_buffer, dst_buffer, domain_size); @@ -319,8 +317,7 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, spline->size() * type.size(), type.alignment(), __func__); const DataTypeConversions &conversions = blender::nodes::get_implicit_type_conversions(); - conversions.try_convert(std::make_unique<GVArray_For_GSpan>(*attribute), type) - ->materialize(converted_buffer); + conversions.try_convert(GVArray::ForSpan(*attribute), type).materialize(converted_buffer); spline->attributes.remove(attribute_id); spline->attributes.create_by_move(attribute_id, data_type, converted_buffer); @@ -333,14 +330,14 @@ static void ensure_control_point_attribute(const AttributeIDRef &attribute_id, /* In this case the attribute did not exist, but there is a spline domain attribute * we can retrieve a value from, as a spline to point domain conversion. So fill the * new attribute with the value for this spline. */ - GVArrayPtr current_curve_attribute = current_curve->attributes.get_for_read( + GVArray current_curve_attribute = current_curve->attributes.get_for_read( attribute_id, data_type, nullptr); BLI_assert(spline->attributes.get_for_read(attribute_id)); std::optional<GMutableSpan> new_attribute = spline->attributes.get_for_write(attribute_id); BUFFER_FOR_CPP_TYPE_VALUE(type, buffer); - current_curve_attribute->get(spline_index_in_component, buffer); + current_curve_attribute.get(spline_index_in_component, buffer); type.fill_assign_n(buffer, new_attribute->data(), new_attribute->size()); } } @@ -397,8 +394,8 @@ static void ensure_spline_attribute(const AttributeIDRef &attribute_id, if (size == 0) { continue; } - GVArrayPtr read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); - GVArray_GSpan src_span{*read_attribute}; + GVArray read_attribute = curve.attributes.get_for_read(attribute_id, data_type, nullptr); + GVArray_GSpan src_span{read_attribute}; const void *src_buffer = src_span.data(); type.copy_assign_n(src_buffer, result_attribute[offset], size); @@ -498,7 +495,7 @@ static void join_component_type(Span<GeometrySet> src_geometry_sets, GeometrySet join_components(components, result); } -static void geo_node_join_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<GeometrySet> geometry_sets = params.extract_multi_input<GeometrySet>("Geometry"); @@ -511,14 +508,16 @@ static void geo_node_join_geometry_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set_result)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_join_geometry_cc void register_node_type_geo_join_geometry() { + namespace file_ns = blender::nodes::node_geo_join_geometry_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_JOIN_GEOMETRY, "Join Geometry", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_join_geometry_exec; - ntype.declare = blender::nodes::geo_node_join_geometry_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc index e4a62bd5267..5a334126350 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_replace.cc @@ -24,9 +24,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_replace_cc { -static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Material>(N_("Old")); @@ -34,7 +34,7 @@ static void geo_node_material_replace_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_material_replace_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *old_material = params.extract_input<Material *>("Old"); Material *new_material = params.extract_input<Material *>("New"); @@ -55,15 +55,17 @@ static void geo_node_material_replace_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_replace_cc void register_node_type_geo_material_replace() { + namespace file_ns = blender::nodes::node_geo_material_replace_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REPLACE_MATERIAL, "Replace Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_replace_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_replace_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc index 06c770820ee..948565b62f0 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_material_selection.cc @@ -26,9 +26,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_material_selection_cc { -static void geo_node_material_selection_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Material>(N_("Material")).hide_label(true); b.add_output<decl::Bool>(N_("Selection")).field_source(); @@ -64,36 +64,33 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { category_ = Category::Generated; } - const GVArray *get_varray_for_context(const fn::FieldContext &context, - IndexMask mask, - ResourceScope &scope) const final + GVArray get_varray_for_context(const fn::FieldContext &context, + IndexMask mask, + ResourceScope &UNUSED(scope)) const final { if (const GeometryComponentFieldContext *geometry_context = dynamic_cast<const GeometryComponentFieldContext *>(&context)) { const GeometryComponent &component = geometry_context->geometry_component(); const AttributeDomain domain = geometry_context->domain(); if (component.type() != GEO_COMPONENT_TYPE_MESH) { - return nullptr; + return {}; } const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); const Mesh *mesh = mesh_component.get_for_read(); if (mesh == nullptr) { - return nullptr; + return {}; } if (domain == ATTR_DOMAIN_FACE) { Array<bool> selection(mask.min_array_size()); select_mesh_by_material(*mesh, material_, mask, selection); - return &scope.construct<fn::GVArray_For_ArrayContainer<Array<bool>>>(std::move(selection)); + return VArray<bool>::ForContainer(std::move(selection)); } Array<bool> selection(mesh->totpoly); select_mesh_by_material(*mesh, material_, IndexMask(mesh->totpoly), selection); - GVArrayPtr face_selection = std::make_unique<fn::GVArray_For_ArrayContainer<Array<bool>>>( - std::move(selection)); - GVArrayPtr final_selection = mesh_component.attribute_try_adapt_domain( - std::move(face_selection), ATTR_DOMAIN_FACE, domain); - return scope.add_value(std::move(final_selection)).get(); + return mesh_component.attribute_try_adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(selection)), ATTR_DOMAIN_FACE, domain); } return nullptr; @@ -114,22 +111,24 @@ class MaterialSelectionFieldInput final : public fn::FieldInput { } }; -static void geo_node_material_selection_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); Field<bool> material_field{std::make_shared<MaterialSelectionFieldInput>(material)}; params.set_output("Selection", std::move(material_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_material_selection_cc void register_node_type_geo_material_selection() { + namespace file_ns = blender::nodes::node_geo_material_selection_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MATERIAL_SELECTION, "Material Selection", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_material_selection_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_material_selection_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc index 685a8faff5c..ec06bdc0455 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc @@ -25,25 +25,30 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_circle_cc { -static void geo_node_mesh_primitive_circle_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Int>(N_("Vertices")) + .default_value(32) + .min(3) + .description(N_("Number of vertices on the circle")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance of the vertices from the origin")); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_circle_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_circle_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCircle *node_storage = (NodeGeometryMeshCircle *)MEM_callocN( sizeof(NodeGeometryMeshCircle), __func__); @@ -192,7 +197,7 @@ static Mesh *create_circle_mesh(const float radius, return mesh; } -static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCircle &storage = *(const NodeGeometryMeshCircle *)node.storage; @@ -215,19 +220,21 @@ static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_circle_cc void register_node_type_geo_mesh_primitive_circle() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_circle_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_circle_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage( &ntype, "NodeGeometryMeshCircle", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_circle_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_circle_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_circle_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc index 206d48d40c8..d2739e7e3ad 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc @@ -25,53 +25,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { - -static void geo_node_mesh_primitive_cone_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Int>(N_("Vertices")).default_value(32).min(3).max(512); - b.add_input<decl::Int>(N_("Side Segments")).default_value(1).min(1).max(512); - b.add_input<decl::Int>(N_("Fill Segments")).default_value(1).min(1).max(512); - b.add_input<decl::Float>(N_("Radius Top")).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Radius Bottom")) - .default_value(1.0f) - .min(0.0f) - .subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Depth")).default_value(2.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_output<decl::Geometry>(N_("Mesh")); -} - -static void geo_node_mesh_primitive_cone_init(bNodeTree *UNUSED(ntree), bNode *node) -{ - NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( - sizeof(NodeGeometryMeshCone), __func__); - - node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; - - node->storage = node_storage; -} +#include <cmath> -static void geo_node_mesh_primitive_cone_update(bNodeTree *UNUSED(ntree), bNode *node) -{ - bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; - bNodeSocket *rings_socket = vertices_socket->next; - bNodeSocket *fill_subdiv_socket = rings_socket->next; - - const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; - const GeometryNodeMeshCircleFillType fill_type = - static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); - const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); -} - -static void geo_node_mesh_primitive_cone_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayoutSetPropSep(layout, true); - uiLayoutSetPropDecorate(layout, false); - uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); -} +namespace blender::nodes { struct ConeConfig { float radius_top; @@ -94,6 +50,8 @@ struct ConeConfig { int tot_edge_rings; int tot_verts; int tot_edges; + int tot_corners; + int tot_faces; /* Helpful vertex indices. */ int first_vert; @@ -107,6 +65,14 @@ struct ConeConfig { int last_fan_edges_start; int last_edge; + /* Helpful face indices. */ + int top_faces_start; + int top_faces_len; + int side_faces_start; + int side_faces_len; + int bottom_faces_start; + int bottom_faces_len; + ConeConfig(float radius_top, float radius_bottom, float depth, @@ -133,6 +99,7 @@ struct ConeConfig { this->tot_edge_rings = this->calculate_total_edge_rings(); this->tot_verts = this->calculate_total_verts(); this->tot_edges = this->calculate_total_edges(); + this->tot_corners = this->calculate_total_corners(); this->first_vert = 0; this->first_ring_verts_start = this->top_has_center_vert ? 1 : first_vert; @@ -144,6 +111,36 @@ struct ConeConfig { this->tot_quad_rings * this->circle_segments * 2; this->last_fan_edges_start = this->tot_edges - this->circle_segments; this->last_edge = this->tot_edges - 1; + + this->top_faces_start = 0; + if (!this->top_is_point) { + this->top_faces_len = (fill_segments - 1) * circle_segments; + this->top_faces_len += this->top_has_center_vert ? circle_segments : 0; + this->top_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0; + } + else { + this->top_faces_len = 0; + } + + this->side_faces_start = this->top_faces_len; + if (this->top_is_point && this->bottom_is_point) { + this->side_faces_len = 0; + } + else { + this->side_faces_len = side_segments * circle_segments; + } + + if (!this->bottom_is_point) { + this->bottom_faces_len = (fill_segments - 1) * circle_segments; + this->bottom_faces_len += this->bottom_has_center_vert ? circle_segments : 0; + this->bottom_faces_len += this->fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON ? 1 : 0; + } + else { + this->bottom_faces_len = 0; + } + this->bottom_faces_start = this->side_faces_start + this->side_faces_len; + + this->tot_faces = this->top_faces_len + this->side_faces_len + this->bottom_faces_len; } private: @@ -151,10 +148,7 @@ struct ConeConfig { int calculate_total_edge_rings(); int calculate_total_verts(); int calculate_total_edges(); - - public: - int get_tot_corners() const; - int get_tot_faces() const; + int calculate_total_corners(); }; int ConeConfig::calculate_total_quad_rings() @@ -248,7 +242,7 @@ int ConeConfig::calculate_total_edges() return edge_total; } -int ConeConfig::get_tot_corners() const +int ConeConfig::calculate_total_corners() { if (top_is_point && bottom_is_point) { return 0; @@ -275,32 +269,6 @@ int ConeConfig::get_tot_corners() const return corner_total; } -int ConeConfig::get_tot_faces() const -{ - if (top_is_point && bottom_is_point) { - return 0; - } - - int face_total = 0; - if (top_has_center_vert) { - face_total += circle_segments; - } - else if (!top_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) { - face_total++; - } - - face_total += tot_quad_rings * circle_segments; - - if (bottom_has_center_vert) { - face_total += circle_segments; - } - else if (!bottom_is_point && fill_type == GEO_NODE_MESH_CIRCLE_FILL_NGON) { - face_total++; - } - - return face_total; -} - static void calculate_cone_vertices(const MutableSpan<MVert> &verts, const ConeConfig &config) { Array<float2> circle(config.circle_segments); @@ -522,6 +490,60 @@ static void calculate_cone_faces(const MutableSpan<MLoop> &loops, } } +static void calculate_selection_outputs(Mesh *mesh, + const ConeConfig &config, + ConeAttributeOutputs &attribute_outputs) +{ + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + + /* Populate "Top" selection output. */ + if (attribute_outputs.top_id) { + const bool face = !config.top_is_point && config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.top_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + + if (config.top_is_point) { + selection[config.first_vert] = true; + } + else { + selection.slice(0, face ? config.top_faces_len : config.circle_segments).fill(true); + } + attribute.save(); + } + + /* Populate "Bottom" selection output. */ + if (attribute_outputs.bottom_id) { + const bool face = !config.bottom_is_point && + config.fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.bottom_id.get(), face ? ATTR_DOMAIN_FACE : ATTR_DOMAIN_POINT); + MutableSpan<bool> selection = attribute.as_span(); + + if (config.bottom_is_point) { + selection[config.last_vert] = true; + } + else { + selection + .slice(config.bottom_faces_start, + face ? config.bottom_faces_len : config.circle_segments) + .fill(true); + } + attribute.save(); + } + + /* Populate "Side" selection output. */ + if (attribute_outputs.side_id) { + OutputAttribute_Typed<bool> attribute = mesh_component.attribute_try_get_for_output_only<bool>( + attribute_outputs.side_id.get(), ATTR_DOMAIN_FACE); + MutableSpan<bool> selection = attribute.as_span(); + + selection.slice(config.side_faces_start, config.side_faces_len).fill(true); + attribute.save(); + } +} + /** * If the top is the cone tip or has a fill, it is unwrapped into a circle in the * lower left quadrant of the UV. @@ -665,7 +687,8 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, const int circle_segments, const int side_segments, const int fill_segments, - const GeometryNodeMeshCircleFillType fill_type) + const GeometryNodeMeshCircleFillType fill_type, + ConeAttributeOutputs &attribute_outputs) { const ConeConfig config( radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type); @@ -683,7 +706,7 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, } Mesh *mesh = BKE_mesh_new_nomain( - config.tot_verts, config.tot_edges, 0, config.get_tot_corners(), config.get_tot_faces()); + config.tot_verts, config.tot_edges, 0, config.tot_corners, config.tot_faces); BKE_id_material_eval_ensure_default_slot(&mesh->id); MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; @@ -695,67 +718,179 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, calculate_cone_edges(edges, config); calculate_cone_faces(loops, polys, config); calculate_cone_uvs(mesh, config); + calculate_selection_outputs(mesh, config, attribute_outputs); BKE_mesh_normals_tag_dirty(mesh); return mesh; } -static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cone_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Vertices")) + .default_value(32) + .min(3) + .max(512) + .description(N_("Number of points on the circle at the top and bottom")); + b.add_input<decl::Int>(N_("Side Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("The number of edges running vertically along the side of the cone")); + b.add_input<decl::Int>(N_("Fill Segments")) + .default_value(1) + .min(1) + .max(512) + .description(N_("Number of concentric rings used to fill the round face")); + b.add_input<decl::Float>(N_("Radius Top")) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the top circle of the cone")); + b.add_input<decl::Float>(N_("Radius Bottom")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Radius of the bottom circle of the cone")); + b.add_input<decl::Float>(N_("Depth")) + .default_value(2.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Height of the generated cone")); + b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Top")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); +} + +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryMeshCone *node_storage = (NodeGeometryMeshCone *)MEM_callocN( + sizeof(NodeGeometryMeshCone), __func__); + + node_storage->fill_type = GEO_NODE_MESH_CIRCLE_FILL_NGON; + + node->storage = node_storage; +} + +static void node_update(bNodeTree *ntree, bNode *node) +{ + bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; + bNodeSocket *rings_socket = vertices_socket->next; + bNodeSocket *fill_subdiv_socket = rings_socket->next; + + const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node->storage; + const GeometryNodeMeshCircleFillType fill_type = + static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); + const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); +} + +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); +} + +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCone &storage = *(const NodeGeometryMeshCone *)node.storage; const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) storage.fill_type; + auto return_default = [&]() { + params.set_output("Top", fn::make_constant_field<bool>(false)); + params.set_output("Bottom", fn::make_constant_field<bool>(false)); + params.set_output("Side", fn::make_constant_field<bool>(false)); + params.set_output("Mesh", GeometrySet()); + }; + const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const float radius_top = params.extract_input<float>("Radius Top"); const float radius_bottom = params.extract_input<float>("Radius Bottom"); const float depth = params.extract_input<float>("Depth"); - Mesh *mesh = create_cylinder_or_cone_mesh( - radius_top, radius_bottom, depth, circle_segments, side_segments, fill_segments, fill_type); + ConeAttributeOutputs attribute_outputs; + if (params.output_is_required("Top")) { + attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection"); + } + if (params.output_is_required("Bottom")) { + attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection"); + } + if (params.output_is_required("Side")) { + attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection"); + } + + Mesh *mesh = create_cylinder_or_cone_mesh(radius_top, + radius_bottom, + depth, + circle_segments, + side_segments, + fill_segments, + fill_type, + attribute_outputs); /* Transform the mesh so that the base of the cone is at the origin. */ BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false); + if (attribute_outputs.top_id) { + params.set_output("Top", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.top_id), params.attribute_producer_name())); + } + if (attribute_outputs.bottom_id) { + params.set_output( + "Bottom", + AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id), + params.attribute_producer_name())); + } + if (attribute_outputs.side_id) { + params.set_output("Side", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.side_id), params.attribute_producer_name())); + } + params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cone_cc void register_node_type_geo_mesh_primitive_cone() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cone_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CONE, "Cone", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cone_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cone_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCone", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cone_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cone_layout; - ntype.declare = blender::nodes::geo_node_mesh_primitive_cone_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc index 3a211993bdc..682efcc81bd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc @@ -24,18 +24,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_cube_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Vector>(N_("Size")) - .default_value(float3(1)) - .min(0.0f) - .subtype(PROP_TRANSLATION); - b.add_input<decl::Int>(N_("Vertices X")).default_value(2).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Y")).default_value(2).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Z")).default_value(2).min(2).max(1000); - b.add_output<decl::Geometry>(N_("Mesh")); -} - struct CuboidConfig { float3 size; int verts_x; @@ -426,6 +414,35 @@ Mesh *create_cuboid_mesh(const float3 size, return mesh; } +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_cube_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Vector>(N_("Size")) + .default_value(float3(1)) + .min(0.0f) + .subtype(PROP_TRANSLATION) + .description(N_("Side length along each axis")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the X side of the shape")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Y side of the shape")); + b.add_input<decl::Int>(N_("Vertices Z")) + .default_value(2) + .min(2) + .max(1000) + .description(N_("Number of vertices for the Z side of the shape")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + static Mesh *create_cube_mesh(const float3 size, const int verts_x, const int verts_y, @@ -471,7 +488,7 @@ static Mesh *create_cube_mesh(const float3 size, return create_cuboid_mesh(size, verts_x, verts_y, verts_z); } -static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const float3 size = params.extract_input<float3>("Size"); const int verts_x = params.extract_input<int>("Vertices X"); @@ -488,14 +505,16 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cube_cc void register_node_type_geo_mesh_primitive_cube() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cube_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CUBE, "Cube", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cube_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cube_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc index 3bcf42b40b1..f5ef277de03 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc @@ -25,25 +25,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc { -static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Int>(N_("Vertices")) .default_value(32) .min(3) .max(512) - .description(N_("The number of vertices around the circumference")); + .description(N_("The number of vertices on the top and bottom circles")); b.add_input<decl::Int>(N_("Side Segments")) .default_value(1) .min(1) .max(512) - .description(N_("The number of segments along the side")); + .description(N_("The number of rectangular segments along each side")); b.add_input<decl::Int>(N_("Fill Segments")) .default_value(1) .min(1) .max(512) - .description(N_("The number of concentric segments of the fill")); + .description(N_("The number of concentric rings used to fill the round faces")); b.add_input<decl::Float>(N_("Radius")) .default_value(1.0f) .min(0.0f) @@ -53,20 +53,21 @@ static void geo_node_mesh_primitive_cylinder_declare(NodeDeclarationBuilder &b) .default_value(2.0f) .min(0.0f) .subtype(PROP_DISTANCE) - .description(N_("The height of the cylinder on the Z axis")); + .description(N_("The height of the cylinder")); b.add_output<decl::Geometry>(N_("Mesh")); + b.add_output<decl::Bool>(N_("Top")).field_source(); + b.add_output<decl::Bool>(N_("Side")).field_source(); + b.add_output<decl::Bool>(N_("Bottom")).field_source(); } -static void geo_node_mesh_primitive_cylinder_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "fill_type", 0, nullptr, ICON_NONE); } -static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshCylinder *node_storage = (NodeGeometryMeshCylinder *)MEM_callocN( sizeof(NodeGeometryMeshCylinder), __func__); @@ -76,7 +77,7 @@ static void geo_node_mesh_primitive_cylinder_init(bNodeTree *UNUSED(ntree), bNod node->storage = node_storage; } -static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *vertices_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *rings_socket = vertices_socket->next; @@ -86,10 +87,10 @@ static void geo_node_mesh_primitive_cylinder_update(bNodeTree *UNUSED(ntree), bN const GeometryNodeMeshCircleFillType fill_type = static_cast<const GeometryNodeMeshCircleFillType>(storage.fill_type); const bool has_fill = fill_type != GEO_NODE_MESH_CIRCLE_FILL_NONE; - nodeSetSocketAvailability(fill_subdiv_socket, has_fill); + nodeSetSocketAvailability(ntree, fill_subdiv_socket, has_fill); } -static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &node = params.node(); const NodeGeometryMeshCylinder &storage = *(const NodeGeometryMeshCylinder *)node.storage; @@ -97,49 +98,89 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params) const GeometryNodeMeshCircleFillType fill_type = (const GeometryNodeMeshCircleFillType) storage.fill_type; + auto return_default = [&]() { + params.set_output("Top", fn::make_constant_field<bool>(false)); + params.set_output("Bottom", fn::make_constant_field<bool>(false)); + params.set_output("Side", fn::make_constant_field<bool>(false)); + params.set_output("Mesh", GeometrySet()); + }; + const float radius = params.extract_input<float>("Radius"); const float depth = params.extract_input<float>("Depth"); const int circle_segments = params.extract_input<int>("Vertices"); if (circle_segments < 3) { params.error_message_add(NodeWarningType::Info, TIP_("Vertices must be at least 3")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const int side_segments = params.extract_input<int>("Side Segments"); if (side_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Side Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); } const bool no_fill = fill_type == GEO_NODE_MESH_CIRCLE_FILL_NONE; const int fill_segments = no_fill ? 1 : params.extract_input<int>("Fill Segments"); if (fill_segments < 1) { params.error_message_add(NodeWarningType::Info, TIP_("Fill Segments must be at least 1")); - params.set_output("Mesh", GeometrySet()); - return; + return return_default(); + } + + ConeAttributeOutputs attribute_outputs; + if (params.output_is_required("Top")) { + attribute_outputs.top_id = StrongAnonymousAttributeID("top_selection"); + } + if (params.output_is_required("Bottom")) { + attribute_outputs.bottom_id = StrongAnonymousAttributeID("bottom_selection"); + } + if (params.output_is_required("Side")) { + attribute_outputs.side_id = StrongAnonymousAttributeID("side_selection"); } /* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */ - Mesh *mesh = create_cylinder_or_cone_mesh( - radius, radius, depth, circle_segments, side_segments, fill_segments, fill_type); + Mesh *mesh = create_cylinder_or_cone_mesh(radius, + radius, + depth, + circle_segments, + side_segments, + fill_segments, + fill_type, + attribute_outputs); + + if (attribute_outputs.top_id) { + params.set_output("Top", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.top_id), params.attribute_producer_name())); + } + if (attribute_outputs.bottom_id) { + params.set_output( + "Bottom", + AnonymousAttributeFieldInput::Create<bool>(std::move(attribute_outputs.bottom_id), + params.attribute_producer_name())); + } + if (attribute_outputs.side_id) { + params.set_output("Side", + AnonymousAttributeFieldInput::Create<bool>( + std::move(attribute_outputs.side_id), params.attribute_producer_name())); + } params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_cylinder_cc void register_node_type_geo_mesh_primitive_cylinder() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_cylinder_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CYLINDER, "Cylinder", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_cylinder_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshCylinder", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_mesh_primitive_cylinder_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_cylinder_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_cylinder_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index c4e476981c1..c761380645d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -27,15 +27,6 @@ namespace blender::nodes { -static void geo_node_mesh_primitive_grid_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Float>(N_("Size X")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Float>(N_("Size Y")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Int>(N_("Vertices X")).default_value(3).min(2).max(1000); - b.add_input<decl::Int>(N_("Vertices Y")).default_value(3).min(2).max(1000); - b.add_output<decl::Geometry>(N_("Mesh")); -} - static void calculate_uvs( Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, const float size_x, const float size_y) { @@ -153,7 +144,36 @@ Mesh *create_grid_mesh(const int verts_x, return mesh; } -static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) +} // namespace blender::nodes + +namespace blender::nodes::node_geo_mesh_primitive_grid_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Float>(N_("Size X")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the X direction")); + b.add_input<decl::Float>(N_("Size Y")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Side length of the plane in the Y direction")); + b.add_input<decl::Int>(N_("Vertices X")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the X direction")); + b.add_input<decl::Int>(N_("Vertices Y")) + .default_value(3) + .min(2) + .max(1000) + .description(N_("Number of vertices in the Y direction")); + b.add_output<decl::Geometry>(N_("Mesh")); +} + +static void node_geo_exec(GeoNodeExecParams params) { const float size_x = params.extract_input<float>("Size X"); const float size_y = params.extract_input<float>("Size Y"); @@ -171,14 +191,16 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_grid_cc void register_node_type_geo_mesh_primitive_grid() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_grid_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_grid_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc index da3dfef3aea..5f483a95063 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc @@ -24,12 +24,20 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc { -static void geo_node_mesh_primitive_ico_sphere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); - b.add_input<decl::Int>(N_("Subdivisions")).default_value(1).min(1).max(7); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance from the generated points to the origin")); + b.add_input<decl::Int>(N_("Subdivisions")) + .default_value(1) + .min(1) + .max(7) + .description(N_("Number of subdivisions on top of the basic icosahedron")); b.add_output<decl::Geometry>(N_("Mesh")); } @@ -37,9 +45,10 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) { const float4x4 transform = float4x4::identity(); - const BMeshCreateParams bmcp = {true}; + BMeshCreateParams bmesh_create_params{}; + bmesh_create_params.use_toolflags = true; const BMAllocTemplate allocsize = {0, 0, 0, 0}; - BMesh *bm = BM_mesh_create(&allocsize, &bmcp); + BMesh *bm = BM_mesh_create(&allocsize, &bmesh_create_params); BM_data_layer_add_named(bm, &bm->ldata, CD_MLOOPUV, nullptr); BMO_op_callf(bm, @@ -60,7 +69,7 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) return mesh; } -static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int subdivisions = std::min(params.extract_input<int>("Subdivisions"), 10); const float radius = params.extract_input<float>("Radius"); @@ -69,15 +78,17 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_ico_sphere_cc void register_node_type_geo_mesh_primitive_ico_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_ico_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, "Ico Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_ico_sphere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_ico_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc index 6515afe5966..cda55eadaf6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc @@ -25,22 +25,33 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_line_cc { -static void geo_node_mesh_primitive_line_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Count")).default_value(10).min(1).max(10000); - b.add_input<decl::Float>(N_("Resolution")).default_value(1.0f).min(0.1f).subtype(PROP_DISTANCE); - b.add_input<decl::Vector>(N_("Start Location")).subtype(PROP_TRANSLATION); + b.add_input<decl::Int>(N_("Count")) + .default_value(10) + .min(1) + .max(10000) + .description(N_("Number of vertices on the line")); + b.add_input<decl::Float>(N_("Resolution")) + .default_value(1.0f) + .min(0.1f) + .subtype(PROP_DISTANCE) + .description(N_("Length of each individual edge")); + b.add_input<decl::Vector>(N_("Start Location")) + .subtype(PROP_TRANSLATION) + .description(N_("Position of the first vertex")); b.add_input<decl::Vector>(N_("Offset")) .default_value({0.0f, 0.0f, 1.0f}) - .subtype(PROP_TRANSLATION); + .subtype(PROP_TRANSLATION) + .description(N_( + "In offset mode, the distance between each socket on each axis. In end points mode, the " + "position of the final vertex")); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_mesh_primitive_line_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -50,7 +61,7 @@ static void geo_node_mesh_primitive_line_layout(uiLayout *layout, } } -static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryMeshLine *node_storage = (NodeGeometryMeshLine *)MEM_callocN( sizeof(NodeGeometryMeshLine), __func__); @@ -61,7 +72,7 @@ static void geo_node_mesh_primitive_line_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = node_storage; } -static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { bNodeSocket *count_socket = (bNodeSocket *)node->inputs.first; bNodeSocket *resolution_socket = count_socket->next; @@ -77,48 +88,17 @@ static void geo_node_mesh_primitive_line_update(bNodeTree *UNUSED(tree), bNode * (mode == GEO_NODE_MESH_LINE_MODE_END_POINTS) ? N_("End Location") : N_("Offset")); - nodeSetSocketAvailability(resolution_socket, + nodeSetSocketAvailability(ntree, + resolution_socket, mode == GEO_NODE_MESH_LINE_MODE_END_POINTS && count_mode == GEO_NODE_MESH_LINE_COUNT_RESOLUTION); - nodeSetSocketAvailability(count_socket, + nodeSetSocketAvailability(ntree, + count_socket, mode == GEO_NODE_MESH_LINE_MODE_OFFSET || count_mode == GEO_NODE_MESH_LINE_COUNT_TOTAL); } -static void fill_edge_data(MutableSpan<MEdge> edges) -{ - for (const int i : edges.index_range()) { - edges[i].v1 = i; - edges[i].v2 = i + 1; - edges[i].flag |= ME_LOOSEEDGE; - } -} - -Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) -{ - if (count < 1) { - return nullptr; - } - - Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); - BKE_id_material_eval_ensure_default_slot(&mesh->id); - MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; - MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; - - short normal[3]; - normal_float_to_short_v3(normal, delta.normalized()); - - for (const int i : verts.index_range()) { - copy_v3_v3(verts[i].co, start + delta * i); - copy_v3_v3_short(verts[i].no, normal); - } - - fill_edge_data(edges); - - return mesh; -} - -static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometryMeshLine &storage = *(const NodeGeometryMeshLine *)params.node().storage; const GeometryNodeMeshLineMode mode = (const GeometryNodeMeshLineMode)storage.mode; @@ -159,19 +139,58 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } +} // namespace blender::nodes::node_geo_mesh_primitive_line_cc + +namespace blender::nodes { + +static void fill_edge_data(MutableSpan<MEdge> edges) +{ + for (const int i : edges.index_range()) { + edges[i].v1 = i; + edges[i].v2 = i + 1; + edges[i].flag |= ME_LOOSEEDGE; + } +} + +Mesh *create_line_mesh(const float3 start, const float3 delta, const int count) +{ + if (count < 1) { + return nullptr; + } + + Mesh *mesh = BKE_mesh_new_nomain(count, count - 1, 0, 0, 0); + BKE_id_material_eval_ensure_default_slot(&mesh->id); + MutableSpan<MVert> verts{mesh->mvert, mesh->totvert}; + MutableSpan<MEdge> edges{mesh->medge, mesh->totedge}; + + short normal[3]; + normal_float_to_short_v3(normal, delta.normalized()); + + for (const int i : verts.index_range()) { + copy_v3_v3(verts[i].co, start + delta * i); + copy_v3_v3_short(verts[i].no, normal); + } + + fill_edge_data(edges); + + return mesh; +} + } // namespace blender::nodes void register_node_type_geo_mesh_primitive_line() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_line_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_line_declare; - node_type_init(&ntype, blender::nodes::geo_node_mesh_primitive_line_init); - node_type_update(&ntype, blender::nodes::geo_node_mesh_primitive_line_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryMeshLine", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_line_exec; - ntype.draw_buttons = blender::nodes::geo_node_mesh_primitive_line_layout; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc index 54a762fc15d..c109596c1c6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc @@ -25,13 +25,25 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc { -static void geo_node_mesh_primitive_uv_shpere_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { - b.add_input<decl::Int>(N_("Segments")).default_value(32).min(3).max(1024); - b.add_input<decl::Int>(N_("Rings")).default_value(16).min(2).max(1024); - b.add_input<decl::Float>(N_("Radius")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); + b.add_input<decl::Int>(N_("Segments")) + .default_value(32) + .min(3) + .max(1024) + .description(N_("Horizontal resolution of the sphere")); + b.add_input<decl::Int>(N_("Rings")) + .default_value(16) + .min(2) + .max(1024) + .description(N_("The number of horizontal rings")); + b.add_input<decl::Float>(N_("Radius")) + .default_value(1.0f) + .min(0.0f) + .subtype(PROP_DISTANCE) + .description(N_("Distance from the generated points to the origin")); b.add_output<decl::Geometry>(N_("Mesh")); } @@ -280,7 +292,7 @@ static Mesh *create_uv_sphere_mesh(const float radius, const int segments, const return mesh; } -static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const int segments_num = params.extract_input<int>("Segments"); const int rings_num = params.extract_input<int>("Rings"); @@ -301,15 +313,17 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params) params.set_output("Mesh", GeometrySet::create_with_mesh(mesh)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_primitive_uv_sphere_cc void register_node_type_geo_mesh_primitive_uv_sphere() { + namespace file_ns = blender::nodes::node_geo_mesh_primitive_uv_sphere_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, "UV Sphere", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_primitive_uv_shpere_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_uv_sphere_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc index d99c0c851a8..6206b51b6a8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc @@ -23,9 +23,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_subdivide_cc { -static void geo_node_mesh_subdivide_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -72,7 +72,7 @@ static void geometry_set_mesh_subdivide(GeometrySet &geometry_set, const int lev BKE_subdiv_free(subdiv); } -static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -97,14 +97,16 @@ static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_subdivide_cc void register_node_type_geo_mesh_subdivide() { + namespace file_ns = blender::nodes::node_geo_mesh_subdivide_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE_MESH, "Subdivide Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_subdivide_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc index 11865c635b8..90f0af75788 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc @@ -18,16 +18,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_curve_cc { -static void geo_node_legacy_mesh_to_curve_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); @@ -56,14 +56,16 @@ static void geo_node_legacy_mesh_to_curve_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_curve_cc void register_node_type_geo_mesh_to_curve() { + namespace file_ns = blender::nodes::node_geo_mesh_to_curve_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_legacy_mesh_to_curve_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_legacy_mesh_to_curve_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc index 92911e89f59..d3c4aa87547 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_points.cc @@ -26,9 +26,9 @@ using blender::Array; -namespace blender::nodes { +namespace blender::nodes::node_geo_mesh_to_points_cc { -static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -41,12 +41,12 @@ static void geo_node_mesh_to_points_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Points")); } -static void geo_node_mesh_to_points_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", 0, "", ICON_NONE); } -static void geo_node_mesh_to_points_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryMeshToPoints *data = (NodeGeometryMeshToPoints *)MEM_callocN( sizeof(NodeGeometryMeshToPoints), __func__); @@ -113,14 +113,14 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); + GVArray src = mesh_component->attribute_get_for_read(attribute_id, domain, data_type); OutputAttribute dst = point_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - copy_attribute_to_points(*src_typed, selection, dst.as_span().typed<T>()); + VArray<T> src_typed = src.typed<T>(); + copy_attribute_to_points(src_typed, selection, dst.as_span().typed<T>()); }); dst.save(); } @@ -129,7 +129,7 @@ static void geometry_set_mesh_to_points(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); Field<float3> position = params.extract_input<Field<float3>>("Position"); @@ -172,17 +172,19 @@ static void geo_node_mesh_to_points_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_mesh_to_points_cc void register_node_type_geo_mesh_to_points() { + namespace file_ns = blender::nodes::node_geo_mesh_to_points_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_MESH_TO_POINTS, "Mesh to Points", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_mesh_to_points_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_points_exec; - node_type_init(&ntype, blender::nodes::geo_node_mesh_to_points_init); - ntype.draw_buttons = blender::nodes::geo_node_mesh_to_points_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + ntype.draw_buttons = file_ns::node_layout; node_type_storage( &ntype, "NodeGeometryMeshToPoints", node_free_standard_storage, node_copy_standard_storage); nodeRegisterType(&ntype); 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 3ba32c4b674..ff71bf973b2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -21,83 +21,93 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_object_info_cc { -static void geo_node_object_info_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Object>(N_("Object")).hide_label(); b.add_input<decl::Bool>(N_("As Instance")) - .description( - N_("Output the entire object as single instance. " - "This allows instancing non-geometry object types")); + .description(N_("Output the entire object as single instance. " + "This allows instancing non-geometry object types")); b.add_output<decl::Vector>(N_("Location")); b.add_output<decl::Vector>(N_("Rotation")); b.add_output<decl::Vector>(N_("Scale")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_object_info_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "transform_space", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_object_info_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const bNode &bnode = params.node(); NodeGeometryObjectInfo *node_storage = (NodeGeometryObjectInfo *)bnode.storage; const bool transform_space_relative = (node_storage->transform_space == GEO_NODE_TRANSFORM_SPACE_RELATIVE); - Object *object = params.get_input<Object *>("Object"); + auto default_transform = [&]() { + params.set_output("Location", float3(0)); + params.set_output("Rotation", float3(0)); + params.set_output("Scale", float3(0)); + }; + auto default_geometry = [&]() { params.set_output("Geometry", GeometrySet()); }; - float3 location = {0, 0, 0}; - float3 rotation = {0, 0, 0}; - float3 scale = {0, 0, 0}; - GeometrySet geometry_set; + Object *object = params.get_input<Object *>("Object"); const Object *self_object = params.self_object(); + if (object == nullptr) { + default_transform(); + default_geometry(); + return; + } - if (object != nullptr) { - const float4x4 transform = float4x4(self_object->imat) * float4x4(object->obmat); + const float4x4 &object_matrix = object->obmat; + const float4x4 transform = float4x4(self_object->imat) * object_matrix; - float quaternion[4]; - if (transform_space_relative) { - mat4_decompose(location, quaternion, scale, transform.values); - } - else { - mat4_decompose(location, quaternion, scale, object->obmat); + if (transform_space_relative) { + params.set_output("Location", transform.translation()); + params.set_output("Rotation", transform.to_euler()); + params.set_output("Scale", transform.scale()); + } + else { + params.set_output("Location", object_matrix.translation()); + params.set_output("Rotation", object_matrix.to_euler()); + params.set_output("Scale", object_matrix.scale()); + } + + if (params.output_is_required("Geometry")) { + if (object == self_object) { + params.error_message_add(NodeWarningType::Error, + TIP_("Geometry cannot be retrieved from the modifier object")); + default_geometry(); + return; } - quat_to_eul(rotation, quaternion); - - if (object != self_object) { - if (params.get_input<bool>("As Instance")) { - InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); - const int handle = instances.add_reference(*object); - if (transform_space_relative) { - instances.add_instance(handle, transform); - } - else { - float unit_transform[4][4]; - unit_m4(unit_transform); - instances.add_instance(handle, unit_transform); - } + + GeometrySet geometry_set; + if (params.get_input<bool>("As Instance")) { + InstancesComponent &instances = geometry_set.get_component_for_write<InstancesComponent>(); + const int handle = instances.add_reference(*object); + if (transform_space_relative) { + instances.add_instance(handle, transform); } else { - geometry_set = bke::object_get_evaluated_geometry_set(*object); - if (transform_space_relative) { - transform_geometry_set(geometry_set, transform, *params.depsgraph()); - } + instances.add_instance(handle, float4x4::identity()); + } + } + else { + geometry_set = bke::object_get_evaluated_geometry_set(*object); + if (transform_space_relative) { + transform_geometry_set(geometry_set, transform, *params.depsgraph()); } } - } - params.set_output("Location", location); - params.set_output("Rotation", rotation); - params.set_output("Scale", scale); - params.set_output("Geometry", geometry_set); + params.set_output("Geometry", geometry_set); + } } -static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryObjectInfo *data = (NodeGeometryObjectInfo *)MEM_callocN( sizeof(NodeGeometryObjectInfo), __func__); @@ -105,18 +115,20 @@ static void geo_node_object_info_node_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_object_info_cc void register_node_type_geo_object_info() { + namespace file_ns = blender::nodes::node_geo_object_info_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_OBJECT_INFO, "Object Info", NODE_CLASS_INPUT, 0); - node_type_init(&ntype, blender::nodes::geo_node_object_info_node_init); + node_type_init(&ntype, file_ns::node_node_init); node_type_storage( &ntype, "NodeGeometryObjectInfo", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_object_info_exec; - ntype.draw_buttons = blender::nodes::geo_node_object_info_layout; - ntype.declare = blender::nodes::geo_node_object_info_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc index 3e0096824d3..5510773eabd 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_vertices.cc @@ -21,11 +21,11 @@ #include "node_geometry_util.hh" -using blender::Array; +namespace blender::nodes::node_geo_points_to_vertices_cc { -namespace blender::nodes { +using blender::Array; -static void geo_node_points_to_vertices_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).supports_field().hide_value(); @@ -74,15 +74,15 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, for (Map<AttributeIDRef, AttributeKind>::Item entry : attributes.items()) { const AttributeIDRef attribute_id = entry.key; const CustomDataType data_type = entry.value.data_type; - GVArrayPtr src = point_component->attribute_get_for_read( + GVArray src = point_component->attribute_get_for_read( attribute_id, ATTR_DOMAIN_POINT, data_type); OutputAttribute dst = mesh_component.attribute_try_get_for_output_only( attribute_id, ATTR_DOMAIN_POINT, data_type); if (dst && src) { attribute_math::convert_to_static_type(data_type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src_typed{*src}; - VArray_Span<T> src_typed_span{*src_typed}; + VArray<T> src_typed = src.typed<T>(); + VArray_Span<T> src_typed_span{src_typed}; copy_attribute_to_vertices(src_typed_span, selection, dst.as_span().typed<T>()); }); dst.save(); @@ -92,7 +92,7 @@ static void geometry_set_points_to_vertices(GeometrySet &geometry_set, geometry_set.keep_only({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_INSTANCES}); } -static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -104,15 +104,17 @@ static void geo_node_points_to_vertices_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_vertices_cc void register_node_type_geo_points_to_vertices() { + namespace file_ns = blender::nodes::node_geo_points_to_vertices_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_POINTS_TO_VERTICES, "Points to Vertices", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_points_to_vertices_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_vertices_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index 312ea7df919..a064dca3a3f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -28,9 +28,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_points_to_volume_cc { -static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")); b.add_input<decl::Float>(N_("Density")).default_value(1.0f).min(0.0f); @@ -44,16 +44,14 @@ static void geo_node_points_to_volume_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Volume")); } -static void geo_node_points_to_volume_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( sizeof(NodeGeometryPointsToVolume), __func__); @@ -61,16 +59,19 @@ static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node node->storage = data; } -static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *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, + nodeSetSocketAvailability(ntree, + 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); + nodeSetSocketAvailability(ntree, + voxel_size_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); } #ifdef WITH_OPENVDB @@ -165,7 +166,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, Vector<float3> &r_positions, Vector<float> &r_radii) { - GVArray_Typed<float3> positions = component.attribute_get_for_read<float3>( + VArray<float3> positions = component.attribute_get_for_read<float3>( "position", ATTR_DOMAIN_POINT, {0, 0, 0}); Field<float> radius_field = params.get_input<Field<float>>("Radius"); @@ -173,7 +174,7 @@ static void gather_point_data_from_component(GeoNodeExecParams ¶ms, const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); r_positions.resize(r_positions.size() + domain_size); - positions->materialize(r_positions.as_mutable_span().take_back(domain_size)); + positions.materialize(r_positions.as_mutable_span().take_back(domain_size)); r_radii.resize(r_radii.size() + domain_size); fn::FieldEvaluator evaluator{field_context, domain_size}; @@ -222,22 +223,18 @@ static void initialize_volume_component_from_points(GeoNodeExecParams ¶ms, 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<openvdb::FloatGrid>( - BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false)); - const float density = params.get_input<float>("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); + new_grid->transform().postScale(voxel_size); + BKE_volume_grid_add_vdb(*volume, "density", std::move(new_grid)); + r_geometry_set.keep_only({GEO_COMPONENT_TYPE_VOLUME, GEO_COMPONENT_TYPE_INSTANCES}); r_geometry_set.replace_volume(volume); } #endif -static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); @@ -253,10 +250,12 @@ static void geo_node_points_to_volume_exec(GeoNodeExecParams params) #endif } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_points_to_volume_cc void register_node_type_geo_points_to_volume() { + namespace file_ns = blender::nodes::node_geo_points_to_volume_cc; + static bNodeType ntype; geo_node_type_base( @@ -266,10 +265,10 @@ void register_node_type_geo_points_to_volume() 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.declare = blender::nodes::geo_node_points_to_volume_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; - ntype.draw_buttons = blender::nodes::geo_node_points_to_volume_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc index c05476b982b..4431ccd5459 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_proximity.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_proximity.cc @@ -27,9 +27,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_proximity_cc { -static void geo_node_proximity_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) .only_realized_data() @@ -39,7 +39,7 @@ static void geo_node_proximity_declare(NodeDeclarationBuilder &b) b.add_output<decl::Float>(N_("Distance")).dependent_field(); } -static void geo_node_proximity_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target_element", 0, "", ICON_NONE); } @@ -206,7 +206,7 @@ class ProximityFunction : public fn::MultiFunction { } }; -static void geo_node_proximity_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set_target = params.extract_input<GeometrySet>("Target"); geometry_set_target.ensure_owns_direct_data(); @@ -233,18 +233,20 @@ static void geo_node_proximity_exec(GeoNodeExecParams params) params.set_output("Distance", Field<float>(proximity_op, 1)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_proximity_cc void register_node_type_geo_proximity() { + namespace file_ns = blender::nodes::node_geo_proximity_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_PROXIMITY, "Geometry Proximity", NODE_CLASS_GEOMETRY, 0); - node_type_init(&ntype, blender::nodes::geo_proximity_init); + node_type_init(&ntype, file_ns::geo_proximity_init); node_type_storage( &ntype, "NodeGeometryProximity", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_proximity_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_proximity_exec; - ntype.draw_buttons = blender::nodes::geo_node_proximity_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc index 42924a46667..c1f5b0c6706 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc @@ -25,11 +25,11 @@ #include "node_geometry_util.hh" -using namespace blender::bke::mesh_surface_sample; +namespace blender::nodes::node_geo_raycast_cc { -namespace blender::nodes { +using namespace blender::bke::mesh_surface_sample; -static void geo_node_raycast_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target Geometry")) .only_realized_data() @@ -63,13 +63,13 @@ static void geo_node_raycast_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({1, 2, 3, 4, 5, 6}); } -static void geo_node_raycast_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); uiItemR(layout, ptr, "mapping", 0, "", ICON_NONE); } -static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryRaycast *data = (NodeGeometryRaycast *)MEM_callocN(sizeof(NodeGeometryRaycast), __func__); @@ -78,7 +78,7 @@ static void geo_node_raycast_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(data.data_type); @@ -89,11 +89,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *socket_boolean = socket_color4f->next; bNodeSocket *socket_int32 = socket_boolean->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); bNodeSocket *out_socket_vector = (bNodeSocket *)BLI_findlink(&node->outputs, 4); bNodeSocket *out_socket_float = out_socket_vector->next; @@ -101,11 +101,11 @@ static void geo_node_raycast_update(bNodeTree *UNUSED(ntree), bNode *node) bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static eAttributeMapMode get_map_mode(GeometryNodeRaycastMapMode map_mode) @@ -375,7 +375,7 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_raycast_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet target = params.extract_input<GeometrySet>("Target Geometry"); const NodeGeometryRaycast &data = *(const NodeGeometryRaycast *)params.node().storage; @@ -426,20 +426,22 @@ static void geo_node_raycast_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_raycast_cc void register_node_type_geo_raycast() { + namespace file_ns = blender::nodes::node_geo_raycast_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_RAYCAST, "Raycast", NODE_CLASS_GEOMETRY, 0); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); - node_type_init(&ntype, blender::nodes::geo_node_raycast_init); - node_type_update(&ntype, blender::nodes::geo_node_raycast_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage( &ntype, "NodeGeometryRaycast", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_raycast_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_raycast_exec; - ntype.draw_buttons = blender::nodes::geo_node_raycast_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc index 6c51c1f738f..5b161e66d97 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_realize_instances.cc @@ -19,30 +19,32 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_realize_instances_cc { -static void geo_node_realize_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Geometry")); } -static void geo_node_realize_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); geometry_set = bke::geometry_set_realize_instances(geometry_set); params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_realize_instances_cc void register_node_type_geo_realize_instances() { + namespace file_ns = blender::nodes::node_geo_realize_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_REALIZE_INSTANCES, "Realize Instances", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_realize_instances_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_realize_instances_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc index abf44b1aaf8..0508ff7a215 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_rotate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_rotate_instances_cc { -static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -32,7 +32,7 @@ static void geo_node_rotate_instances_declare(NodeDeclarationBuilder &b) static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; const int domain_size = instances_component.instances_amount(); fn::FieldEvaluator selection_evaluator{field_context, domain_size}; @@ -96,7 +96,7 @@ static void rotate_instances(GeoNodeExecParams ¶ms, InstancesComponent &inst }); } -static void geo_node_rotate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -106,15 +106,17 @@ static void geo_node_rotate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_rotate_instances_cc void register_node_type_geo_rotate_instances() { + namespace file_ns = blender::nodes::node_geo_rotate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_ROTATE_INSTANCES, "Rotate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_rotate_instances_exec; - ntype.declare = blender::nodes::geo_node_rotate_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc index ea2b458410e..3e0f3160f89 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_scale_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_scale_instances_cc { -static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -35,7 +35,7 @@ static void geo_node_scale_instances_declare(NodeDeclarationBuilder &b) static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); @@ -75,7 +75,7 @@ static void scale_instances(GeoNodeExecParams ¶ms, InstancesComponent &insta }); } -static void geo_node_scale_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -85,14 +85,16 @@ static void geo_node_scale_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_scale_instances_cc void register_node_type_geo_scale_instances() { + namespace file_ns = blender::nodes::node_geo_scale_instances_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SCALE_INSTANCES, "Scale Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_scale_instances_exec; - ntype.declare = blender::nodes::geo_node_scale_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc index a16fb712b13..e4adfe6587d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_components.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_components_cc { -static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_output<decl::Geometry>(N_("Mesh")); @@ -28,7 +28,7 @@ static void geo_node_join_geometry_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Instances")); } -static void geo_node_separate_components_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -61,15 +61,17 @@ static void geo_node_separate_components_exec(GeoNodeExecParams params) params.set_output("Instances", instances); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_components_cc void register_node_type_geo_separate_components() { + namespace file_ns = blender::nodes::node_geo_separate_components_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SEPARATE_COMPONENTS, "Separate Components", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_join_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_components_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc index 28e214c0ccc..220aa07faa6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_separate_geometry.cc @@ -19,9 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_separate_geometry_cc { -static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")) @@ -35,14 +35,12 @@ static void geo_node_separate_geometry_declare(NodeDeclarationBuilder &b) .description(N_("The parts of the geometry not in the selection")); } -static void geo_node_separate_geometry_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "domain", 0, "", ICON_NONE); } -static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySeparateGeometry *data = (NodeGeometrySeparateGeometry *)MEM_callocN( sizeof(NodeGeometrySeparateGeometry), __func__); @@ -51,7 +49,7 @@ static void geo_node_separate_geometry_init(bNodeTree *UNUSED(tree), bNode *node node->storage = data; } -static void geo_node_separate_geometry_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -95,10 +93,12 @@ static void geo_node_separate_geometry_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_separate_geometry_cc void register_node_type_geo_separate_geometry() { + namespace file_ns = blender::nodes::node_geo_separate_geometry_cc; + static bNodeType ntype; geo_node_type_base( @@ -109,10 +109,10 @@ void register_node_type_geo_separate_geometry() node_free_standard_storage, node_copy_standard_storage); - node_type_init(&ntype, blender::nodes::geo_node_separate_geometry_init); + node_type_init(&ntype, file_ns::node_init); - ntype.declare = blender::nodes::geo_node_separate_geometry_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_separate_geometry_exec; - ntype.draw_buttons = blender::nodes::geo_node_separate_geometry_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc index b64aa266330..f0b8579ae7d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_handles.cc @@ -21,24 +21,23 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_handles_cc { -static void geo_node_set_curve_handles_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); b.add_input<decl::Vector>(N_("Position")).implicit_field(); + b.add_input<decl::Vector>(N_("Offset")).default_value(float3(0.0f, 0.0f, 0.0f)).supports_field(); b.add_output<decl::Geometry>(N_("Curve")); } -static void geo_node_set_curve_handles_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); } -static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometrySetCurveHandlePositions *data = (NodeGeometrySetCurveHandlePositions *)MEM_callocN( sizeof(NodeGeometrySetCurveHandlePositions), __func__); @@ -50,7 +49,8 @@ static void geo_node_set_curve_handles_init(bNodeTree *UNUSED(tree), bNode *node static void set_position_in_component(const GeometryNodeCurveHandleMode mode, GeometryComponent &component, const Field<bool> &selection_field, - const Field<float3> &position_field) + const Field<float3> &position_field, + const Field<float3> &offset_field) { GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); @@ -111,15 +111,26 @@ static void set_position_in_component(const GeometryNodeCurveHandleMode mode, } } - OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output_only<float3>( - side, ATTR_DOMAIN_POINT); fn::FieldEvaluator position_evaluator{field_context, &selection}; - position_evaluator.add_with_destination(position_field, positions.varray()); + position_evaluator.add(position_field); + position_evaluator.add(offset_field); position_evaluator.evaluate(); + + const VArray<float3> &positions_input = position_evaluator.get_evaluated<float3>(0); + const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); + + OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( + side, ATTR_DOMAIN_POINT, {0, 0, 0}); + MutableSpan<float3> position_mutable = positions.as_span(); + + for (int i : selection) { + position_mutable[i] = positions_input[i] + offsets_input[i]; + } + positions.save(); } -static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeGeometrySetCurveHandlePositions *node_storage = (NodeGeometrySetCurveHandlePositions *)params.node().storage; @@ -128,6 +139,7 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); Field<float3> position_field = params.extract_input<Field<float3>>("Position"); + Field<float3> offset_field = params.extract_input<Field<float3>>("Offset"); bool has_bezier = false; geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { @@ -137,7 +149,8 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) set_position_in_component(mode, geometry_set.get_component_for_write<CurveComponent>(), selection_field, - position_field); + position_field, + offset_field); } }); if (!has_bezier) { @@ -147,22 +160,24 @@ static void geo_node_set_curve_handles_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_handles_cc void register_node_type_geo_set_curve_handles() { + namespace file_ns = blender::nodes::node_geo_set_curve_handles_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_HANDLES, "Set Handle Positions", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_handles_exec; - ntype.declare = blender::nodes::geo_node_set_curve_handles_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; ntype.minwidth = 100.0f; - node_type_init(&ntype, blender::nodes::geo_node_set_curve_handles_init); + node_type_init(&ntype, file_ns::node_init); node_type_storage(&ntype, "NodeGeometrySetCurveHandlePositions", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_set_curve_handles_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc index e47ce7dea30..fd486f07e69 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_radius_cc { -static void geo_node_set_curve_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -53,7 +53,7 @@ static void set_radius_in_component(GeometryComponent &component, radii.save(); } -static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -69,15 +69,17 @@ static void geo_node_set_curve_radius_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_radius_cc void register_node_type_geo_set_curve_radius() { + namespace file_ns = blender::nodes::node_geo_set_curve_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_CURVE_RADIUS, "Set Curve Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_radius_exec; - ntype.declare = blender::nodes::geo_node_set_curve_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc index a861c35f738..653ae39b4fa 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_curve_tilt.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_curve_tilt_cc { -static void geo_node_set_curve_tilt_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Curve")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_tilt_in_component(GeometryComponent &component, tilts.save(); } -static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Curve"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,14 +65,16 @@ static void geo_node_set_curve_tilt_exec(GeoNodeExecParams params) params.set_output("Curve", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_curve_tilt_cc void register_node_type_geo_set_curve_tilt() { + namespace file_ns = blender::nodes::node_geo_set_curve_tilt_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_CURVE_TILT, "Set Curve Tilt", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_curve_tilt_exec; - ntype.declare = blender::nodes::geo_node_set_curve_tilt_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc index 77d8e786501..e2f48edc72d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_id.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_id.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_id_cc { -static void geo_node_set_id_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -63,7 +63,7 @@ static void set_id_in_component(GeometryComponent &component, } } -static void geo_node_set_id_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,14 +81,16 @@ static void geo_node_set_id_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_id_cc void register_node_type_geo_set_id() { + namespace file_ns = blender::nodes::node_geo_set_id_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_ID, "Set ID", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_id_exec; - ntype.declare = blender::nodes::geo_node_set_id_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc index 3817de02a38..fd65bcc235a 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material.cc @@ -25,9 +25,9 @@ #include "BKE_material.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_cc { -static void geo_node_set_material_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")) .supported_type({GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_VOLUME}); @@ -59,7 +59,7 @@ static void assign_material_to_faces(Mesh &mesh, const IndexMask selection, Mate } } -static void geo_node_set_material_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Material *material = params.extract_input<Material *>("Material"); const Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -103,14 +103,16 @@ static void geo_node_set_material_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_cc void register_node_type_geo_set_material() { + namespace file_ns = blender::nodes::node_geo_set_material_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_MATERIAL, "Set Material", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_set_material_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc index a8bb1bd8644..25634311225 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_material_index.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_material_index_cc { -static void geo_node_set_material_index_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_material_index_in_component(GeometryComponent &component, indices.save(); } -static void geo_node_set_material_index_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +64,17 @@ static void geo_node_set_material_index_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_material_index_cc void register_node_type_geo_set_material_index() { + namespace file_ns = blender::nodes::node_geo_set_material_index_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_MATERIAL_INDEX, "Set Material Index", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_material_index_exec; - ntype.declare = blender::nodes::geo_node_set_material_index_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc index 9ff299542b4..bc7c59f75be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_point_radius.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_point_radius_cc { -static void geo_node_set_point_radius_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Points")).supported_type(GEO_COMPONENT_TYPE_POINT_CLOUD); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -53,7 +53,7 @@ static void set_radius_in_component(GeometryComponent &component, radii.save(); } -static void geo_node_set_point_radius_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Points"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -70,15 +70,17 @@ static void geo_node_set_point_radius_exec(GeoNodeExecParams params) params.set_output("Points", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_point_radius_cc void register_node_type_geo_set_point_radius() { + namespace file_ns = blender::nodes::node_geo_set_point_radius_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_POINT_RADIUS, "Set Point Radius", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_point_radius_exec; - ntype.declare = blender::nodes::geo_node_set_point_radius_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc index 4e564386a28..a8e59a807e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_position.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_position.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_position_cc { -static void geo_node_set_position_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -34,8 +34,11 @@ static void set_position_in_component(GeometryComponent &component, const Field<float3> &position_field, const Field<float3> &offset_field) { - GeometryComponentFieldContext field_context{component, ATTR_DOMAIN_POINT}; - const int domain_size = component.attribute_domain_size(ATTR_DOMAIN_POINT); + AttributeDomain domain = component.type() == GEO_COMPONENT_TYPE_INSTANCES ? + ATTR_DOMAIN_INSTANCE : + ATTR_DOMAIN_POINT; + GeometryComponentFieldContext field_context{component, domain}; + const int domain_size = component.attribute_domain_size(domain); if (domain_size == 0) { return; } @@ -57,7 +60,7 @@ static void set_position_in_component(GeometryComponent &component, const VArray<float3> &offsets_input = position_evaluator.get_evaluated<float3>(1); OutputAttribute_Typed<float3> positions = component.attribute_try_get_for_output<float3>( - "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + "position", domain, {0, 0, 0}); MutableSpan<float3> position_mutable = positions.as_span(); for (int i : selection) { @@ -66,7 +69,7 @@ static void set_position_in_component(GeometryComponent &component, positions.save(); } -static void geo_node_set_position_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -86,14 +89,16 @@ static void geo_node_set_position_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_position_cc void register_node_type_geo_set_position() { + namespace file_ns = blender::nodes::node_geo_set_position_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SET_POSITION, "Set Position", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_position_exec; - ntype.declare = blender::nodes::geo_node_set_position_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc index 06e25c2ed55..a8831130453 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_shade_smooth.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_shade_smooth_cc { -static void geo_node_set_shade_smooth_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_smooth_in_component(GeometryComponent &component, shades.save(); } -static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -64,15 +64,17 @@ static void geo_node_set_shade_smooth_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_shade_smooth_cc void register_node_type_geo_set_shade_smooth() { + namespace file_ns = blender::nodes::node_geo_set_shade_smooth_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SHADE_SMOOTH, "Set Shade Smooth", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_shade_smooth_exec; - ntype.declare = blender::nodes::geo_node_set_shade_smooth_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc index ec751ae1d2b..7ffda8787e6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_cyclic.cc @@ -16,9 +16,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_cyclic_cc { -static void geo_node_set_spline_cyclic_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -49,7 +49,7 @@ static void set_cyclic_in_component(GeometryComponent &component, cyclics.save(); } -static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -65,15 +65,17 @@ static void geo_node_set_spline_cyclic_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_cyclic_cc void register_node_type_geo_set_spline_cyclic() { + namespace file_ns = blender::nodes::node_geo_set_spline_cyclic_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_CYCLIC, "Set Spline Cyclic", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_cyclic_exec; - ntype.declare = blender::nodes::geo_node_set_spline_cyclic_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc index ccf419975ca..4280372faa6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_set_spline_resolution.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_set_spline_resolution_cc { -static void geo_node_set_spline_resolution_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")).supported_type(GEO_COMPONENT_TYPE_CURVE); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -51,7 +51,7 @@ static void set_resolution_in_component(GeometryComponent &component, resolutions.save(); } -static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); Field<bool> selection_field = params.extract_input<Field<bool>>("Selection"); @@ -81,15 +81,17 @@ static void geo_node_set_spline_resolution_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_set_spline_resolution_cc void register_node_type_geo_set_spline_resolution() { + namespace file_ns = blender::nodes::node_geo_set_spline_resolution_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SET_SPLINE_RESOLUTION, "Set Spline Resolution", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_set_spline_resolution_exec; - ntype.declare = blender::nodes::geo_node_set_spline_resolution_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc index 98d0aca084a..5308b43afb2 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_join.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_join.cc @@ -16,16 +16,16 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_join_cc { -static void geo_node_string_join_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("Delimiter")); b.add_input<decl::String>(N_("Strings")).multi_input().hide_value(); b.add_output<decl::String>(N_("String")); }; -static void geo_node_string_join_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { Vector<std::string> strings = params.extract_multi_input<std::string>("Strings"); const std::string delim = params.extract_input<std::string>("Delimiter"); @@ -40,14 +40,16 @@ static void geo_node_string_join_exec(GeoNodeExecParams params) params.set_output("String", std::move(output)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_join_cc void register_node_type_geo_string_join() { + namespace file_ns = blender::nodes::node_geo_string_join_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_STRING_JOIN, "Join Strings", NODE_CLASS_CONVERTER, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_string_join_exec; - ntype.declare = blender::nodes::geo_node_string_join_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc index 95e94a22d81..6a793e12f82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_string_to_curves.cc @@ -30,9 +30,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_string_to_curves_cc { -static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::String>(N_("String")); b.add_input<decl::Float>(N_("Size")).default_value(1.0f).min(0.0f).subtype(PROP_DISTANCE); @@ -60,7 +60,7 @@ static void geo_node_string_to_curves_declare(NodeDeclarationBuilder &b) b.add_output<decl::String>(N_("Remainder")); } -static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) +static void node_layout(uiLayout *layout, struct bContext *C, PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); @@ -79,7 +79,7 @@ static void geo_node_string_to_curves_layout(uiLayout *layout, struct bContext * uiItemR(layout, ptr, "align_y", 0, "", ICON_NONE); } -static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryStringToCurves *data = (NodeGeometryStringToCurves *)MEM_callocN( sizeof(NodeGeometryStringToCurves), __func__); @@ -91,17 +91,19 @@ static void geo_node_string_to_curves_init(bNodeTree *UNUSED(ntree), bNode *node node->id = (ID *)BKE_vfont_builtin_get(); } -static void geo_node_string_to_curves_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryStringToCurves *storage = (const NodeGeometryStringToCurves *)node->storage; const GeometryNodeStringToCurvesOverflowMode overflow = (GeometryNodeStringToCurvesOverflowMode) storage->overflow; bNodeSocket *socket_remainder = ((bNodeSocket *)node->outputs.first)->next; - nodeSetSocketAvailability(socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); + nodeSetSocketAvailability( + ntree, socket_remainder, overflow == GEO_NODE_STRING_TO_CURVES_MODE_TRUNCATE); bNodeSocket *height_socket = (bNodeSocket *)node->inputs.last; bNodeSocket *width_socket = height_socket->prev; - nodeSetSocketAvailability(height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); + nodeSetSocketAvailability( + ntree, height_socket, overflow != GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW); node_sock_label(width_socket, overflow == GEO_NODE_STRING_TO_CURVES_MODE_OVERFLOW ? N_("Max Width") : N_("Text Box Width")); @@ -263,7 +265,7 @@ static void add_instances_from_handles(InstancesComponent &instances, }); } -static void geo_node_string_to_curves_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { TextLayout layout = get_text_layout(params); @@ -295,23 +297,25 @@ static void geo_node_string_to_curves_exec(GeoNodeExecParams params) params.set_output("Curves", std::move(geometry_set_out)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_string_to_curves_cc void register_node_type_geo_string_to_curves() { + namespace file_ns = blender::nodes::node_geo_string_to_curves_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_STRING_TO_CURVES, "String to Curves", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_string_to_curves_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_string_to_curves_exec; - node_type_init(&ntype, blender::nodes::geo_node_string_to_curves_init); - node_type_update(&ntype, blender::nodes::geo_node_string_to_curves_update); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_size(&ntype, 190, 120, 700); node_type_storage(&ntype, "NodeGeometryStringToCurves", node_free_standard_storage, node_copy_standard_storage); - ntype.draw_buttons = blender::nodes::geo_node_string_to_curves_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc index 2b3430a5ed0..011d1e2af82 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc @@ -27,9 +27,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_subdivision_surface_cc { -static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Level")).default_value(1).min(0).max(6); @@ -42,15 +42,13 @@ static void geo_node_subdivision_surface_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "uv_smooth", 0, "", ICON_NONE); uiItemR(layout, ptr, "boundary_smooth", 0, "", ICON_NONE); } -static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometrySubdivisionSurface *data = (NodeGeometrySubdivisionSurface *)MEM_callocN( sizeof(NodeGeometrySubdivisionSurface), __func__); @@ -59,7 +57,7 @@ static void geo_node_subdivision_surface_init(bNodeTree *UNUSED(ntree), bNode *n node->storage = data; } -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); #ifndef WITH_OPENSUBDIV @@ -145,18 +143,20 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_subdivision_surface_cc void register_node_type_geo_subdivision_surface() { + namespace file_ns = blender::nodes::node_geo_subdivision_surface_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_subdivision_surface_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = blender::nodes::geo_node_subdivision_surface_layout; - node_type_init(&ntype, blender::nodes::geo_node_subdivision_surface_init); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; + node_type_init(&ntype, file_ns::node_init); node_type_size_preset(&ntype, NODE_SIZE_MIDDLE); node_type_storage(&ntype, "NodeGeometrySubdivisionSurface", diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc index 7e07a552650..3a07af30e19 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc @@ -26,9 +26,9 @@ #include "FN_multi_function_signature.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_switch_cc { -static void geo_node_switch_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Bool>(N_("Switch")).default_value(false).supports_field(); b.add_input<decl::Bool>(N_("Switch"), "Switch_001").default_value(false); @@ -83,19 +83,19 @@ static void geo_node_switch_declare(NodeDeclarationBuilder &b) b.add_output<decl::Image>(N_("Output"), "Output_011"); } -static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "input_type", 0, "", ICON_NONE); } -static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__); data->input_type = SOCK_GEOMETRY; node->storage = data; } -static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeSwitch *node_storage = (NodeSwitch *)node->storage; int index = 0; @@ -110,20 +110,20 @@ static void geo_node_switch_update(bNodeTree *UNUSED(ntree), bNode *node) SOCK_RGBA, SOCK_STRING); - nodeSetSocketAvailability(field_switch, fields_type); - nodeSetSocketAvailability(non_field_switch, !fields_type); + nodeSetSocketAvailability(ntree, field_switch, fields_type); + nodeSetSocketAvailability(ntree, non_field_switch, !fields_type); LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, &node->inputs, index) { if (index <= 1) { continue; } - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } LISTBASE_FOREACH (bNodeSocket *, socket, &node->outputs) { - nodeSetSocketAvailability(socket, - socket->type == (eNodeSocketDatatype)node_storage->input_type); + nodeSetSocketAvailability( + ntree, socket, socket->type == (eNodeSocketDatatype)node_storage->input_type); } } @@ -232,7 +232,7 @@ template<typename T> void switch_no_fields(GeoNodeExecParams ¶ms, const Stri } } -static void geo_node_switch_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { const NodeSwitch &storage = *(const NodeSwitch *)params.node().storage; const eNodeSocketDatatype data_type = static_cast<eNodeSocketDatatype>(storage.input_type); @@ -293,19 +293,21 @@ static void geo_node_switch_exec(GeoNodeExecParams params) } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_switch_cc void register_node_type_geo_switch() { + namespace file_ns = blender::nodes::node_geo_switch_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTER, 0); - ntype.declare = blender::nodes::geo_node_switch_declare; - node_type_init(&ntype, blender::nodes::geo_node_switch_init); - node_type_update(&ntype, blender::nodes::geo_node_switch_update); + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage); - ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec; + ntype.geometry_node_execute = file_ns::node_geo_exec; ntype.geometry_node_execute_supports_laziness = true; - ntype.draw_buttons = blender::nodes::geo_node_switch_layout; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc index 9754b3f81a0..acd8e6cad25 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transfer_attribute.cc @@ -33,17 +33,18 @@ #include "node_geometry_util.hh" +namespace blender::nodes::node_geo_transfer_attribute_cc { + using namespace blender::bke::mesh_surface_sample; using blender::fn::GArray; -namespace blender::nodes { - -static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Target")) - .only_realized_data() - .supported_type( - {GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}); + .supported_type({GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}); b.add_input<decl::Vector>(N_("Attribute")).hide_value().supports_field(); b.add_input<decl::Float>(N_("Attribute"), "Attribute_001").hide_value().supports_field(); @@ -61,9 +62,7 @@ static void geo_node_transfer_attribute_declare(NodeDeclarationBuilder &b) b.add_output<decl::Int>(N_("Attribute"), "Attribute_004").dependent_field({6, 7}); } -static void geo_node_transfer_attribute_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { const bNode &node = *static_cast<const bNode *>(ptr->data); const NodeGeometryTransferAttribute &data = *static_cast<const NodeGeometryTransferAttribute *>( @@ -77,7 +76,7 @@ static void geo_node_transfer_attribute_layout(uiLayout *layout, } } -static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryTransferAttribute *data = (NodeGeometryTransferAttribute *)MEM_callocN( sizeof(NodeGeometryTransferAttribute), __func__); @@ -86,7 +85,7 @@ static void geo_node_transfer_attribute_init(bNodeTree *UNUSED(tree), bNode *nod node->storage = data; } -static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryTransferAttribute &data = *(const NodeGeometryTransferAttribute *) node->storage; @@ -103,14 +102,14 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *socket_positions = socket_int32->next; bNodeSocket *socket_indices = socket_positions->next; - nodeSetSocketAvailability(socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, socket_int32, data_type == CD_PROP_INT32); - nodeSetSocketAvailability(socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); - nodeSetSocketAvailability(socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_positions, mapping != GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); + nodeSetSocketAvailability(ntree, socket_indices, mapping == GEO_NODE_ATTRIBUTE_TRANSFER_INDEX); bNodeSocket *out_socket_vector = (bNodeSocket *)node->outputs.first; bNodeSocket *out_socket_float = out_socket_vector->next; @@ -118,11 +117,11 @@ static void geo_node_transfer_attribute_update(bNodeTree *UNUSED(ntree), bNode * bNodeSocket *out_socket_boolean = out_socket_color4f->next; bNodeSocket *out_socket_int32 = out_socket_boolean->next; - nodeSetSocketAvailability(out_socket_vector, data_type == CD_PROP_FLOAT3); - nodeSetSocketAvailability(out_socket_float, data_type == CD_PROP_FLOAT); - nodeSetSocketAvailability(out_socket_color4f, data_type == CD_PROP_COLOR); - nodeSetSocketAvailability(out_socket_boolean, data_type == CD_PROP_BOOL); - nodeSetSocketAvailability(out_socket_int32, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(ntree, out_socket_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(ntree, out_socket_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(ntree, out_socket_color4f, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(ntree, out_socket_boolean, data_type == CD_PROP_BOOL); + nodeSetSocketAvailability(ntree, out_socket_int32, data_type == CD_PROP_INT32); } static void get_closest_in_bvhtree(BVHTreeFromMesh &tree_data, @@ -541,10 +540,10 @@ class NearestTransferFunction : public fn::MultiFunction { attribute_math::convert_to_static_type(dst.type(), [&](auto dummy) { using T = decltype(dummy); if (use_mesh_ && use_points_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices_and_comparison(*src_mesh, - *src_point, + VArray<T> src_mesh = mesh_data_->typed<T>(); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices_and_comparison(src_mesh, + src_point, mesh_distances, point_distances, mask, @@ -553,12 +552,12 @@ class NearestTransferFunction : public fn::MultiFunction { dst.typed<T>()); } else if (use_points_) { - GVArray_Typed<T> src_point{*point_data_}; - copy_with_indices(*src_point, mask, point_indices, dst.typed<T>()); + VArray<T> src_point = point_data_->typed<T>(); + copy_with_indices(src_point, mask, point_indices, dst.typed<T>()); } else if (use_mesh_) { - GVArray_Typed<T> src_mesh{*mesh_data_}; - copy_with_indices(*src_mesh, mask, mesh_indices, dst.typed<T>()); + VArray<T> src_mesh = mesh_data_->typed<T>(); + copy_with_indices(src_mesh, mask, mesh_indices, dst.typed<T>()); } }); } @@ -593,8 +592,10 @@ static const GeometryComponent *find_target_component(const GeometrySet &geometr { /* Choose the other component based on a consistent order, rather than some more complicated * heuristic. This is the same order visible in the spreadsheet and used in the ray-cast node. */ - static const Array<GeometryComponentType> supported_types = { - GEO_COMPONENT_TYPE_MESH, GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_CURVE}; + static const Array<GeometryComponentType> supported_types = {GEO_COMPONENT_TYPE_MESH, + GEO_COMPONENT_TYPE_POINT_CLOUD, + GEO_COMPONENT_TYPE_CURVE, + GEO_COMPONENT_TYPE_INSTANCES}; for (const GeometryComponentType src_type : supported_types) { if (component_is_available(geometry, src_type, domain)) { return geometry.get_component_for_read(src_type); @@ -667,8 +668,7 @@ class IndexTransferFunction : public fn::MultiFunction { attribute_math::convert_to_static_type(type, [&](auto dummy) { using T = decltype(dummy); - GVArray_Typed<T> src{*src_data_}; - copy_with_indices_clamped(*src, mask, indices, dst.typed<T>()); + copy_with_indices_clamped(src_data_->typed<T>(), mask, indices, dst.typed<T>()); }); } }; @@ -720,7 +720,7 @@ static void output_attribute_field(GeoNodeExecParams ¶ms, GField field) } } -static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry = params.extract_input<GeometrySet>("Target"); const bNode &node = params.node(); @@ -738,10 +738,6 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) }); }; - /* Since the instances are not used, there is no point in keeping - * a reference to them while the field is passed around. */ - geometry.remove(GEO_COMPONENT_TYPE_INSTANCES); - GField output_field; switch (mapping) { case GEO_NODE_ATTRIBUTE_TRANSFER_NEAREST_FACE_INTERPOLATED: { @@ -795,22 +791,24 @@ static void geo_node_transfer_attribute_exec(GeoNodeExecParams params) output_attribute_field(params, std::move(output_field)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_transfer_attribute_cc void register_node_type_geo_transfer_attribute() { + namespace file_ns = blender::nodes::node_geo_transfer_attribute_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_TRANSFER_ATTRIBUTE, "Transfer Attribute", NODE_CLASS_ATTRIBUTE, 0); - node_type_init(&ntype, blender::nodes::geo_node_transfer_attribute_init); - node_type_update(&ntype, blender::nodes::geo_node_transfer_attribute_update); + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); node_type_storage(&ntype, "NodeGeometryTransferAttribute", node_free_standard_storage, node_copy_standard_storage); - ntype.declare = blender::nodes::geo_node_transfer_attribute_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transfer_attribute_exec; - ntype.draw_buttons = blender::nodes::geo_node_transfer_attribute_layout; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; 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 2c55a255b5d..8322de20d20 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -35,15 +35,6 @@ namespace blender::nodes { -static void geo_node_transform_declare(NodeDeclarationBuilder &b) -{ - b.add_input<decl::Geometry>(N_("Geometry")); - b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); - b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); - b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); - b.add_output<decl::Geometry>(N_("Geometry")); -} - static bool use_translate(const float3 rotation, const float3 scale) { if (compare_ff(rotation.length_squared(), 0.0f, 1e-9f) != 1) { @@ -69,15 +60,6 @@ static void transform_mesh(Mesh &mesh, const float4x4 &transform) BKE_mesh_normals_tag_dirty(&mesh); } -void transform_mesh(Mesh &mesh, - const float3 translation, - const float3 rotation, - const float3 scale) -{ - const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); - transform_mesh(mesh, matrix); -} - static void translate_pointcloud(PointCloud &pointcloud, const float3 translation) { CustomData_duplicate_referenced_layer(&pointcloud.pdata, CD_PROP_FLOAT3, pointcloud.totpoint); @@ -153,49 +135,71 @@ static void translate_volume(Volume &volume, const float3 translation, const Dep transform_volume(volume, float4x4::from_location(translation), depsgraph); } -void transform_geometry_set(GeometrySet &geometry, - const float4x4 &transform, - const Depsgraph &depsgraph) +static void translate_geometry_set(GeometrySet &geometry, + const float3 translation, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->transform(transform); + curve->translate(translation); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - transform_mesh(*mesh, transform); + translate_mesh(*mesh, translation); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - transform_pointcloud(*pointcloud, transform); + translate_pointcloud(*pointcloud, translation); } if (Volume *volume = geometry.get_volume_for_write()) { - transform_volume(*volume, transform, depsgraph); + translate_volume(*volume, translation, depsgraph); } if (geometry.has_instances()) { - transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); + translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); } } -static void translate_geometry_set(GeometrySet &geometry, - const float3 translation, - const Depsgraph &depsgraph) +void transform_geometry_set(GeometrySet &geometry, + const float4x4 &transform, + const Depsgraph &depsgraph) { if (CurveEval *curve = geometry.get_curve_for_write()) { - curve->translate(translation); + curve->transform(transform); } if (Mesh *mesh = geometry.get_mesh_for_write()) { - translate_mesh(*mesh, translation); + transform_mesh(*mesh, transform); } if (PointCloud *pointcloud = geometry.get_pointcloud_for_write()) { - translate_pointcloud(*pointcloud, translation); + transform_pointcloud(*pointcloud, transform); } if (Volume *volume = geometry.get_volume_for_write()) { - translate_volume(*volume, translation, depsgraph); + transform_volume(*volume, transform, depsgraph); } if (geometry.has_instances()) { - translate_instances(geometry.get_component_for_write<InstancesComponent>(), translation); + transform_instances(geometry.get_component_for_write<InstancesComponent>(), transform); } } -static void geo_node_transform_exec(GeoNodeExecParams params) +void transform_mesh(Mesh &mesh, + const float3 translation, + const float3 rotation, + const float3 scale) +{ + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + transform_mesh(mesh, matrix); +} + +} // namespace blender::nodes + +namespace blender::nodes::node_geo_transform_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Geometry>(N_("Geometry")); + b.add_input<decl::Vector>(N_("Translation")).subtype(PROP_TRANSLATION); + b.add_input<decl::Vector>(N_("Rotation")).subtype(PROP_EULER); + b.add_input<decl::Vector>(N_("Scale")).default_value({1, 1, 1}).subtype(PROP_XYZ); + b.add_output<decl::Geometry>(N_("Geometry")); +} + +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); const float3 translation = params.extract_input<float3>("Translation"); @@ -214,14 +218,16 @@ static void geo_node_transform_exec(GeoNodeExecParams params) params.set_output("Geometry", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_transform_cc void register_node_type_geo_transform() { + namespace file_ns = blender::nodes::node_geo_transform_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRANSFORM, "Transform", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_transform_declare; - ntype.geometry_node_execute = blender::nodes::geo_node_transform_exec; + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc index fa05d858a07..8ef80323f99 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_translate_instances.cc @@ -18,9 +18,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { +namespace blender::nodes::node_geo_translate_instances_cc { -static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Instances")).only_instances(); b.add_input<decl::Bool>(N_("Selection")).default_value(true).hide_value().supports_field(); @@ -31,7 +31,7 @@ static void geo_node_translate_instances_declare(NodeDeclarationBuilder &b) static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &instances_component) { - GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_POINT}; + GeometryComponentFieldContext field_context{instances_component, ATTR_DOMAIN_INSTANCE}; fn::FieldEvaluator selection_evaluator{field_context, instances_component.instances_amount()}; selection_evaluator.add(params.extract_input<Field<bool>>("Selection")); @@ -60,7 +60,7 @@ static void translate_instances(GeoNodeExecParams ¶ms, InstancesComponent &i }); } -static void geo_node_translate_instances_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Instances"); if (geometry_set.has_instances()) { @@ -70,15 +70,17 @@ static void geo_node_translate_instances_exec(GeoNodeExecParams params) params.set_output("Instances", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_translate_instances_cc void register_node_type_geo_translate_instances() { + namespace file_ns = blender::nodes::node_geo_translate_instances_cc; + static bNodeType ntype; geo_node_type_base( &ntype, GEO_NODE_TRANSLATE_INSTANCES, "Translate Instances", NODE_CLASS_GEOMETRY, 0); - ntype.geometry_node_execute = blender::nodes::geo_node_translate_instances_exec; - ntype.declare = blender::nodes::geo_node_translate_instances_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.declare = file_ns::node_declare; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc index c869846e1f8..f8deaaa4a14 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc @@ -27,16 +27,16 @@ Mesh *triangulate_mesh(Mesh *mesh, const int flag); } -namespace blender::nodes { +namespace blender::nodes::node_geo_triangulate_cc { -static void geo_node_triangulate_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Mesh")).supported_type(GEO_COMPONENT_TYPE_MESH); b.add_input<decl::Int>(N_("Minimum Vertices")).default_value(4).min(4).max(10000); b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_triangulate_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "quad_method", 0, "", ICON_NONE); uiItemR(layout, ptr, "ngon_method", 0, "", ICON_NONE); @@ -48,7 +48,7 @@ static void geo_triangulate_init(bNodeTree *UNUSED(ntree), bNode *node) node->custom2 = GEO_NODE_TRIANGULATE_NGON_BEAUTY; } -static void geo_node_triangulate_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh"); const int min_vertices = std::max(params.extract_input<int>("Minimum Vertices"), 4); @@ -69,16 +69,18 @@ static void geo_node_triangulate_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_triangulate_cc void register_node_type_geo_triangulate() { + namespace file_ns = blender::nodes::node_geo_triangulate_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_triangulate_declare; - node_type_init(&ntype, blender::nodes::geo_triangulate_init); - ntype.geometry_node_execute = blender::nodes::geo_node_triangulate_exec; - ntype.draw_buttons = blender::nodes::geo_node_triangulate_layout; + ntype.declare = file_ns::node_declare; + node_type_init(&ntype, file_ns::geo_triangulate_init); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc index 194d1a751ed..accbcc74174 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc @@ -19,8 +19,9 @@ #include "node_geometry_util.hh" -namespace blender::nodes { -static void geo_node_viewer_declare(NodeDeclarationBuilder &b) +namespace blender::nodes::node_geo_viewer_cc { + +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Geometry")); b.add_input<decl::Float>(N_("Value")).supports_field().hide_value(); @@ -30,7 +31,7 @@ static void geo_node_viewer_declare(NodeDeclarationBuilder &b) b.add_input<decl::Bool>(N_("Value"), "Value_004").supports_field().hide_value(); } -static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) +static void node_init(bNodeTree *UNUSED(tree), bNode *node) { NodeGeometryViewer *data = (NodeGeometryViewer *)MEM_callocN(sizeof(NodeGeometryViewer), __func__); @@ -39,7 +40,7 @@ static void geo_node_viewer_init(bNodeTree *UNUSED(tree), bNode *node) node->storage = data; } -static void geo_node_viewer_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); } @@ -63,7 +64,7 @@ static eNodeSocketDatatype custom_data_type_to_socket_type(const CustomDataType } } -static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { const NodeGeometryViewer &storage = *(const NodeGeometryViewer *)node->storage; const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); @@ -73,22 +74,24 @@ static void geo_node_viewer_update(bNodeTree *UNUSED(ntree), bNode *node) if (socket->type == SOCK_GEOMETRY) { continue; } - nodeSetSocketAvailability(socket, socket->type == socket_type); + nodeSetSocketAvailability(ntree, socket, socket->type == socket_type); } } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_viewer_cc void register_node_type_geo_viewer() { + namespace file_ns = blender::nodes::node_geo_viewer_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0); node_type_storage( &ntype, "NodeGeometryViewer", node_free_standard_storage, node_copy_standard_storage); - node_type_update(&ntype, blender::nodes::geo_node_viewer_update); - node_type_init(&ntype, blender::nodes::geo_node_viewer_init); - ntype.declare = blender::nodes::geo_node_viewer_declare; - ntype.draw_buttons_ex = blender::nodes::geo_node_viewer_layout; + node_type_update(&ntype, file_ns::node_update); + node_type_init(&ntype, file_ns::node_init); + ntype.declare = file_ns::node_declare; + ntype.draw_buttons_ex = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc index 416d502dc59..12a7435d8be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc @@ -35,9 +35,9 @@ #include "UI_interface.h" #include "UI_resources.h" -namespace blender::nodes { +namespace blender::nodes::node_geo_volume_to_mesh_cc { -static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) +static void node_declare(NodeDeclarationBuilder &b) { b.add_input<decl::Geometry>(N_("Volume")).supported_type(GEO_COMPONENT_TYPE_VOLUME); b.add_input<decl::Float>(N_("Voxel Size")).default_value(0.3f).min(0.01f).subtype(PROP_DISTANCE); @@ -47,14 +47,14 @@ static void geo_node_volume_to_mesh_declare(NodeDeclarationBuilder &b) b.add_output<decl::Geometry>(N_("Mesh")); } -static void geo_node_volume_to_mesh_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiLayoutSetPropSep(layout, true); uiLayoutSetPropDecorate(layout, false); uiItemR(layout, ptr, "resolution_mode", 0, IFACE_("Resolution"), ICON_NONE); } -static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) +static void node_init(bNodeTree *UNUSED(ntree), bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)MEM_callocN( sizeof(NodeGeometryVolumeToMesh), __func__); @@ -62,15 +62,17 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) node->storage = data; } -static void geo_node_volume_to_mesh_update(bNodeTree *UNUSED(ntree), bNode *node) +static void node_update(bNodeTree *ntree, bNode *node) { NodeGeometryVolumeToMesh *data = (NodeGeometryVolumeToMesh *)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, + nodeSetSocketAvailability(ntree, + voxel_amount_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_AMOUNT); - nodeSetSocketAvailability(voxel_size_socket, + nodeSetSocketAvailability(ntree, + voxel_size_socket, data->resolution_mode == VOLUME_TO_MESH_RESOLUTION_MODE_VOXEL_SIZE); } @@ -174,7 +176,7 @@ static Mesh *create_mesh_from_volume(GeometrySet &geometry_set, GeoNodeExecParam #endif /* WITH_OPENVDB */ -static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) +static void node_geo_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume"); @@ -192,20 +194,22 @@ static void geo_node_volume_to_mesh_exec(GeoNodeExecParams params) params.set_output("Mesh", std::move(geometry_set)); } -} // namespace blender::nodes +} // namespace blender::nodes::node_geo_volume_to_mesh_cc void register_node_type_geo_volume_to_mesh() { + namespace file_ns = blender::nodes::node_geo_volume_to_mesh_cc; + static bNodeType ntype; geo_node_type_base(&ntype, GEO_NODE_VOLUME_TO_MESH, "Volume to Mesh", NODE_CLASS_GEOMETRY, 0); - ntype.declare = blender::nodes::geo_node_volume_to_mesh_declare; + ntype.declare = file_ns::node_declare; node_type_storage( &ntype, "NodeGeometryVolumeToMesh", node_free_standard_storage, node_copy_standard_storage); node_type_size(&ntype, 170, 120, 700); - node_type_init(&ntype, blender::nodes::geo_node_volume_to_mesh_init); - node_type_update(&ntype, blender::nodes::geo_node_volume_to_mesh_update); - ntype.geometry_node_execute = blender::nodes::geo_node_volume_to_mesh_exec; - ntype.draw_buttons = blender::nodes::geo_node_volume_to_mesh_layout; + node_type_init(&ntype, file_ns::node_init); + node_type_update(&ntype, file_ns::node_update); + ntype.geometry_node_execute = file_ns::node_geo_exec; + ntype.draw_buttons = file_ns::node_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc index ddd3c991518..4cba9669647 100644 --- a/source/blender/nodes/intern/geometry_nodes_eval_log.cc +++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc @@ -25,12 +25,15 @@ #include "BLT_translation.h" +#include <chrono> + namespace blender::nodes::geometry_nodes_eval_log { using fn::CPPType; using fn::FieldCPPType; using fn::FieldInput; using fn::GField; +using fn::ValueOrFieldCPPType; ModifierLog::ModifierLog(GeoLogger &logger) : input_geometry_log_(std::move(logger.input_geometry_log_)), @@ -63,6 +66,12 @@ ModifierLog::ModifierLog(GeoLogger &logger) node_with_warning.node); node_log.warnings_.append(node_with_warning.warning); } + + for (NodeWithExecutionTime &node_with_exec_time : local_logger.node_exec_times_) { + NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, + node_with_exec_time.node); + node_log.exec_time_ = node_with_exec_time.exec_time; + } } } @@ -417,25 +426,38 @@ void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value geometry_set, log_full_geometry); values_.append({copied_sockets, std::move(value_log)}); } - else if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) { - GField field = field_type->get_gfield(value.get()); - bool log_full_field = false; - if (!field.node().depends_on_input()) { - /* Always log constant fields so that their value can be shown in socket inspection. - * In the future we can also evaluate the field here and only store the value. */ - log_full_field = true; - } - if (!log_full_field) { - for (const DSocket &socket : sockets) { - if (main_logger_->log_full_sockets_.contains(socket)) { - log_full_field = true; - break; + else if (const ValueOrFieldCPPType *value_or_field_type = + dynamic_cast<const ValueOrFieldCPPType *>(&type)) { + const void *value_or_field = value.get(); + if (value_or_field_type->is_field(value_or_field)) { + GField field = *value_or_field_type->get_field_ptr(value_or_field); + bool log_full_field = false; + if (!field.node().depends_on_input()) { + /* Always log constant fields so that their value can be shown in socket inspection. + * In the future we can also evaluate the field here and only store the value. */ + log_full_field = true; + } + if (!log_full_field) { + for (const DSocket &socket : sockets) { + if (main_logger_->log_full_sockets_.contains(socket)) { + log_full_field = true; + break; + } } } + destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( + std::move(field), log_full_field); + values_.append({copied_sockets, std::move(value_log)}); + } + else { + const CPPType &base_type = value_or_field_type->base_type(); + const void *value = value_or_field_type->get_value_ptr(value_or_field); + void *buffer = allocator_->allocate(base_type.size(), base_type.alignment()); + base_type.copy_construct(value, buffer); + destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>( + GMutablePointer{base_type, buffer}); + values_.append({copied_sockets, std::move(value_log)}); } - destruct_ptr<GFieldValueLog> value_log = allocator_->construct<GFieldValueLog>( - std::move(field), log_full_field); - values_.append({copied_sockets, std::move(value_log)}); } else { void *buffer = allocator_->allocate(type.size(), type.alignment()); @@ -457,4 +479,9 @@ void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::str node_warnings_.append({node, {type, std::move(message)}}); } +void LocalGeoLogger::log_execution_time(DNode node, std::chrono::microseconds exec_time) +{ + node_exec_times_.append({node, exec_time}); +} + } // namespace blender::nodes::geometry_nodes_eval_log diff --git a/source/blender/nodes/intern/node_common.cc b/source/blender/nodes/intern/node_common.cc index e5ec50858d9..b80cedc9352 100644 --- a/source/blender/nodes/intern/node_common.cc +++ b/source/blender/nodes/intern/node_common.cc @@ -251,26 +251,6 @@ void register_node_type_frame(void) /** \name Node Re-Route * \{ */ -/* simple, only a single input and output here */ -static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node) -{ - bNodeLink *link; - - /* Security check! */ - if (!ntree) { - return; - } - - link = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "internal node link"); - link->fromnode = node; - link->fromsock = (bNodeSocket *)node->inputs.first; - link->tonode = node; - link->tosock = (bNodeSocket *)node->outputs.first; - /* internal link is always valid */ - link->flag |= NODE_LINK_VALID; - BLI_addtail(&node->internal_links, link); -} - static void node_reroute_init(bNodeTree *ntree, bNode *node) { /* NOTE: Cannot use socket templates for this, since it would reset the socket type @@ -288,7 +268,6 @@ void register_node_type_reroute(void) node_type_base(ntype, NODE_REROUTE, "Reroute", NODE_CLASS_LAYOUT, 0); node_type_init(ntype, node_reroute_init); - node_type_internal_links(ntype, node_reroute_update_internal_links); nodeRegisterType(ntype); } diff --git a/source/blender/nodes/intern/node_declaration.cc b/source/blender/nodes/intern/node_declaration.cc index 8a38b68ec59..e804d10ad75 100644 --- a/source/blender/nodes/intern/node_declaration.cc +++ b/source/blender/nodes/intern/node_declaration.cc @@ -20,16 +20,6 @@ namespace blender::nodes { -void NodeDeclaration::build(bNodeTree &ntree, bNode &node) const -{ - for (const SocketDeclarationPtr &decl : inputs_) { - decl->build(ntree, node, SOCK_IN); - } - for (const SocketDeclarationPtr &decl : outputs_) { - decl->build(ntree, node, SOCK_OUT); - } -} - bool NodeDeclaration::matches(const bNode &node) const { auto check_sockets = [&](ListBase sockets, Span<SocketDeclarationPtr> socket_decls) { diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index c7a3e795c33..f54ef25d4d6 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -39,8 +39,8 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin void GeoNodeExecParams::check_input_geometry_set(StringRef identifier, const GeometrySet &geometry_set) const { - const int input_index = provider_->dnode->input_by_identifier(identifier).index(); - const SocketDeclaration &decl = *provider_->dnode->declaration()->inputs()[input_index]; + const SocketDeclaration &decl = + *provider_->dnode->input_by_identifier(identifier).bsocket()->declaration; const decl::Geometry *geo_decl = dynamic_cast<const decl::Geometry *>(&decl); if (geo_decl == nullptr) { return; @@ -113,11 +113,11 @@ const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name return nullptr; } -GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, - const GeometryComponent &component, - const AttributeDomain domain, - const CustomDataType type, - const void *default_value) const +GVArray GeoNodeExecParams::get_input_attribute(const StringRef name, + const GeometryComponent &component, + const AttributeDomain domain, + const CustomDataType type, + const void *default_value) const { const bNodeSocket *found_socket = this->find_available_socket(name); BLI_assert(found_socket != nullptr); /* There should always be available socket for the name. */ @@ -129,13 +129,13 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, } if (found_socket == nullptr) { - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } if (found_socket->type == SOCK_STRING) { const std::string name = this->get_input<std::string>(found_socket->identifier); /* Try getting the attribute without the default value. */ - GVArrayPtr attribute = component.attribute_try_get_for_read(name, domain, type); + GVArray attribute = component.attribute_try_get_for_read(name, domain, type); if (attribute) { return attribute; } @@ -147,36 +147,36 @@ GVArrayPtr GeoNodeExecParams::get_input_attribute(const StringRef name, this->error_message_add(NodeWarningType::Error, TIP_("No attribute with name \"") + name + "\""); } - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } const DataTypeConversions &conversions = get_implicit_type_conversions(); if (found_socket->type == SOCK_FLOAT) { const float value = this->get_input<float>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_INT) { const int value = this->get_input<int>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<int>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_VECTOR) { const float3 value = this->get_input<float3>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized(CPPType::get<float3>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } if (found_socket->type == SOCK_RGBA) { const ColorGeometry4f value = this->get_input<ColorGeometry4f>(found_socket->identifier); BUFFER_FOR_CPP_TYPE_VALUE(*cpp_type, buffer); conversions.convert_to_uninitialized( CPPType::get<ColorGeometry4f>(), *cpp_type, &value, buffer); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, buffer); + return GVArray::ForSingle(*cpp_type, domain_size, buffer); } BLI_assert(false); - return std::make_unique<fn::GVArray_For_SingleValue>(*cpp_type, domain_size, default_value); + return GVArray::ForSingle(*cpp_type, domain_size, default_value); } CustomDataType GeoNodeExecParams::get_input_attribute_data_type( @@ -288,7 +288,7 @@ void GeoNodeExecParams::check_input_access(StringRef identifier, BLI_assert_unreachable(); } else if (requested_type != nullptr) { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (*requested_type != expected_type) { std::cout << "The requested type '" << requested_type->name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; @@ -328,7 +328,7 @@ void GeoNodeExecParams::check_output_access(StringRef identifier, const CPPType BLI_assert_unreachable(); } else { - const CPPType &expected_type = *found_socket->typeinfo->get_geometry_nodes_cpp_type(); + const CPPType &expected_type = *found_socket->typeinfo->geometry_nodes_cpp_type; if (value_type != expected_type) { std::cout << "The value type '" << value_type.name() << "' is incorrect. Expected '" << expected_type.name() << "'.\n"; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 11356178d87..68e8f6421bd 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -51,6 +51,7 @@ #include "FN_field.hh" using namespace blender; +using blender::fn::ValueOrField; using blender::nodes::SocketDeclarationPtr; struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, @@ -269,10 +270,11 @@ void node_verify_sockets(bNodeTree *ntree, bNode *node, bool do_id_user) return; } if (ntype->declare != nullptr) { - nodeDeclarationEnsure(ntree, node); + nodeDeclarationEnsureOnOutdatedNode(ntree, node); if (!node->declaration->matches(*node)) { refresh_node(*ntree, *node, *node->declaration, do_id_user); } + nodeSocketDeclarationsUpdate(node); return; } /* Don't try to match socket lists when there are no templates. @@ -696,17 +698,15 @@ static bNodeSocketType *make_socket_type_virtual() static bNodeSocketType *make_socket_type_bool() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<bool>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<bool>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<bool>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { bool value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<bool>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<bool>(value); }; return socktype; } @@ -714,17 +714,15 @@ static bNodeSocketType *make_socket_type_bool() static bNodeSocketType *make_socket_type_float(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<float>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<float>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<float>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<float>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { float value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<float>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<float>(value); }; return socktype; } @@ -732,17 +730,15 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype) static bNodeSocketType *make_socket_type_int(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<int>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<int>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<int>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<int>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { int value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<int>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<int>(value); }; return socktype; } @@ -750,17 +746,15 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype) static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) { bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::float3>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::float3>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<blender::float3>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::float3 value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<blender::float3>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::float3>(value); }; return socktype; } @@ -768,20 +762,16 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype) static bNodeSocketType *make_socket_type_rgba() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE); - socktype->get_base_cpp_type = []() { - return &blender::fn::CPPType::get<blender::ColorGeometry4f>(); - }; + socktype->base_cpp_type = &blender::fn::CPPType::get<blender::ColorGeometry4f>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(blender::ColorGeometry4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<blender::ColorGeometry4f>>(); - }; + socktype->geometry_nodes_cpp_type = + &blender::fn::CPPType::get<ValueOrField<blender::ColorGeometry4f>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { blender::ColorGeometry4f value; socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) - blender::fn::Field<blender::ColorGeometry4f>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<blender::ColorGeometry4f>(value); }; return socktype; } @@ -789,18 +779,16 @@ static bNodeSocketType *make_socket_type_rgba() static bNodeSocketType *make_socket_type_string() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<std::string>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value); }; - socktype->get_geometry_nodes_cpp_type = []() { - return &blender::fn::CPPType::get<blender::fn::Field<std::string>>(); - }; + socktype->geometry_nodes_cpp_type = &blender::fn::CPPType::get<ValueOrField<std::string>>(); socktype->get_geometry_nodes_cpp_value = [](const bNodeSocket &socket, void *r_value) { std::string value; value.~basic_string(); socket.typeinfo->get_base_cpp_value(socket, &value); - new (r_value) blender::fn::Field<std::string>(blender::fn::make_constant_field(value)); + new (r_value) ValueOrField<std::string>(value); }; return socktype; } @@ -814,11 +802,11 @@ MAKE_CPP_TYPE(Material, Material *, CPPTypeFlags::BasicType) static bNodeSocketType *make_socket_type_object() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Object *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Object *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Object **)r_value = ((bNodeSocketValueObject *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -826,11 +814,11 @@ static bNodeSocketType *make_socket_type_object() static bNodeSocketType *make_socket_type_geometry() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<GeometrySet>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<GeometrySet>(); socktype->get_base_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) { new (r_value) GeometrySet(); }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -838,11 +826,11 @@ static bNodeSocketType *make_socket_type_geometry() static bNodeSocketType *make_socket_type_collection() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_COLLECTION, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Collection *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Collection *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Collection **)r_value = ((bNodeSocketValueCollection *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -850,11 +838,11 @@ static bNodeSocketType *make_socket_type_collection() static bNodeSocketType *make_socket_type_texture() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_TEXTURE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Tex *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Tex *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Tex **)r_value = ((bNodeSocketValueTexture *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -862,11 +850,11 @@ static bNodeSocketType *make_socket_type_texture() static bNodeSocketType *make_socket_type_image() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_IMAGE, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Image *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Image *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Image **)r_value = ((bNodeSocketValueImage *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } @@ -874,11 +862,11 @@ static bNodeSocketType *make_socket_type_image() static bNodeSocketType *make_socket_type_material() { bNodeSocketType *socktype = make_standard_socket_type(SOCK_MATERIAL, PROP_NONE); - socktype->get_base_cpp_type = []() { return &blender::fn::CPPType::get<Material *>(); }; + socktype->base_cpp_type = &blender::fn::CPPType::get<Material *>(); socktype->get_base_cpp_value = [](const bNodeSocket &socket, void *r_value) { *(Material **)r_value = ((bNodeSocketValueMaterial *)socket.default_value)->value; }; - socktype->get_geometry_nodes_cpp_type = socktype->get_base_cpp_type; + socktype->geometry_nodes_cpp_type = socktype->base_cpp_type; socktype->get_geometry_nodes_cpp_value = socktype->get_base_cpp_value; return socktype; } diff --git a/source/blender/nodes/intern/node_util.c b/source/blender/nodes/intern/node_util.c index ba0cfeacb83..231030030eb 100644 --- a/source/blender/nodes/intern/node_util.c +++ b/source/blender/nodes/intern/node_util.c @@ -41,6 +41,8 @@ #include "MEM_guardedalloc.h" +#include "NOD_common.h" + #include "node_util.h" /* -------------------------------------------------------------------- */ @@ -97,12 +99,13 @@ void node_sock_label_clear(bNodeSocket *sock) } } -void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) +void node_math_update(bNodeTree *ntree, bNode *node) { bNodeSocket *sock1 = BLI_findlink(&node->inputs, 0); bNodeSocket *sock2 = BLI_findlink(&node->inputs, 1); bNodeSocket *sock3 = BLI_findlink(&node->inputs, 2); - nodeSetSocketAvailability(sock2, + nodeSetSocketAvailability(ntree, + sock2, !ELEM(node->custom1, NODE_MATH_SQRT, NODE_MATH_SIGN, @@ -126,7 +129,8 @@ void node_math_update(bNodeTree *UNUSED(ntree), bNode *node) NODE_MATH_COSH, NODE_MATH_SINH, NODE_MATH_TANH)); - nodeSetSocketAvailability(sock3, + nodeSetSocketAvailability(ntree, + sock3, ELEM(node->custom1, NODE_MATH_COMPARE, NODE_MATH_MULTIPLY_ADD, @@ -491,6 +495,10 @@ static int node_datatype_priority(eNodeSocketDatatype from, eNodeSocketDatatype /* select a suitable input socket for an output */ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) { + if (node->type == NODE_REROUTE) { + return node->inputs.first; + } + bNodeSocket *selected = NULL, *input; int i; int sel_priority = -1; @@ -524,7 +532,7 @@ static bNodeSocket *select_internal_link_input(bNode *node, bNodeSocket *output) return selected; } -void node_update_internal_links_default(bNodeTree *ntree, bNode *node) +void node_internal_links_create(bNodeTree *ntree, bNode *node) { bNodeLink *link; bNodeSocket *output, *input; diff --git a/source/blender/nodes/intern/node_util.h b/source/blender/nodes/intern/node_util.h index 9cbb21e02f7..c064ef4ab36 100644 --- a/source/blender/nodes/intern/node_util.h +++ b/source/blender/nodes/intern/node_util.h @@ -83,7 +83,6 @@ void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, /*** Link Handling */ void node_insert_link_default(struct bNodeTree *ntree, struct bNode *node, struct bNodeLink *link); -void node_update_internal_links_default(struct bNodeTree *ntree, struct bNode *node); float node_socket_get_float(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocket *sock); void node_socket_set_float(struct bNodeTree *ntree, diff --git a/source/blender/nodes/intern/type_conversions.cc b/source/blender/nodes/intern/type_conversions.cc index 1a71a3418a5..d4cd7dc6bfe 100644 --- a/source/blender/nodes/intern/type_conversions.cc +++ b/source/blender/nodes/intern/type_conversions.cc @@ -24,19 +24,16 @@ namespace blender::nodes { -using fn::GVArrayPtr; -using fn::GVMutableArray; -using fn::GVMutableArrayPtr; using fn::MFDataType; template<typename From, typename To, To (*ConversionF)(const From &)> static void add_implicit_conversion(DataTypeConversions &conversions) { - const CPPType &from_type = CPPType::get<From>(); - const CPPType &to_type = CPPType::get<To>(); - const std::string conversion_name = from_type.name() + " to " + to_type.name(); + static const CPPType &from_type = CPPType::get<From>(); + static const CPPType &to_type = CPPType::get<To>(); + static const std::string conversion_name = from_type.name() + " to " + to_type.name(); - static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name, ConversionF}; + static fn::CustomMF_SI_SO<From, To> multi_function{conversion_name.c_str(), ConversionF}; static auto convert_single_to_initialized = [](const void *src, void *dst) { *(To *)dst = ConversionF(*(const From *)src); }; @@ -242,107 +239,108 @@ void DataTypeConversions::convert_to_uninitialized(const CPPType &from_type, functions->convert_single_to_uninitialized(from_value, to_value); } -class GVArray_For_ConvertedGVArray : public GVArray { +class GVArray_For_ConvertedGVArray : public fn::GVArrayImpl { private: - GVArrayPtr varray_; + fn::GVArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; public: - GVArray_For_ConvertedGVArray(GVArrayPtr varray, + GVArray_For_ConvertedGVArray(fn::GVArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVArray(to_type, varray->size()), varray_(std::move(varray)), from_type_(varray_->type()) + : fn::GVArrayImpl(to_type, varray.size()), + varray_(std::move(varray)), + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } }; -class GVMutableArray_For_ConvertedGVMutableArray : public GVMutableArray { +class GVMutableArray_For_ConvertedGVMutableArray : public fn::GVMutableArrayImpl { private: - GVMutableArrayPtr varray_; + fn::GVMutableArray varray_; const CPPType &from_type_; ConversionFunctions old_to_new_conversions_; ConversionFunctions new_to_old_conversions_; public: - GVMutableArray_For_ConvertedGVMutableArray(GVMutableArrayPtr varray, + GVMutableArray_For_ConvertedGVMutableArray(fn::GVMutableArray varray, const CPPType &to_type, const DataTypeConversions &conversions) - : GVMutableArray(to_type, varray->size()), + : fn::GVMutableArrayImpl(to_type, varray.size()), varray_(std::move(varray)), - from_type_(varray_->type()) + from_type_(varray_.type()) { old_to_new_conversions_ = *conversions.get_conversion_functions(from_type_, to_type); new_to_old_conversions_ = *conversions.get_conversion_functions(to_type, from_type_); } private: - void get_impl(const int64_t index, void *r_value) const override + void get(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_initialized(buffer, r_value); from_type_.destruct(buffer); } - void get_to_uninitialized_impl(const int64_t index, void *r_value) const override + void get_to_uninitialized(const int64_t index, void *r_value) const override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); - varray_->get(index, buffer); + varray_.get(index, buffer); old_to_new_conversions_.convert_single_to_uninitialized(buffer, r_value); from_type_.destruct(buffer); } - void set_by_move_impl(const int64_t index, void *value) override + void set_by_move(const int64_t index, void *value) override { BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); new_to_old_conversions_.convert_single_to_uninitialized(value, buffer); - varray_->set_by_relocate(index, buffer); + varray_.set_by_relocate(index, buffer); } }; -fn::GVArrayPtr DataTypeConversions::try_convert(fn::GVArrayPtr varray, - const CPPType &to_type) const +fn::GVArray DataTypeConversions::try_convert(fn::GVArray varray, const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); + return fn::GVArray::For<GVArray_For_ConvertedGVArray>(std::move(varray), to_type, *this); } -fn::GVMutableArrayPtr DataTypeConversions::try_convert(fn::GVMutableArrayPtr varray, - const CPPType &to_type) const +fn::GVMutableArray DataTypeConversions::try_convert(fn::GVMutableArray varray, + const CPPType &to_type) const { - const CPPType &from_type = varray->type(); + const CPPType &from_type = varray.type(); if (from_type == to_type) { return varray; } if (!this->is_convertible(from_type, to_type)) { return {}; } - return std::make_unique<GVMutableArray_For_ConvertedGVMutableArray>( + return fn::GVMutableArray::For<GVMutableArray_For_ConvertedGVMutableArray>( std::move(varray), to_type, *this); } diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 97041b3fdfd..e1f6c135568 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -54,7 +54,6 @@ void sh_node_type_base( ntype->poll = sh_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } void sh_fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag) diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c index e29b2ee1c5c..d2b40a7ec39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_hair_principled.c @@ -59,59 +59,34 @@ static void node_shader_init_hair_principled(bNodeTree *UNUSED(ntree), bNode *no } /* Triggers (in)visibility of some sockets when changing Parametrization. */ -static void node_shader_update_hair_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_hair_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int parametrization = node->custom1; for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_REFLECTANCE); } else if (STREQ(sock->name, "Melanin")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Melanin Redness")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Tint")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } else if (STREQ(sock->name, "Absorption Coefficient")) { - if (parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_DIRECT_ABSORPTION); } else if (STREQ(sock->name, "Random Color")) { - if (parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability( + ntree, sock, parametrization == SHD_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c index cb4f0594310..89b7164693f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_bsdf_principled.c @@ -167,7 +167,7 @@ static int node_shader_gpu_bsdf_principled(GPUMaterial *mat, sss_scale); } -static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_principled(bNodeTree *ntree, bNode *node) { bNodeSocket *sock; int distribution = node->custom1; @@ -175,21 +175,11 @@ static void node_shader_update_principled(bNodeTree *UNUSED(ntree), bNode *node) for (sock = node->inputs.first; sock; sock = sock->next) { if (STREQ(sock->name, "Transmission Roughness")) { - if (distribution == SHD_GLOSSY_GGX) { - sock->flag &= ~SOCK_UNAVAIL; - } - else { - sock->flag |= SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, distribution == SHD_GLOSSY_GGX); } if (STR_ELEM(sock->name, "Subsurface IOR", "Subsurface Anisotropy")) { - if (sss_method == SHD_SUBSURFACE_BURLEY) { - sock->flag |= SOCK_UNAVAIL; - } - else { - sock->flag &= ~SOCK_UNAVAIL; - } + nodeSetSocketAvailability(ntree, sock, sss_method == SHD_SUBSURFACE_BURLEY); } } } diff --git a/source/blender/nodes/shader/nodes/node_shader_common.c b/source/blender/nodes/shader/nodes/node_shader_common.c index 4df5add7151..a1dac05434e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_common.c +++ b/source/blender/nodes/shader/nodes/node_shader_common.c @@ -237,7 +237,6 @@ void register_node_type_sh_group(void) ntype.poll = sh_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("ShaderNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); @@ -261,9 +260,6 @@ void register_node_type_sh_custom_group(bNodeType *ntype) if (ntype->insert_link == NULL) { ntype->insert_link = node_insert_link_default; } - if (ntype->update_internal_links == NULL) { - ntype->update_internal_links = node_update_internal_links_default; - } node_type_exec(ntype, group_initexec, group_freeexec, group_execute); node_type_gpu(ntype, gpu_group_execute); diff --git a/source/blender/nodes/shader/nodes/node_shader_map_range.cc b/source/blender/nodes/shader/nodes/node_shader_map_range.cc index c866a154e8c..e55963eb500 100644 --- a/source/blender/nodes/shader/nodes/node_shader_map_range.cc +++ b/source/blender/nodes/shader/nodes/node_shader_map_range.cc @@ -41,10 +41,10 @@ static void sh_node_map_range_declare(NodeDeclarationBuilder &b) } // namespace blender::nodes -static void node_shader_update_map_range(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_map_range(bNodeTree *ntree, bNode *node) { bNodeSocket *sockSteps = nodeFindSocket(node, SOCK_IN, "Steps"); - nodeSetSocketAvailability(sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); + nodeSetSocketAvailability(ntree, sockSteps, node->custom2 == NODE_MAP_RANGE_STEPPED); } static void node_shader_init_map_range(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_mapping.c b/source/blender/nodes/shader/nodes/node_shader_mapping.c index 774e7fed029..cabfecdb6ee 100644 --- a/source/blender/nodes/shader/nodes/node_shader_mapping.c +++ b/source/blender/nodes/shader/nodes/node_shader_mapping.c @@ -57,11 +57,11 @@ static int gpu_shader_mapping(GPUMaterial *mat, return 0; } -static void node_shader_update_mapping(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_mapping(bNodeTree *ntree, bNode *node) { bNodeSocket *sock = nodeFindSocket(node, SOCK_IN, "Location"); nodeSetSocketAvailability( - sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); + ntree, sock, ELEM(node->custom1, NODE_MAPPING_TYPE_POINT, NODE_MAPPING_TYPE_TEXTURE)); } void register_node_type_sh_mapping(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index 284a5f1189f..1e94148c5c7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -88,7 +88,8 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float, float> fn{info.title_case_name.c_str(), + function}; base_fn = &fn; }); if (base_fn != nullptr) { @@ -97,7 +98,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name, + static blender::fn::CustomMF_SI_SI_SO<float, float, float> fn{info.title_case_name.c_str(), function}; base_fn = &fn; }); @@ -108,7 +109,7 @@ static const blender::fn::MultiFunction *get_base_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl_fl_fl_to_fl( mode, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float, float, float, float> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; base_fn = &fn; }); if (base_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_output_aov.c b/source/blender/nodes/shader/nodes/node_shader_output_aov.c index 7e7e1b703f1..32765b459ca 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_aov.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_aov.c @@ -64,8 +64,7 @@ void register_node_type_sh_output_aov(void) &ntype, "NodeShaderOutputAOV", node_free_standard_storage, node_copy_standard_storage); node_type_gpu(&ntype, node_shader_gpu_output_aov); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_light.c b/source/blender/nodes/shader/nodes/node_shader_output_light.c index 722202bafdc..6c4837f3c6f 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_light.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_light.c @@ -36,8 +36,7 @@ void register_node_type_sh_output_light(void) node_type_init(&ntype, NULL); node_type_storage(&ntype, "", NULL, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c index 5b4ebf21f5f..07e253383e2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_linestyle.c @@ -38,8 +38,7 @@ void register_node_type_sh_output_linestyle(void) node_type_socket_templates(&ntype, sh_node_output_linestyle_in, NULL); node_type_init(&ntype, NULL); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_material.c b/source/blender/nodes/shader/nodes/node_shader_output_material.c index fb0b6e7b263..41932cca6a3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_material.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_material.c @@ -84,8 +84,7 @@ void register_node_type_sh_output_material(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_material); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_output_world.c b/source/blender/nodes/shader/nodes/node_shader_output_world.c index 59c77e0b25c..09eca7f712e 100644 --- a/source/blender/nodes/shader/nodes/node_shader_output_world.c +++ b/source/blender/nodes/shader/nodes/node_shader_output_world.c @@ -52,8 +52,7 @@ void register_node_type_sh_output_world(void) node_type_storage(&ntype, "", NULL, NULL); node_type_gpu(&ntype, node_shader_gpu_output_world); - /* Do not allow muting output node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc index 81f9cd735eb..e426d9cc49c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_musgrave.cc @@ -104,7 +104,7 @@ static int node_shader_gpu_tex_musgrave(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_musgrave(bNodeTree *ntree, bNode *node) { NodeTexMusgrave *tex = (NodeTexMusgrave *)node->storage; @@ -113,12 +113,14 @@ static void node_shader_update_tex_musgrave(bNodeTree *UNUSED(ntree), bNode *nod bNodeSocket *inOffsetSock = nodeFindSocket(node, SOCK_IN, "Offset"); bNodeSocket *inGainSock = nodeFindSocket(node, SOCK_IN, "Gain"); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inOffsetSock, + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, + inOffsetSock, tex->musgrave_type != SHD_MUSGRAVE_MULTIFRACTAL && tex->musgrave_type != SHD_MUSGRAVE_FBM); - nodeSetSocketAvailability(inGainSock, + nodeSetSocketAvailability(ntree, + inGainSock, tex->musgrave_type == SHD_MUSGRAVE_HYBRID_MULTIFRACTAL || tex->musgrave_type == SHD_MUSGRAVE_RIDGED_MULTIFRACTAL); @@ -199,28 +201,28 @@ class MusgraveFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_detail = [&](int param_index) -> const VArray<float> & { + auto get_detail = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Detail"); }; - auto get_dimension = [&](int param_index) -> const VArray<float> & { + auto get_dimension = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Dimension"); }; - auto get_lacunarity = [&](int param_index) -> const VArray<float> & { + auto get_lacunarity = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Lacunarity"); }; - auto get_offset = [&](int param_index) -> const VArray<float> & { + auto get_offset = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Offset"); }; - auto get_gain = [&](int param_index) -> const VArray<float> & { + auto get_gain = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Gain"); }; diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc index d28095edb96..7dd2695ecf7 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_noise.cc @@ -76,14 +76,14 @@ static int node_shader_gpu_tex_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); NodeTexNoise *tex = (NodeTexNoise *)node->storage; - nodeSetSocketAvailability(sockVector, tex->dimensions != 1); - nodeSetSocketAvailability(sockW, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, sockVector, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, sockW, tex->dimensions == 1 || tex->dimensions == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c index 5dc11c4df00..5c581528c14 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_sky.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_sky.c @@ -195,12 +195,12 @@ static int node_shader_gpu_tex_sky(GPUMaterial *mat, return GPU_stack_link(mat, node, "node_tex_sky_nishita", in, out); } -static void node_shader_update_sky(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_sky(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); NodeTexSky *tex = (NodeTexSky *)node->storage; - nodeSetSocketAvailability(sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); + nodeSetSocketAvailability(ntree, sockVector, !(tex->sky_model == 2 && tex->sun_disc == 1)); } /* node type definition */ diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc index 422268b98c3..1bc3741d27c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_voronoi.cc @@ -123,7 +123,7 @@ static int node_shader_gpu_tex_voronoi(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out, GPU_constant(&metric)); } -static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_voronoi(bNodeTree *ntree, bNode *node) { bNodeSocket *inVectorSock = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *inWSock = nodeFindSocket(node, SOCK_IN, "W"); @@ -138,27 +138,31 @@ static void node_shader_update_tex_voronoi(bNodeTree *UNUSED(ntree), bNode *node NodeTexVoronoi *tex = (NodeTexVoronoi *)node->storage; - nodeSetSocketAvailability(inWSock, tex->dimensions == 1 || tex->dimensions == 4); - nodeSetSocketAvailability(inVectorSock, tex->dimensions != 1); + nodeSetSocketAvailability(ntree, inWSock, tex->dimensions == 1 || tex->dimensions == 4); + nodeSetSocketAvailability(ntree, inVectorSock, tex->dimensions != 1); nodeSetSocketAvailability( + ntree, inExponentSock, tex->distance == SHD_VORONOI_MINKOWSKI && tex->dimensions != 1 && !ELEM(tex->feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS)); - nodeSetSocketAvailability(inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); + nodeSetSocketAvailability(ntree, inSmoothnessSock, tex->feature == SHD_VORONOI_SMOOTH_F1); - nodeSetSocketAvailability(outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outColorSock, + nodeSetSocketAvailability(ntree, outDistanceSock, tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, + outColorSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS); - nodeSetSocketAvailability(outPositionSock, + nodeSetSocketAvailability(ntree, + outPositionSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && tex->dimensions != 1); - nodeSetSocketAvailability(outWSock, + nodeSetSocketAvailability(ntree, + outWSock, tex->feature != SHD_VORONOI_DISTANCE_TO_EDGE && tex->feature != SHD_VORONOI_N_SPHERE_RADIUS && (ELEM(tex->dimensions, 1, 4))); - nodeSetSocketAvailability(outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); + nodeSetSocketAvailability(ntree, outRadiusSock, tex->feature == SHD_VORONOI_N_SPHERE_RADIUS); } namespace blender::nodes { @@ -220,22 +224,22 @@ class VoronoiMinowskiFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_exponent = [&](int param_index) -> const VArray<float> & { + auto get_exponent = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Exponent"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -651,19 +655,19 @@ class VoronoiMetricFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_smoothness = [&](int param_index) -> const VArray<float> & { + auto get_smoothness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Smoothness"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { @@ -1153,16 +1157,16 @@ class VoronoiEdgeFunction : public fn::MultiFunction { void call(IndexMask mask, fn::MFParams params, fn::MFContext UNUSED(context)) const override { - auto get_vector = [&](int param_index) -> const VArray<float3> & { + auto get_vector = [&](int param_index) -> VArray<float3> { return params.readonly_single_input<float3>(param_index, "Vector"); }; - auto get_w = [&](int param_index) -> const VArray<float> & { + auto get_w = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "W"); }; - auto get_scale = [&](int param_index) -> const VArray<float> & { + auto get_scale = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Scale"); }; - auto get_randomness = [&](int param_index) -> const VArray<float> & { + auto get_randomness = [&](int param_index) -> VArray<float> { return params.readonly_single_input<float>(param_index, "Randomness"); }; auto get_r_distance = [&](int param_index) -> MutableSpan<float> { diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc index 43ee9400551..7b4ff7fec5c 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc +++ b/source/blender/nodes/shader/nodes/node_shader_tex_white_noise.cc @@ -58,13 +58,13 @@ static int gpu_shader_tex_white_noise(GPUMaterial *mat, return GPU_stack_link(mat, node, name, in, out); } -static void node_shader_update_tex_white_noise(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_tex_white_noise(bNodeTree *ntree, bNode *node) { bNodeSocket *sockVector = nodeFindSocket(node, SOCK_IN, "Vector"); bNodeSocket *sockW = nodeFindSocket(node, SOCK_IN, "W"); - nodeSetSocketAvailability(sockVector, node->custom1 != 1); - nodeSetSocketAvailability(sockW, node->custom1 == 1 || node->custom1 == 4); + nodeSetSocketAvailability(ntree, sockVector, node->custom1 != 1); + nodeSetSocketAvailability(ntree, sockW, node->custom1 == 1 || node->custom1 == 4); } namespace blender::nodes { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index ca5aeea9a7d..9b1b2467230 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -119,7 +119,7 @@ static int gpu_shader_vector_math(GPUMaterial *mat, return 0; } -static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_math(bNodeTree *ntree, bNode *node) { bNodeSocket *sockB = (bNodeSocket *)BLI_findlink(&node->inputs, 1); bNodeSocket *sockC = (bNodeSocket *)BLI_findlink(&node->inputs, 2); @@ -128,7 +128,8 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector"); bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value"); - nodeSetSocketAvailability(sockB, + nodeSetSocketAvailability(ntree, + sockB, !ELEM(node->custom1, NODE_VECTOR_MATH_SINE, NODE_VECTOR_MATH_COSINE, @@ -140,19 +141,22 @@ static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node NODE_VECTOR_MATH_ABSOLUTE, NODE_VECTOR_MATH_FRACTION, NODE_VECTOR_MATH_NORMALIZE)); - nodeSetSocketAvailability(sockC, + nodeSetSocketAvailability(ntree, + sockC, ELEM(node->custom1, NODE_VECTOR_MATH_WRAP, NODE_VECTOR_MATH_FACEFORWARD, NODE_VECTOR_MATH_MULTIPLY_ADD)); - nodeSetSocketAvailability(sockScale, - ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); - nodeSetSocketAvailability(sockVector, + nodeSetSocketAvailability( + ntree, sockScale, ELEM(node->custom1, NODE_VECTOR_MATH_SCALE, NODE_VECTOR_MATH_REFRACT)); + nodeSetSocketAvailability(ntree, + sockVector, !ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, NODE_VECTOR_MATH_DOT_PRODUCT)); - nodeSetSocketAvailability(sockValue, + nodeSetSocketAvailability(ntree, + sockValue, ELEM(node->custom1, NODE_VECTOR_MATH_LENGTH, NODE_VECTOR_MATH_DISTANCE, @@ -197,8 +201,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -208,7 +212,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -218,7 +222,7 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - info.title_case_name, function}; + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -227,8 +231,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -237,8 +241,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, - function}; + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ + info.title_case_name.c_str(), function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -247,7 +251,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl3( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { @@ -256,7 +261,8 @@ static const blender::fn::MultiFunction *get_multi_function(bNode &node) blender::nodes::try_dispatch_float_math_fl3_to_fl( operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { - static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name.c_str(), + function}; multi_fn = &fn; }); if (multi_fn != nullptr) { diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc index 1ab643bc3fa..3c1f1ed8d39 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -193,14 +193,16 @@ static void sh_node_vector_rotate_build_multi_function( builder.set_matching_fn(fn); } -static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) +static void node_shader_update_vector_rotate(bNodeTree *ntree, bNode *node) { bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); - nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); - nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); + nodeSetSocketAvailability(ntree, sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); - nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + nodeSetSocketAvailability( + ntree, sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); } void register_node_type_sh_vector_rotate(void) diff --git a/source/blender/nodes/texture/node_texture_util.c b/source/blender/nodes/texture/node_texture_util.c index 570b10d6e89..c968d0bae56 100644 --- a/source/blender/nodes/texture/node_texture_util.c +++ b/source/blender/nodes/texture/node_texture_util.c @@ -57,7 +57,6 @@ void tex_node_type_base( ntype->poll = tex_node_poll_default; ntype->insert_link = node_insert_link_default; - ntype->update_internal_links = node_update_internal_links_default; } static void tex_call_delegate(TexDelegate *dg, float *out, TexParams *params, short thread) diff --git a/source/blender/nodes/texture/nodes/node_texture_common.c b/source/blender/nodes/texture/nodes/node_texture_common.c index 2de64779ea6..868c97e5850 100644 --- a/source/blender/nodes/texture/nodes/node_texture_common.c +++ b/source/blender/nodes/texture/nodes/node_texture_common.c @@ -166,7 +166,6 @@ void register_node_type_tex_group(void) ntype.poll = tex_node_poll_default; ntype.poll_instance = node_group_poll_instance; ntype.insert_link = node_insert_link_default; - ntype.update_internal_links = node_update_internal_links_default; ntype.rna_ext.srna = RNA_struct_find("TextureNodeGroup"); BLI_assert(ntype.rna_ext.srna != NULL); RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype); diff --git a/source/blender/nodes/texture/nodes/node_texture_output.c b/source/blender/nodes/texture/nodes/node_texture_output.c index b24781e032b..9145df0038b 100644 --- a/source/blender/nodes/texture/nodes/node_texture_output.c +++ b/source/blender/nodes/texture/nodes/node_texture_output.c @@ -172,8 +172,7 @@ void register_node_type_tex_output(void) node_type_storage(&ntype, "TexNodeOutput", node_free_standard_storage, copy); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting output. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/texture/nodes/node_texture_viewer.c b/source/blender/nodes/texture/nodes/node_texture_viewer.c index c96ff2062cb..18b11b86d6f 100644 --- a/source/blender/nodes/texture/nodes/node_texture_viewer.c +++ b/source/blender/nodes/texture/nodes/node_texture_viewer.c @@ -60,8 +60,7 @@ void register_node_type_tex_viewer(void) node_type_socket_templates(&ntype, inputs, outputs); node_type_exec(&ntype, NULL, NULL, exec); - /* Do not allow muting viewer node. */ - node_type_internal_links(&ntype, NULL); + ntype.no_muting = true; nodeRegisterType(&ntype); } diff --git a/source/blender/python/generic/blf_py_api.c b/source/blender/python/generic/blf_py_api.c index 9e725730d40..a49c943df94 100644 --- a/source/blender/python/generic/blf_py_api.c +++ b/source/blender/python/generic/blf_py_api.c @@ -70,14 +70,15 @@ PyDoc_STRVAR(py_blf_size_doc, "font use 0.\n" " :type fontid: int\n" " :arg size: Point size of the font.\n" - " :type size: int\n" + " :type size: float\n" " :arg dpi: dots per inch value to use for drawing.\n" " :type dpi: int\n"); static PyObject *py_blf_size(PyObject *UNUSED(self), PyObject *args) { - int fontid, size, dpi; + int fontid, dpi; + float size; - if (!PyArg_ParseTuple(args, "iii:blf.size", &fontid, &size, &dpi)) { + if (!PyArg_ParseTuple(args, "ifi:blf.size", &fontid, &size, &dpi)) { return NULL; } diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 7646109c1b0..3377b2c283e 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -22,9 +22,13 @@ * A script writer should never directly access this module. */ +/* Future-proof, See https://docs.python.org/3/c-api/arg.html#strings-and-buffers */ +#define PY_SSIZE_T_CLEAN + #include <Python.h> #include "BLI_string.h" +#include "BLI_string_utils.h" #include "BLI_utildefines.h" #include "BKE_appdir.h" @@ -149,6 +153,52 @@ static PyObject *bpy_blend_paths(PyObject *UNUSED(self), PyObject *args, PyObjec return list; } +PyDoc_STRVAR(bpy_flip_name_doc, + ".. function:: flip_name(name, strip_digits=False)\n" + "\n" + " Flip a name between left/right sides, useful for \n" + " mirroring bone names.\n" + "\n" + " :arg name: Bone name to flip.\n" + " :type name: string\n" + " :arg strip_digits: Whether to remove ``.###`` suffix.\n" + " :type strip_digits: bool\n" + " :return: The flipped name.\n" + " :rtype: string\n"); +static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *name_src = NULL; + Py_ssize_t name_src_len; + bool strip_digits = false; + + static const char *_keywords[] = {"", "strip_digits", NULL}; + static _PyArg_Parser _parser = { + "s#" /* `name` */ + "|$" /* Optional, keyword only arguments. */ + "O&" /* `strip_digits` */ + /* Name to show in the case of an error. */ + ":flip_name", + _keywords, + 0, + }; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &name_src, &name_src_len, PyC_ParseBool, &strip_digits)) { + return NULL; + } + + /* Worst case we gain one extra byte (besides null-terminator) by changing + "Left" to "Right", because only the first appearance of "Left" gets replaced. */ + const size_t size = name_src_len + 2; + char *name_dst = PyMem_MALLOC(size); + const size_t name_dst_len = BLI_string_flip_side_name(name_dst, name_src, strip_digits, size); + + PyObject *result = PyUnicode_FromStringAndSize(name_dst, name_dst_len); + + PyMem_FREE(name_dst); + + return result; +} + // PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { @@ -338,6 +388,12 @@ static PyMethodDef meth_bpy_blend_paths = { METH_VARARGS | METH_KEYWORDS, bpy_blend_paths_doc, }; +static PyMethodDef meth_bpy_flip_name = { + "flip_name", + (PyCFunction)bpy_flip_name, + METH_VARARGS | METH_KEYWORDS, + bpy_flip_name_doc, +}; static PyMethodDef meth_bpy_user_resource = { "user_resource", (PyCFunction)bpy_user_resource, @@ -472,6 +528,8 @@ void BPy_init_modules(struct bContext *C) PyModule_AddObject(mod, meth_bpy_unescape_identifier.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_unescape_identifier, NULL)); + PyModule_AddObject( + mod, meth_bpy_flip_name.ml_name, (PyObject *)PyCFunction_New(&meth_bpy_flip_name, NULL)); /* register funcs (bpy_rna.c) */ PyModule_AddObject(mod, diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index 5ae123f3254..ae42af7cd85 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -81,7 +81,7 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) const char *context_str = NULL; PyObject *ret; - int context = WM_OP_EXEC_DEFAULT; + wmOperatorCallContext context = WM_OP_EXEC_DEFAULT; /* XXX TODO: work out a better solution for passing on context, * could make a tuple from self and pack the name and Context into it. */ @@ -107,7 +107,9 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) } if (context_str) { - if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) { + int context_int = context; + + if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) { char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s.poll\" error, " @@ -117,6 +119,8 @@ static PyObject *pyop_poll(PyObject *UNUSED(self), PyObject *args) MEM_freeN(enum_str); return NULL; } + /* Copy back to the properly typed enum. */ + context = context_int; } if (ELEM(context_dict, NULL, Py_None)) { @@ -166,8 +170,7 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) PyObject *kw = NULL; /* optional args */ PyObject *context_dict = NULL; /* optional args */ - /* note that context is an int, python does the conversion in this case */ - int context = WM_OP_EXEC_DEFAULT; + wmOperatorCallContext context = WM_OP_EXEC_DEFAULT; int is_undo = false; /* XXX TODO: work out a better solution for passing on context, @@ -209,7 +212,9 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) } if (context_str) { - if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context) == 0) { + int context_int = context; + + if (RNA_enum_value_from_id(rna_enum_operator_context_items, context_str, &context_int) == 0) { char *enum_str = pyrna_enum_repr(rna_enum_operator_context_items); PyErr_Format(PyExc_TypeError, "Calling operator \"bpy.ops.%s\" error, " @@ -219,6 +224,8 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) MEM_freeN(enum_str); return NULL; } + /* Copy back to the properly typed enum. */ + context = context_int; } if (ELEM(context_dict, NULL, Py_None)) { diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index 6d384ed9358..13c7d2947cf 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -366,7 +366,7 @@ static PyObject *bpy_prop_deferred_call(BPy_PropDeferred *UNUSED(self), /** * Expose the function in case scripts need to introspect this information - * (not currently used by Blender it's self). + * (not currently used by Blender itself). */ static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UNUSED(closure)) { @@ -377,7 +377,7 @@ static PyObject *bpy_prop_deferred_function_get(BPy_PropDeferred *self, void *UN /** * Expose keywords in case scripts need to introspect this information - * (not currently used by Blender it's self). + * (not currently used by Blender itself). */ static PyObject *bpy_prop_deferred_keywords_get(BPy_PropDeferred *self, void *UNUSED(closure)) { diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index 7b1877f3191..707de1c2581 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -7693,7 +7693,7 @@ PyObject *BPY_rna_doc(void) /** * This could be a static variable as we only have one `bpy.types` module, - * it just keeps the data isolated to store in the module it's self. + * it just keeps the data isolated to store in the module itself. * * This data doesn't change one initialized. */ diff --git a/source/blender/sequencer/SEQ_edit.h b/source/blender/sequencer/SEQ_edit.h index fbbf4bc53ea..f3a64c9cd62 100644 --- a/source/blender/sequencer/SEQ_edit.h +++ b/source/blender/sequencer/SEQ_edit.h @@ -33,10 +33,15 @@ struct Scene; struct Sequence; int SEQ_edit_sequence_swap(struct Sequence *seq_a, struct Sequence *seq_b, const char **error_str); +bool SEQ_edit_move_strip_to_seqbase(struct Scene *scene, + ListBase *seqbase, + struct Sequence *src_seq, + ListBase *dst_seqbase); bool SEQ_edit_move_strip_to_meta(struct Scene *scene, struct Sequence *src_seq, struct Sequence *dst_seqm, const char **error_str); +bool SEQ_meta_separate(struct Scene *scene, struct Sequence *src_meta, const char **error_str); void SEQ_edit_flag_for_removal(struct Scene *scene, struct ListBase *seqbase, struct Sequence *seq); diff --git a/source/blender/sequencer/intern/effects.c b/source/blender/sequencer/intern/effects.c index b9ee23a9186..6a6889c3679 100644 --- a/source/blender/sequencer/intern/effects.c +++ b/source/blender/sequencer/intern/effects.c @@ -2942,6 +2942,9 @@ static ImBuf *do_solid_color(const SeqRenderData *context, } } } + + out->planes = R_IMF_PLANES_RGB; + return out; } @@ -3741,7 +3744,7 @@ static void init_text_effect(Sequence *seq) data = seq->effectdata = MEM_callocN(sizeof(TextVars), "textvars"); data->text_font = NULL; data->text_blf_id = -1; - data->text_size = 60; + data->text_size = 60.0f; copy_v4_fl(data->color, 1.0f); data->shadow_color[3] = 0.7f; @@ -3842,7 +3845,7 @@ static int num_inputs_text(void) static int early_out_text(Sequence *seq, float UNUSED(facf0), float UNUSED(facf1)) { TextVars *data = seq->effectdata; - if (data->text[0] == 0 || data->text_size < 1 || + if (data->text[0] == 0 || data->text_size < 1.0f || ((data->color[3] == 0.0f) && (data->shadow_color[3] == 0.0f || (data->flag & SEQ_TEXT_SHADOW) == 0))) { return EARLY_USE_INPUT_1; @@ -4024,6 +4027,14 @@ static int early_out_mul_input2(Sequence *UNUSED(seq), float facf0, float facf1) return EARLY_DO_EFFECT; } +static int early_out_mul_input1(Sequence *UNUSED(seq), float facf0, float facf1) +{ + if (facf0 == 0.0f && facf1 == 0.0f) { + return EARLY_USE_INPUT_2; + } + return EARLY_DO_EFFECT; +} + static void get_default_fac_noop(Sequence *UNUSED(seq), float UNUSED(timeline_frame), float *facf0, @@ -4134,6 +4145,7 @@ static struct SeqEffectHandle get_sequence_effect_impl(int seq_type) rval.multithreaded = true; rval.init = init_alpha_over_or_under; rval.execute_slice = do_alphaover_effect; + rval.early_out = early_out_mul_input1; break; case SEQ_TYPE_OVERDROP: rval.multithreaded = true; diff --git a/source/blender/sequencer/intern/render.c b/source/blender/sequencer/intern/render.c index 8ce3398024d..6030b49537c 100644 --- a/source/blender/sequencer/intern/render.c +++ b/source/blender/sequencer/intern/render.c @@ -466,6 +466,45 @@ static void sequencer_thumbnail_transform(ImBuf *in, ImBuf *out) IMB_transform(in, out, transform_matrix, &source_crop, IMB_FILTER_NEAREST); } +/* Check whether transform introduces transparent ares in the result (happens when the transformed + * image does not fully cover the render frame). + * + * The check is done by checking whether all corners of viewport fit inside of the transformed + * image. If they do not the image will have transparent areas. */ +static bool seq_image_transform_transparency_gained(const SeqRenderData *context, Sequence *seq) +{ + Scene *scene = context->scene; + const int x = context->rectx; + const int y = context->recty; + + float seq_image_quad[4][2]; + SEQ_image_transform_final_quad_get(scene, seq, seq_image_quad); + for (int i = 0; i < 4; i++) { + add_v2_v2(seq_image_quad[i], (float[]){x / 2, y / 2}); + } + + return !isect_point_quad_v2((float[]){x, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, y}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){x, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]) || + !isect_point_quad_v2((float[]){0, 0}, + seq_image_quad[0], + seq_image_quad[1], + seq_image_quad[2], + seq_image_quad[3]); +} + static void sequencer_preprocess_transform_crop( ImBuf *in, ImBuf *out, const SeqRenderData *context, Sequence *seq, const bool is_proxy_image) { @@ -490,6 +529,13 @@ static void sequencer_preprocess_transform_crop( const eIMBInterpolationFilterMode filter = context->for_render ? IMB_FILTER_BILINEAR : IMB_FILTER_NEAREST; IMB_transform(in, out, transform_matrix, &source_crop, filter); + + if (!seq_image_transform_transparency_gained(context, seq)) { + out->planes = in->planes; + } + else { + out->planes = R_IMF_PLANES_RGBA; + } } static void multibuf(ImBuf *ibuf, const float fmul) @@ -525,6 +571,10 @@ static void multibuf(ImBuf *ibuf, const float fmul) rt_float += 4; } } + + if (ELEM(ibuf->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB) && fmul < 1.0f) { + ibuf->planes = R_IMF_PLANES_RGBA; + } } static ImBuf *input_preprocess(const SeqRenderData *context, @@ -1804,6 +1854,20 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, early_out = seq_get_early_out_for_blend_mode(seq); + /* Early out for alpha over. It requires image to be rendered, so it can't use + * `seq_get_early_out_for_blend_mode`. */ + if (out == NULL && seq->blend_mode == SEQ_TYPE_ALPHAOVER && seq->blend_opacity == 100.0f) { + ImBuf *test = seq_render_strip(context, state, seq, timeline_frame); + if (ELEM(test->planes, R_IMF_PLANES_BW, R_IMF_PLANES_RGB)) { + early_out = EARLY_USE_INPUT_2; + } + else { + early_out = EARLY_DO_EFFECT; + } + /* Free the image. It is stored in cache, so this doesn't affect performance. */ + IMB_freeImBuf(test); + } + switch (early_out) { case EARLY_NO_INPUT: case EARLY_USE_INPUT_2: @@ -1828,6 +1892,7 @@ static ImBuf *seq_render_strip_stack(const SeqRenderData *context, } break; } + if (out) { break; } diff --git a/source/blender/sequencer/intern/strip_add.c b/source/blender/sequencer/intern/strip_add.c index 70ac2620e20..382fdd4953f 100644 --- a/source/blender/sequencer/intern/strip_add.c +++ b/source/blender/sequencer/intern/strip_add.c @@ -159,7 +159,7 @@ Sequence *SEQ_add_scene_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDat { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_SCENE); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->scene = load_data->scene; seq->len = load_data->scene->r.efra - load_data->scene->r.sfra + 1; id_us_ensure_real((ID *)load_data->scene); @@ -180,7 +180,7 @@ Sequence *SEQ_add_movieclip_strip(Scene *scene, ListBase *seqbase, struct SeqLoa { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MOVIECLIP); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->clip = load_data->clip; seq->len = BKE_movieclip_get_duration(load_data->clip); id_us_ensure_real((ID *)load_data->clip); @@ -201,7 +201,7 @@ Sequence *SEQ_add_mask_strip(Scene *scene, ListBase *seqbase, struct SeqLoadData { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_MASK); - seq->blend_mode = SEQ_TYPE_CROSS; + seq->blend_mode = SEQ_TYPE_ALPHAOVER; seq->mask = load_data->mask; seq->len = BKE_mask_get_duration(load_data->mask); id_us_ensure_real((ID *)load_data->mask); @@ -230,18 +230,12 @@ Sequence *SEQ_add_effect_strip(Scene *scene, ListBase *seqbase, struct SeqLoadDa seq->seq2 = load_data->effect.seq2; seq->seq3 = load_data->effect.seq3; - if (seq->type == SEQ_TYPE_COLOR) { - seq->blend_mode = SEQ_TYPE_CROSS; - } - else if (seq->type == SEQ_TYPE_ADJUSTMENT) { - seq->blend_mode = SEQ_TYPE_CROSS; + if (SEQ_effect_get_num_inputs(seq->type) == 1) { + seq->blend_mode = seq->seq1->blend_mode; } - else if (seq->type == SEQ_TYPE_TEXT) { + else { seq->blend_mode = SEQ_TYPE_ALPHAOVER; } - else if (SEQ_effect_get_num_inputs(seq->type) == 1) { - seq->blend_mode = seq->seq1->blend_mode; - } if (!load_data->effect.seq1) { seq->len = 1; /* Effect is generator, set non zero length. */ @@ -326,7 +320,7 @@ Sequence *SEQ_add_image_strip(Main *bmain, Scene *scene, ListBase *seqbase, SeqL { Sequence *seq = SEQ_sequence_alloc( seqbase, load_data->start_frame, load_data->channel, SEQ_TYPE_IMAGE); - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ seq->len = load_data->image.len; Strip *strip = seq->strip; strip->stripdata = MEM_callocN(load_data->image.len * sizeof(StripElem), "stripelem"); @@ -587,7 +581,7 @@ Sequence *SEQ_add_movie_strip( } } - seq->blend_mode = SEQ_TYPE_CROSS; /* so alpha adjustment fade to the strip below */ + seq->blend_mode = SEQ_TYPE_ALPHAOVER; /* so alpha adjustment fade to the strip below */ if (anim_arr[0] != NULL) { seq->len = IMB_anim_get_duration(anim_arr[0], IMB_TC_RECORD_RUN); diff --git a/source/blender/sequencer/intern/strip_edit.c b/source/blender/sequencer/intern/strip_edit.c index 747f0eb3deb..00b3da86306 100644 --- a/source/blender/sequencer/intern/strip_edit.c +++ b/source/blender/sequencer/intern/strip_edit.c @@ -221,6 +221,40 @@ static bool seq_exists_in_seqbase(Sequence *seq, ListBase *seqbase) return false; } +/** + * Move sequence to seqbase. + * + * \param scene: Scene containing the editing + * \param dst_seqbase: seqbase where `seq` is located + * \param seq: Sequence to move + * \param dst_seqbase: Target seqbase + */ +bool SEQ_edit_move_strip_to_seqbase(Scene *scene, + ListBase *seqbase, + Sequence *seq, + ListBase *dst_seqbase) +{ + /* Move to meta. */ + BLI_remlink(seqbase, seq); + BLI_addtail(dst_seqbase, seq); + SEQ_relations_invalidate_cache_preprocessed(scene, seq); + + /* Update meta. */ + if (SEQ_transform_test_overlap(dst_seqbase, seq)) { + SEQ_transform_seqbase_shuffle(dst_seqbase, seq, scene); + } + + return true; +} + +/** + * Move sequence to meta sequence. + * + * \param scene: Scene containing the editing + * \param src_seq: Sequence to move + * \param dst_seqm: Target Meta sequence + * \param error_str: Error message + */ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *src_seq, Sequence *dst_seqm, @@ -262,17 +296,7 @@ bool SEQ_edit_move_strip_to_meta(Scene *scene, Sequence *seq; SEQ_ITERATOR_FOREACH (seq, collection) { /* Move to meta. */ - BLI_remlink(seqbase, seq); - BLI_addtail(&dst_seqm->seqbase, seq); - SEQ_relations_invalidate_cache_preprocessed(scene, seq); - - /* Update meta. */ - ListBase *meta_seqbase = SEQ_get_seqbase_by_seq(&ed->seqbase, dst_seqm); - SEQ_time_update_meta_strip_range(scene, dst_seqm); - SEQ_time_update_sequence(scene, meta_seqbase, dst_seqm); - if (SEQ_transform_test_overlap(&dst_seqm->seqbase, seq)) { - SEQ_transform_seqbase_shuffle(&dst_seqm->seqbase, seq, scene); - } + SEQ_edit_move_strip_to_seqbase(scene, seqbase, seq, &dst_seqm->seqbase); } SEQ_collection_free(collection); diff --git a/source/blender/sequencer/intern/strip_transform.c b/source/blender/sequencer/intern/strip_transform.c index becf44a7a8e..63ab4a30edc 100644 --- a/source/blender/sequencer/intern/strip_transform.c +++ b/source/blender/sequencer/intern/strip_transform.c @@ -520,10 +520,11 @@ static void seq_image_transform_quad_get_ex(const Scene *scene, } /** - * Get 4 corner points of strip image, optionally without rotation component applied + * Get 4 corner points of strip image, optionally without rotation component applied. + * Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param apply_rotation: Apply sequence rotation transform to the quad * \param r_quad: array of 4 2D vectors */ @@ -536,10 +537,10 @@ void SEQ_image_transform_quad_get(const Scene *scene, } /** - * Get 4 corner points of strip image. + * Get 4 corner points of strip image. Corner vectors are in viewport space. * * \param scene: Scene in which strips are located - * \param seq: Sequence to calculate image transform origin + * \param seq: Sequence to calculate transformed image quad * \param r_quad: array of 4 2D vectors */ void SEQ_image_transform_final_quad_get(const Scene *scene, diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index ef81addbb4d..c41c328c006 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -413,7 +413,7 @@ int WM_generic_select_invoke(struct bContext *C, const struct wmEvent *event); void WM_operator_view3d_unit_defaults(struct bContext *C, struct wmOperator *op); int WM_operator_smooth_viewtx_get(const struct wmOperator *op); -int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, int opcontext); +int WM_menu_invoke_ex(struct bContext *C, struct wmOperator *op, wmOperatorCallContext opcontext); int WM_menu_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event); void WM_menu_name_call(struct bContext *C, const char *menu_name, short context); int WM_enum_search_invoke_previews(struct bContext *C, @@ -451,7 +451,7 @@ int WM_operator_confirm_message_ex(struct bContext *C, const char *title, const int icon, const char *message, - const short opcontext); + const wmOperatorCallContext opcontext); int WM_operator_confirm_message(struct bContext *C, struct wmOperator *op, const char *message); /* operator api */ @@ -474,26 +474,26 @@ bool WM_operator_is_repeat(const struct bContext *C, const struct wmOperator *op bool WM_operator_name_poll(struct bContext *C, const char *opstring); int WM_operator_name_call_ptr(struct bContext *C, struct wmOperatorType *ot, - short context, + wmOperatorCallContext context, struct PointerRNA *properties); int WM_operator_name_call(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct PointerRNA *properties); int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct IDProperty *properties); int WM_operator_call_py(struct bContext *C, struct wmOperatorType *ot, - short context, + wmOperatorCallContext context, struct PointerRNA *properties, struct ReportList *reports, const bool is_undo); void WM_operator_name_call_ptr_with_depends_on_cursor(struct bContext *C, wmOperatorType *ot, - short opcontext, + wmOperatorCallContext opcontext, PointerRNA *properties, const char *drawstr); diff --git a/source/blender/windowmanager/WM_keymap.h b/source/blender/windowmanager/WM_keymap.h index 564afe084b9..0633ffe55ea 100644 --- a/source/blender/windowmanager/WM_keymap.h +++ b/source/blender/windowmanager/WM_keymap.h @@ -26,6 +26,7 @@ /* dna-savable wmStructs here */ #include "BLI_utildefines.h" #include "DNA_windowmanager_types.h" +#include "WM_types.h" #ifdef __cplusplus extern "C" { @@ -169,14 +170,14 @@ int WM_keymap_item_raw_to_string(const short shift, const int result_len); wmKeyMapItem *WM_key_event_operator(const struct bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, struct IDProperty *properties, const short include_mask, const short exclude_mask, struct wmKeyMap **r_keymap); char *WM_key_event_operator_string(const struct bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, struct IDProperty *properties, const bool is_strict, char *result, diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index 27c8aa532f2..b8fe3786bde 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -211,7 +211,7 @@ enum { * Context to call operator in for #WM_operator_name_call. * rna_ui.c contains EnumPropertyItem's of these, keep in sync. */ -enum { +typedef enum wmOperatorCallContext { /* if there's invoke, call it, otherwise exec */ WM_OP_INVOKE_DEFAULT, WM_OP_INVOKE_REGION_WIN, @@ -226,9 +226,11 @@ enum { WM_OP_EXEC_REGION_PREVIEW, WM_OP_EXEC_AREA, WM_OP_EXEC_SCREEN, -}; +} wmOperatorCallContext; -#define WM_OP_CONTEXT_HAS_AREA(type) (!ELEM(type, WM_OP_INVOKE_SCREEN, WM_OP_EXEC_SCREEN)) +#define WM_OP_CONTEXT_HAS_AREA(type) \ + (CHECK_TYPE_INLINE(type, wmOperatorCallContext), \ + !ELEM(type, WM_OP_INVOKE_SCREEN, WM_OP_EXEC_SCREEN)) #define WM_OP_CONTEXT_HAS_REGION(type) \ (WM_OP_CONTEXT_HAS_AREA(type) && !ELEM(type, WM_OP_INVOKE_AREA, WM_OP_EXEC_AREA)) @@ -923,7 +925,7 @@ typedef struct wmOperatorType { typedef struct wmOperatorCallParams { struct wmOperatorType *optype; struct PointerRNA *opptr; - short opcontext; + wmOperatorCallContext opcontext; } wmOperatorCallParams; #ifdef WITH_INPUT_IME @@ -1079,6 +1081,10 @@ typedef struct wmDrag { /** * Dropboxes are like keymaps, part of the screen/area/region definition. * Allocation and free is on startup and exit. + * + * The operator is polled and invoked with the current context (#WM_OP_INVOKE_DEFAULT), there is no + * way to override that (by design, since dropboxes should act on the exact mouse position). So the + * drop-boxes are supposed to check the required area and region context in their poll. */ typedef struct wmDropBox { struct wmDropBox *next, *prev; @@ -1120,10 +1126,6 @@ typedef struct wmDropBox { struct IDProperty *properties; /** RNA pointer to access properties. */ struct PointerRNA *ptr; - - /** Default invoke. */ - short opcontext; - } wmDropBox; /** diff --git a/source/blender/windowmanager/gizmo/WM_gizmo_types.h b/source/blender/windowmanager/gizmo/WM_gizmo_types.h index ceaec94e70b..8bf82a41c91 100644 --- a/source/blender/windowmanager/gizmo/WM_gizmo_types.h +++ b/source/blender/windowmanager/gizmo/WM_gizmo_types.h @@ -29,6 +29,7 @@ #pragma once #include "BLI_compiler_attrs.h" +#include "BLI_utildefines.h" struct wmGizmo; struct wmGizmoGroup; @@ -163,6 +164,8 @@ typedef enum eWM_GizmoFlagGroupTypeFlag { WM_GIZMOGROUPTYPE_VR_REDRAWS = (1 << 10), } eWM_GizmoFlagGroupTypeFlag; +ENUM_OPERATORS(eWM_GizmoFlagGroupTypeFlag, WM_GIZMOGROUPTYPE_VR_REDRAWS); + /** * #wmGizmoGroup.init_flag */ diff --git a/source/blender/windowmanager/intern/wm.c b/source/blender/windowmanager/intern/wm.c index 4458b386ab6..47ee296823b 100644 --- a/source/blender/windowmanager/intern/wm.c +++ b/source/blender/windowmanager/intern/wm.c @@ -91,13 +91,18 @@ static void window_manager_foreach_id(ID *id, LibraryForeachIDData *data) /* This pointer can be NULL during old files reading, better be safe than sorry. */ if (win->workspace_hook != NULL) { ID *workspace = (ID *)BKE_workspace_active_get(win->workspace_hook); - BKE_LIB_FOREACHID_PROCESS_ID(data, workspace, IDWALK_CB_NOP); + BKE_lib_query_foreachid_process(data, &workspace, IDWALK_CB_USER); /* Allow callback to set a different workspace. */ BKE_workspace_active_set(win->workspace_hook, (WorkSpace *)workspace); + if (BKE_lib_query_foreachid_iter_stop(data)) { + return; + } } + if (BKE_lib_query_foreachid_process_flags_get(data) & IDWALK_INCLUDE_UI) { LISTBASE_FOREACH (ScrArea *, area, &win->global_areas.areabase) { - BKE_screen_foreach_id_screen_area(data, area); + BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, + BKE_screen_foreach_id_screen_area(data, area)); } } } diff --git a/source/blender/windowmanager/intern/wm_dragdrop.c b/source/blender/windowmanager/intern/wm_dragdrop.c index 49b84abf9a2..bc87347b2f3 100644 --- a/source/blender/windowmanager/intern/wm_dragdrop.c +++ b/source/blender/windowmanager/intern/wm_dragdrop.c @@ -122,7 +122,6 @@ wmDropBox *WM_dropbox_add(ListBase *lb, drop->cancel = cancel; drop->tooltip = tooltip; drop->ot = WM_operatortype_find(idname, 0); - drop->opcontext = WM_OP_INVOKE_DEFAULT; if (drop->ot == NULL) { MEM_freeN(drop); @@ -324,7 +323,8 @@ static wmDropBox *dropbox_active(bContext *C, continue; } - if (WM_operator_poll_context(C, drop->ot, drop->opcontext)) { + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); + if (WM_operator_poll_context(C, drop->ot, opcontext)) { return drop; } @@ -392,10 +392,11 @@ static void wm_drop_update_active(bContext *C, wmDrag *drag, const wmEvent *even void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop) { + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); /* Optionally copy drag information to operator properties. Don't call it if the * operator fails anyway, it might do more than just set properties (e.g. * typically import an asset). */ - if (drop->copy && WM_operator_poll_context(C, drop->ot, drop->opcontext)) { + if (drop->copy && WM_operator_poll_context(C, drop->ot, opcontext)) { drop->copy(drag, drop); } @@ -423,6 +424,16 @@ void wm_drags_check_ops(bContext *C, const wmEvent *event) } } +/** + * The operator of a dropbox should always be executed in the context determined by the mouse + * coordinates. The dropbox poll should check the context area and region as needed. + * So this always returns #WM_OP_INVOKE_DEFAULT. + */ +wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *UNUSED(drop)) +{ + return WM_OP_INVOKE_DEFAULT; +} + /* ************** IDs ***************** */ void WM_drag_add_local_ID(wmDrag *drag, ID *id, ID *from_parent) diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 8acce240046..d8d57a9370c 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -108,6 +108,8 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) } if (pc->poll == NULL || pc->poll(C)) { + UI_SetTheme(area->spacetype, region->regiontype); + /* Prevent drawing outside region. */ GPU_scissor_test(true); GPU_scissor(region->winrct.xmin, @@ -839,6 +841,7 @@ static void wm_draw_window_onscreen(bContext *C, wmWindow *win, int view) } /* After area regions so we can do area 'overlay' drawing. */ + UI_SetTheme(0, 0); ED_screen_draw_edges(win); wm_draw_callbacks(win); wmWindowViewport(win); diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index b780fef289a..474d900a53d 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -108,7 +108,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, + const wmOperatorCallContext context, const bool poll_only, wmEvent *event); @@ -1460,7 +1460,7 @@ static int wm_operator_call_internal(bContext *C, wmOperatorType *ot, PointerRNA *properties, ReportList *reports, - const short context, + const wmOperatorCallContext context, const bool poll_only, wmEvent *event) { @@ -1595,13 +1595,16 @@ static int wm_operator_call_internal(bContext *C, /* Invokes operator in context. */ int WM_operator_name_call_ptr(bContext *C, wmOperatorType *ot, - short context, + wmOperatorCallContext context, PointerRNA *properties) { BLI_assert(ot == WM_operatortype_find(ot->idname, true)); return wm_operator_call_internal(C, ot, properties, NULL, context, false, NULL); } -int WM_operator_name_call(bContext *C, const char *opstring, short context, PointerRNA *properties) +int WM_operator_name_call(bContext *C, + const char *opstring, + wmOperatorCallContext context, + PointerRNA *properties) { wmOperatorType *ot = WM_operatortype_find(opstring, 0); if (ot) { @@ -1623,7 +1626,7 @@ bool WM_operator_name_poll(bContext *C, const char *opstring) int WM_operator_name_call_with_properties(struct bContext *C, const char *opstring, - short context, + wmOperatorCallContext context, struct IDProperty *properties) { PointerRNA props_ptr; @@ -1654,7 +1657,7 @@ void WM_menu_name_call(bContext *C, const char *menu_name, short context) */ int WM_operator_call_py(bContext *C, wmOperatorType *ot, - short context, + wmOperatorCallContext context, PointerRNA *properties, ReportList *reports, const bool is_undo) @@ -1778,8 +1781,11 @@ static int ui_handler_wait_for_input(bContext *C, const wmEvent *event, void *us return WM_UI_HANDLER_CONTINUE; } -void WM_operator_name_call_ptr_with_depends_on_cursor( - bContext *C, wmOperatorType *ot, short opcontext, PointerRNA *properties, const char *drawstr) +void WM_operator_name_call_ptr_with_depends_on_cursor(bContext *C, + wmOperatorType *ot, + wmOperatorCallContext opcontext, + PointerRNA *properties, + const char *drawstr) { int flag = ot->flag; @@ -3073,8 +3079,9 @@ static int wm_handlers_do_intern(bContext *C, wmWindow *win, wmEvent *event, Lis BLI_addtail(&single_lb, drag); event->customdata = &single_lb; + const wmOperatorCallContext opcontext = wm_drop_operator_context_get(drop); int op_retval = wm_operator_call_internal( - C, drop->ot, drop->ptr, NULL, drop->opcontext, false, event); + C, drop->ot, drop->ptr, NULL, opcontext, false, event); OPERATOR_RETVAL_CHECK(op_retval); if ((op_retval & OPERATOR_CANCELLED) && drop->cancel) { diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index b45cf765a75..00ac1c2ffe6 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -53,6 +53,7 @@ #include "BLO_readfile.h" #include "BKE_armature.h" +#include "BKE_blendfile_link_append.h" #include "BKE_context.h" #include "BKE_global.h" #include "BKE_key.h" @@ -166,838 +167,6 @@ static int wm_link_append_flag(wmOperator *op) return flag; } -typedef struct WMLinkAppendDataItem { - char *name; - BLI_bitmap - *libraries; /* All libs (from WMLinkAppendData.libraries) to try to load this ID from. */ - short idcode; - - /** Type of action to do to append this item, and other append-specific information. */ - char append_action; - char append_tag; - - ID *new_id; - Library *source_library; - void *customdata; -} WMLinkAppendDataItem; - -typedef struct WMLinkAppendData { - LinkNodePair libraries; - LinkNodePair items; - int num_libraries; - int num_items; - /** - * Combines #eFileSel_Params_Flag from DNA_space_types.h & #eBLOLibLinkFlags from BLO_readfile.h - */ - int flag; - - /** Allows to easily find an existing items from an ID pointer. Used by append code. */ - GHash *new_id_to_item; - - /** Runtime info used by append code to manage re-use of already appended matching IDs. */ - GHash *library_weak_reference_mapping; - - /* Internal 'private' data */ - MemArena *memarena; -} WMLinkAppendData; - -typedef struct WMLinkAppendDataCallBack { - WMLinkAppendData *lapp_data; - WMLinkAppendDataItem *item; - ReportList *reports; - -} WMLinkAppendDataCallBack; - -enum { - WM_APPEND_ACT_UNSET = 0, - WM_APPEND_ACT_KEEP_LINKED, - WM_APPEND_ACT_REUSE_LOCAL, - WM_APPEND_ACT_MAKE_LOCAL, - WM_APPEND_ACT_COPY_LOCAL, -}; - -enum { - WM_APPEND_TAG_INDIRECT = 1 << 0, -}; - -static WMLinkAppendData *wm_link_append_data_new(const int flag) -{ - MemArena *ma = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); - WMLinkAppendData *lapp_data = BLI_memarena_calloc(ma, sizeof(*lapp_data)); - - lapp_data->flag = flag; - lapp_data->memarena = ma; - - return lapp_data; -} - -static void wm_link_append_data_free(WMLinkAppendData *lapp_data) -{ - if (lapp_data->new_id_to_item != NULL) { - BLI_ghash_free(lapp_data->new_id_to_item, NULL, NULL); - } - - BLI_assert(lapp_data->library_weak_reference_mapping == NULL); - - BLI_memarena_free(lapp_data->memarena); -} - -/* WARNING! *Never* call wm_link_append_data_library_add() after having added some items! */ - -static void wm_link_append_data_library_add(WMLinkAppendData *lapp_data, const char *libname) -{ - size_t len = strlen(libname) + 1; - char *libpath = BLI_memarena_alloc(lapp_data->memarena, len); - - BLI_strncpy(libpath, libname, len); - BLI_linklist_append_arena(&lapp_data->libraries, libpath, lapp_data->memarena); - lapp_data->num_libraries++; -} - -static WMLinkAppendDataItem *wm_link_append_data_item_add(WMLinkAppendData *lapp_data, - const char *idname, - const short idcode, - void *customdata) -{ - WMLinkAppendDataItem *item = BLI_memarena_calloc(lapp_data->memarena, sizeof(*item)); - size_t len = strlen(idname) + 1; - - item->name = BLI_memarena_alloc(lapp_data->memarena, len); - BLI_strncpy(item->name, idname, len); - item->idcode = idcode; - item->libraries = BLI_BITMAP_NEW_MEMARENA(lapp_data->memarena, lapp_data->num_libraries); - - item->new_id = NULL; - item->append_action = WM_APPEND_ACT_UNSET; - item->customdata = customdata; - - BLI_linklist_append_arena(&lapp_data->items, item, lapp_data->memarena); - lapp_data->num_items++; - - return item; -} - -/* -------------------------------------------------------------------- */ -/** \name Library appending helper functions. - * - * FIXME: Deduplicate code with similar one in readfile.c - * \{ */ - -static bool object_in_any_scene(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Scene *, sce, &bmain->scenes) { - if (BKE_scene_object_find(sce, ob)) { - return true; - } - } - - return false; -} - -static bool object_in_any_collection(Main *bmain, Object *ob) -{ - LISTBASE_FOREACH (Collection *, collection, &bmain->collections) { - if (BKE_collection_has_object(collection, ob)) { - return true; - } - } - - LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { - if (scene->master_collection != NULL && - BKE_collection_has_object(scene->master_collection, ob)) { - return true; - } - } - - return false; -} - -static ID *wm_append_loose_data_instantiate_process_check(WMLinkAppendDataItem *item) -{ - /* We consider that if we either kept it linked, or re-used already local data, instantiation - * status of those should not be modified. */ - if (!ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_MAKE_LOCAL)) { - return NULL; - } - - ID *id = item->new_id; - if (id == NULL) { - return NULL; - } - - if (item->append_action == WM_APPEND_ACT_COPY_LOCAL) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - return NULL; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; - } - - BLI_assert(!ID_IS_LINKED(id)); - return id; -} - -static void wm_append_loose_data_instantiate_ensure_active_collection( - WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - Collection **r_active_collection) -{ - /* Find or add collection as needed. */ - if (*r_active_collection == NULL) { - if (lapp_data->flag & FILE_ACTIVE_COLLECTION) { - LayerCollection *lc = BKE_layer_collection_get_active(view_layer); - *r_active_collection = lc->collection; - } - else { - *r_active_collection = BKE_collection_add(bmain, scene->master_collection, NULL); - } - } -} - -/* TODO: De-duplicate this code with the one in readfile.c, think we need some utils code for that - * in BKE. */ -static void wm_append_loose_data_instantiate(WMLinkAppendData *lapp_data, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - if (scene == NULL) { - /* In some cases, like the asset drag&drop e.g., the caller code manages instantiation itself. - */ - return; - } - - LinkNode *itemlink; - Collection *active_collection = NULL; - const bool do_obdata = (lapp_data->flag & BLO_LIBLINK_OBDATA_INSTANCE) != 0; - - /* Do NOT make base active here! screws up GUI stuff, - * if you want it do it at the editor level. */ - const bool object_set_active = false; - - /* First pass on obdata to enable their instantiation by default, then do a second pass on - * objects to clear it for any obdata already in use. */ - if (do_obdata) { - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - - id->tag |= LIB_TAG_DOIT; - } - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - Object *new_ob = (Object *)id->newid; - if (ob->data != NULL) { - ((ID *)(ob->data))->tag &= ~LIB_TAG_DOIT; - } - if (new_ob != NULL && new_ob->data != NULL) { - ((ID *)(new_ob->data))->tag &= ~LIB_TAG_DOIT; - } - } - } - - /* First do collections, then objects, then obdata. */ - - /* NOTE: For collections we only view_layer-instantiate duplicated collections that have - * non-instantiated objects in them. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_GR) { - continue; - } - - /* We do not want to force instantiation of indirectly appended collections. Users can now - * easily instantiate collections (and their objects) as needed by themselves. See T67032. */ - /* We need to check that objects in that collections are already instantiated in a scene. - * Otherwise, it's better to add the collection to the scene's active collection, than to - * instantiate its objects in active scene's collection directly. See T61141. - * - * NOTE: We only check object directly into that collection, not recursively into its - * children. - */ - Collection *collection = (Collection *)id; - /* We always add collections directly selected by the user. */ - bool do_add_collection = (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0; - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - if (!object_in_any_scene(bmain, ob)) { - do_add_collection = true; - break; - } - } - if (do_add_collection) { - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - /* In case user requested instantiation of collections as empties, we do so for the one they - * explicitly selected (originally directly linked IDs). */ - if ((lapp_data->flag & BLO_LIBLINK_COLLECTION_INSTANCE) != 0 && - (item->append_tag & WM_APPEND_TAG_INDIRECT) == 0) { - /* BKE_object_add(...) messes with the selection. */ - Object *ob = BKE_object_add_only_object(bmain, OB_EMPTY, collection->id.name + 2); - ob->type = OB_EMPTY; - ob->empty_drawsize = U.collection_instance_empty_size; - - const bool set_selected = (lapp_data->flag & FILE_AUTOSELECT) != 0; - /* TODO: why is it OK to make this active here but not in other situations? - * See other callers of #object_base_instance_init */ - const bool set_active = set_selected; - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, set_active); - - /* Assign the collection. */ - ob->instance_collection = collection; - id_us_plus(&collection->id); - ob->transflag |= OB_DUPLICOLLECTION; - copy_v3_v3(ob->loc, scene->cursor.location); - } - else { - /* Add collection as child of active collection. */ - BKE_collection_child_add(bmain, active_collection, collection); - - if ((lapp_data->flag & FILE_AUTOSELECT) != 0) { - LISTBASE_FOREACH (CollectionObject *, coll_ob, &collection->gobject) { - Object *ob = coll_ob->ob; - Base *base = BKE_view_layer_base_find(view_layer, ob); - if (base) { - base->flag |= BASE_SELECTED; - BKE_scene_object_base_flag_sync_from_base(base); - } - } - } - } - } - } - - /* NOTE: For objects we only view_layer-instantiate duplicated objects that are not yet used - * anywhere. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - - Object *ob = (Object *)id; - - if (object_in_any_collection(bmain, ob)) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - CLAMP_MIN(ob->id.us, 0); - ob->mode = OB_MODE_OBJECT; - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - } - - if (!do_obdata) { - return; - } - - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL) { - continue; - } - const ID_Type idcode = GS(id->name); - if (!OB_DATA_SUPPORT_ID(idcode)) { - continue; - } - if ((id->tag & LIB_TAG_DOIT) == 0) { - continue; - } - - wm_append_loose_data_instantiate_ensure_active_collection( - lapp_data, bmain, scene, view_layer, &active_collection); - - const int type = BKE_object_obdata_to_type(id); - BLI_assert(type != -1); - Object *ob = BKE_object_add_only_object(bmain, type, id->name + 2); - ob->data = id; - id_us_plus(id); - BKE_object_materials_test(bmain, ob, ob->data); - - BLO_object_instantiate_object_base_instance_init( - bmain, active_collection, ob, view_layer, v3d, lapp_data->flag, object_set_active); - - copy_v3_v3(ob->loc, scene->cursor.location); - - id->tag &= ~LIB_TAG_DOIT; - } - - /* Finally, add rigid body objects and constraints to current RB world(s). */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = wm_append_loose_data_instantiate_process_check(item); - if (id == NULL || GS(id->name) != ID_OB) { - continue; - } - BKE_rigidbody_ensure_local_object(bmain, (Object *)id); - } -} - -/** \} */ - -static int foreach_libblock_append_callback(LibraryIDLinkCallbackData *cb_data) -{ - /* NOTE: It is important to also skip liboverride references here, as those should never be made - * local. */ - if (cb_data->cb_flag & (IDWALK_CB_EMBEDDED | IDWALK_CB_INTERNAL | IDWALK_CB_LOOPBACK | - IDWALK_CB_OVERRIDE_LIBRARY_REFERENCE)) { - return IDWALK_RET_NOP; - } - - WMLinkAppendDataCallBack *data = cb_data->user_data; - ID *id = *cb_data->id_pointer; - - if (id == NULL) { - return IDWALK_RET_NOP; - } - - if (!BKE_idtype_idcode_is_linkable(GS(id->name))) { - /* While we do not want to add non-linkable ID (shape keys...) to the list of linked items, - * unfortunately they can use fully linkable valid IDs too, like actions. Those need to be - * processed, so we need to recursively deal with them here. */ - /* NOTE: Since we are by-passing checks in `BKE_library_foreach_ID_link` by manually calling it - * recursively, we need to take care of potential recursion cases ourselves (e.g.animdata of - * shapekey referencing the shapekey itself). */ - if (id != cb_data->id_self) { - BKE_library_foreach_ID_link( - cb_data->bmain, id, foreach_libblock_append_callback, data, IDWALK_NOP); - } - return IDWALK_RET_NOP; - } - - const bool do_recursive = (data->lapp_data->flag & BLO_LIBLINK_APPEND_RECURSIVE) != 0; - if (!do_recursive && cb_data->id_owner->lib != id->lib) { - /* When `do_recursive` is false, we only make local IDs from same library(-ies) as the - * initially directly linked ones. */ - return IDWALK_RET_NOP; - } - - WMLinkAppendDataItem *item = BLI_ghash_lookup(data->lapp_data->new_id_to_item, id); - if (item == NULL) { - item = wm_link_append_data_item_add(data->lapp_data, id->name, GS(id->name), NULL); - item->new_id = id; - item->source_library = id->lib; - /* Since we did not have an item for that ID yet, we know user did not selected it explicitly, - * it was rather linked indirectly. This info is important for instantiation of collections. */ - item->append_tag |= WM_APPEND_TAG_INDIRECT; - BLI_ghash_insert(data->lapp_data->new_id_to_item, id, item); - } - - /* NOTE: currently there is no need to do anything else here, but in the future this would be - * the place to add specific per-usage decisions on how to append an ID. */ - - return IDWALK_RET_NOP; -} - -/* Perform append operation, using modern ID usage looper to detect which ID should be kept linked, - * made local, duplicated as local, re-used from local etc. - * - * TODO: Expose somehow this logic to the two other parts of code performing actual append - * (i.e. copy/paste and `bpy` link/append API). - * Then we can heavily simplify #BKE_library_make_local(). */ -static void wm_append_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - BLI_assert((lapp_data->flag & FILE_LINK) == 0); - - const bool set_fakeuser = (lapp_data->flag & BLO_LIBLINK_APPEND_SET_FAKEUSER) != 0; - const bool do_reuse_local_id = (lapp_data->flag & BLO_LIBLINK_APPEND_LOCAL_ID_REUSE) != 0; - - const int make_local_common_flags = LIB_ID_MAKELOCAL_FULL_LIBRARY | - ((lapp_data->flag & BLO_LIBLINK_APPEND_ASSET_DATA_CLEAR) != - 0 ? - LIB_ID_MAKELOCAL_ASSET_DATA_CLEAR : - 0); - - LinkNode *itemlink; - - /* Generate a mapping between newly linked IDs and their items, and tag linked IDs used as - * liboverride references as already existing. */ - lapp_data->new_id_to_item = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, __func__); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_ghash_insert(lapp_data->new_id_to_item, id, item); - - /* This ensures that if a liboverride reference is also linked/used by some other appended - * data, it gets a local copy instead of being made directly local, so that the liboverride - * references remain valid (i.e. linked data). */ - if (ID_IS_OVERRIDE_LIBRARY_REAL(id)) { - id->override_library->reference->tag |= LIB_TAG_PRE_EXISTING; - } - } - - lapp_data->library_weak_reference_mapping = BKE_main_library_weak_reference_create(bmain); - - /* NOTE: Since we append items for IDs not already listed (i.e. implicitly linked indirect - * dependencies), this list will grow and we will process those IDs later, leading to a flatten - * recursive processing of all the linked dependencies. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(item->customdata == NULL); - - /* In Append case linked IDs should never be marked as needing post-processing (instantiation - * of loose objects etc.). */ - BLI_assert((id->tag & LIB_TAG_DOIT) == 0); - - ID *existing_local_id = BKE_idtype_idcode_append_is_reusable(GS(id->name)) ? - BKE_main_library_weak_reference_search_item( - lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name) : - NULL; - - if (item->append_action != WM_APPEND_ACT_UNSET) { - /* Already set, pass. */ - } - if (GS(id->name) == ID_OB && ((Object *)id)->proxy_from != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' is proxified, keeping it linked...", id->name); - item->append_action = WM_APPEND_ACT_KEEP_LINKED; - } - else if (do_reuse_local_id && existing_local_id != NULL) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' as a matching local one, re-using it...", id->name); - item->append_action = WM_APPEND_ACT_REUSE_LOCAL; - item->customdata = existing_local_id; - } - else if (id->tag & LIB_TAG_PRE_EXISTING) { - CLOG_INFO(&LOG, 3, "Appended ID '%s' was already linked, need to copy it...", id->name); - item->append_action = WM_APPEND_ACT_COPY_LOCAL; - } - else { - CLOG_INFO(&LOG, 3, "Appended ID '%s' will be made local...", id->name); - item->append_action = WM_APPEND_ACT_MAKE_LOCAL; - } - - /* Only check dependencies if we are not keeping linked data, nor re-using existing local data. - */ - if (!ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - WMLinkAppendDataCallBack cb_data = { - .lapp_data = lapp_data, .item = item, .reports = reports}; - BKE_library_foreach_ID_link( - bmain, id, foreach_libblock_append_callback, &cb_data, IDWALK_NOP); - } - - /* If we found a matching existing local id but are not re-using it, we need to properly clear - * its weak reference to linked data. */ - if (existing_local_id != NULL && - !ELEM(item->append_action, WM_APPEND_ACT_KEEP_LINKED, WM_APPEND_ACT_REUSE_LOCAL)) { - BKE_main_library_weak_reference_remove_item(lapp_data->library_weak_reference_mapping, - id->lib->filepath, - id->name, - existing_local_id); - } - } - - /* Effectively perform required operation on every linked ID. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *id = item->new_id; - if (id == NULL) { - continue; - } - - ID *local_appended_new_id = NULL; - char lib_filepath[FILE_MAX]; - BLI_strncpy(lib_filepath, id->lib->filepath, sizeof(lib_filepath)); - char lib_id_name[MAX_ID_NAME]; - BLI_strncpy(lib_id_name, id->name, sizeof(lib_id_name)); - - switch (item->append_action) { - case WM_APPEND_ACT_COPY_LOCAL: - BKE_lib_id_make_local(bmain, id, make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_COPY); - local_appended_new_id = id->newid; - break; - case WM_APPEND_ACT_MAKE_LOCAL: - BKE_lib_id_make_local(bmain, - id, - make_local_common_flags | LIB_ID_MAKELOCAL_FORCE_LOCAL | - LIB_ID_MAKELOCAL_OBJECT_NO_PROXY_CLEARING); - BLI_assert(id->newid == NULL); - local_appended_new_id = id; - break; - case WM_APPEND_ACT_KEEP_LINKED: - /* Nothing to do here. */ - break; - case WM_APPEND_ACT_REUSE_LOCAL: - /* We only need to set `newid` to ID found in previous loop, for proper remapping. */ - ID_NEW_SET(id, item->customdata); - /* This is not a 'new' local appended id, do not set `local_appended_new_id` here. */ - break; - case WM_APPEND_ACT_UNSET: - CLOG_ERROR( - &LOG, "Unexpected unset append action for '%s' ID, assuming 'keep link'", id->name); - break; - default: - BLI_assert(0); - } - - if (local_appended_new_id != NULL) { - if (BKE_idtype_idcode_append_is_reusable(GS(local_appended_new_id->name))) { - BKE_main_library_weak_reference_add_item(lapp_data->library_weak_reference_mapping, - lib_filepath, - lib_id_name, - local_appended_new_id); - } - - if (set_fakeuser) { - if (!ELEM(GS(local_appended_new_id->name), ID_OB, ID_GR)) { - /* Do not set fake user on objects nor collections (instancing). */ - id_fake_user_set(local_appended_new_id); - } - } - } - } - - BKE_main_library_weak_reference_destroy(lapp_data->library_weak_reference_mapping); - lapp_data->library_weak_reference_mapping = NULL; - - /* Remap IDs as needed. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action == WM_APPEND_ACT_KEEP_LINKED) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - if (ELEM(item->append_action, WM_APPEND_ACT_COPY_LOCAL, WM_APPEND_ACT_REUSE_LOCAL)) { - BLI_assert(ID_IS_LINKED(id)); - id = id->newid; - if (id == NULL) { - continue; - } - } - - BLI_assert(!ID_IS_LINKED(id)); - - BKE_libblock_relink_to_newid_new(bmain, id); - } - - /* Remove linked IDs when a local existing data has been reused instead. */ - BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_REUSE_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - BLI_assert(id->newid != NULL); - - id->tag |= LIB_TAG_DOIT; - item->new_id = id->newid; - } - BKE_id_multi_tagged_delete(bmain); - - /* Instantiate newly created (duplicated) IDs as needed. */ - wm_append_loose_data_instantiate(lapp_data, bmain, scene, view_layer, v3d); - - /* Attempt to deal with object proxies. - * - * NOTE: Copied from `BKE_library_make_local`, but this is not really working (as in, not - * producing any useful result in any known use case), neither here nor in - * `BKE_library_make_local` currently. - * Proxies are end of life anyway, so not worth spending time on this. */ - for (itemlink = lapp_data->items.list; itemlink; itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - - if (item->append_action != WM_APPEND_ACT_COPY_LOCAL) { - continue; - } - - ID *id = item->new_id; - if (id == NULL) { - continue; - } - BLI_assert(ID_IS_LINKED(id)); - - /* Attempt to re-link copied proxy objects. This allows appending of an entire scene - * from another blend file into this one, even when that blend file contains proxified - * armatures that have local references. Since the proxified object needs to be linked - * (not local), this will only work when the "Localize all" checkbox is disabled. - * TL;DR: this is a dirty hack on top of an already weak feature (proxies). */ - if (GS(id->name) == ID_OB && ((Object *)id)->proxy != NULL) { - Object *ob = (Object *)id; - Object *ob_new = (Object *)id->newid; - bool is_local = false, is_lib = false; - - /* Proxies only work when the proxified object is linked-in from a library. */ - if (!ID_IS_LINKED(ob->proxy)) { - CLOG_WARN(&LOG, - "Proxy object %s will lose its link to %s, because the " - "proxified object is local", - id->newid->name, - ob->proxy->id.name); - continue; - } - - BKE_library_ID_test_usages(bmain, id, &is_local, &is_lib); - - /* We can only switch the proxy'ing to a made-local proxy if it is no longer - * referred to from a library. Not checking for local use; if new local proxy - * was not used locally would be a nasty bug! */ - if (is_local || is_lib) { - CLOG_WARN(&LOG, - "Made-local proxy object %s will lose its link to %s, " - "because the linked-in proxy is referenced (is_local=%i, is_lib=%i)", - id->newid->name, - ob->proxy->id.name, - is_local, - is_lib); - } - else { - /* we can switch the proxy'ing from the linked-in to the made-local proxy. - * BKE_object_make_proxy() shouldn't be used here, as it allocates memory that - * was already allocated by object_make_local() (which called BKE_object_copy). */ - ob_new->proxy = ob->proxy; - ob_new->proxy_group = ob->proxy_group; - ob_new->proxy_from = ob->proxy_from; - ob_new->proxy->proxy_from = ob_new; - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - } - } - } - - BKE_main_id_newptr_and_tag_clear(bmain); -} - -static void wm_link_do(WMLinkAppendData *lapp_data, - ReportList *reports, - Main *bmain, - Scene *scene, - ViewLayer *view_layer, - const View3D *v3d) -{ - Main *mainl; - BlendHandle *bh; - Library *lib; - - const int flag = lapp_data->flag; - const int id_tag_extra = 0; - - LinkNode *liblink, *itemlink; - int lib_idx, item_idx; - - BLI_assert(lapp_data->num_items && lapp_data->num_libraries); - - for (lib_idx = 0, liblink = lapp_data->libraries.list; liblink; - lib_idx++, liblink = liblink->next) { - char *libname = liblink->link; - BlendFileReadReport bf_reports = {.reports = reports}; - - if (STREQ(libname, BLO_EMBEDDED_STARTUP_BLEND)) { - bh = BLO_blendhandle_from_memory( - datatoc_startup_blend, datatoc_startup_blend_size, &bf_reports); - } - else { - bh = BLO_blendhandle_from_file(libname, &bf_reports); - } - - if (bh == NULL) { - /* Unlikely since we just browsed it, but possible - * Error reports will have been made by BLO_blendhandle_from_file() */ - continue; - } - - /* here appending/linking starts */ - struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); - /* In case of append, do not handle instantiation in linking process, but during append phase - * (see #wm_append_loose_data_instantiate ). */ - if ((flag & FILE_LINK) == 0) { - liblink_params.flag &= ~BLO_LIBLINK_NEEDS_ID_TAG_DOIT; - } - - mainl = BLO_library_link_begin(&bh, libname, &liblink_params); - lib = mainl->curlib; - BLI_assert(lib); - UNUSED_VARS_NDEBUG(lib); - - if (mainl->versionfile < 250) { - BKE_reportf(reports, - RPT_WARNING, - "Linking or appending from a very old .blend file format (%d.%d), no animation " - "conversion will " - "be done! You may want to re-save your lib file with current Blender", - mainl->versionfile, - mainl->subversionfile); - } - - /* For each lib file, we try to link all items belonging to that lib, - * and tag those successful to not try to load them again with the other libs. */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *new_id; - - if (!BLI_BITMAP_TEST(item->libraries, lib_idx)) { - continue; - } - - new_id = BLO_library_link_named_part(mainl, &bh, item->idcode, item->name, &liblink_params); - - if (new_id) { - /* If the link is successful, clear item's libs 'todo' flags. - * This avoids trying to link same item with other libraries to come. */ - BLI_bitmap_set_all(item->libraries, false, lapp_data->num_libraries); - item->new_id = new_id; - item->source_library = new_id->lib; - } - } - - BLO_library_link_end(mainl, &bh, &liblink_params); - BLO_blendhandle_close(bh); - } -} - /** * Check if an item defined by \a name and \a group can be appended/linked. * @@ -1048,7 +217,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX_LIBEXTRA], root[FILE_MAXDIR], libname[FILE_MAX_LIBEXTRA], relname[FILE_MAX]; char *group, *name; int totfiles = 0; @@ -1115,7 +284,14 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* We define our working data... * Note that here, each item 'uses' one library, and only one. */ - lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, scene, view_layer, CTX_wm_view3d(C)); + + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); + if (totfiles != 0) { GHash *libraries = BLI_ghash_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, __func__); int lib_idx = 0; @@ -1133,7 +309,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) if (!BLI_ghash_haskey(libraries, libname)) { BLI_ghash_insert(libraries, BLI_strdup(libname), POINTER_FROM_INT(lib_idx)); lib_idx++; - wm_link_append_data_library_add(lapp_data, libname); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); } } } @@ -1145,7 +321,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_join_dirfile(path, sizeof(path), root, relname); if (BLO_library_path_explode(path, libname, &group, &name)) { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; if (!wm_link_append_item_poll(op->reports, path, group, name, do_append)) { continue; @@ -1153,9 +329,9 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) lib_idx = POINTER_AS_INT(BLI_ghash_lookup(libraries, libname)); - item = wm_link_append_data_item_add( - lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, lib_idx); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, lib_idx); } } RNA_END; @@ -1163,16 +339,17 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) BLI_ghash_free(libraries, MEM_freeN, NULL); } else { - WMLinkAppendDataItem *item; + BlendfileLinkAppendContextItem *item; - wm_link_append_data_library_add(lapp_data, libname); - item = wm_link_append_data_item_add(lapp_data, name, BKE_idtype_idcode_from_name(group), NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, libname, NULL); + item = BKE_blendfile_link_append_context_item_add( + lapp_context, name, BKE_idtype_idcode_from_name(group), NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); } - if (lapp_data->num_items == 0) { + if (BKE_blendfile_link_append_context_is_empty(lapp_context)) { /* Early out in case there is nothing to link. */ - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* Clear pre existing tag. */ BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); return OPERATOR_CANCELLED; @@ -1181,7 +358,7 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* XXX We'd need re-entrant locking on Main for this to work... */ // BKE_main_lock(bmain); - wm_link_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_link(lapp_context, op->reports); // BKE_main_unlock(bmain); @@ -1191,10 +368,10 @@ static int wm_link_append_exec(bContext *C, wmOperator *op) /* append, rather than linking */ if (do_append) { - wm_append_do(lapp_data, op->reports, bmain, scene, view_layer, CTX_wm_view3d(C)); + BKE_blendfile_append(lapp_context, op->reports); } - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* important we unset, otherwise these object won't * link into other scenes from this blend file */ @@ -1346,23 +523,29 @@ static ID *wm_file_link_append_datablock_ex(Main *bmain, BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* Define working data, with just the one item we want to link. */ - WMLinkAppendData *lapp_data = wm_link_append_data_new(flag); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, bmain, flag, 0, scene, view_layer, v3d); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_embedded_blendfile_set( + lapp_context, datatoc_startup_blend, datatoc_startup_blend_size); - wm_link_append_data_library_add(lapp_data, filepath); - WMLinkAppendDataItem *item = wm_link_append_data_item_add(lapp_data, id_name, id_code, NULL); - BLI_BITMAP_ENABLE(item->libraries, 0); + BKE_blendfile_link_append_context_library_add(lapp_context, filepath, NULL); + BlendfileLinkAppendContextItem *item = BKE_blendfile_link_append_context_item_add( + lapp_context, id_name, id_code, NULL); + BKE_blendfile_link_append_context_item_library_index_enable(lapp_context, item, 0); /* Link datablock. */ - wm_link_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_link(lapp_context, NULL); if (do_append) { - wm_append_do(lapp_data, NULL, bmain, scene, view_layer, v3d); + BKE_blendfile_append(lapp_context, NULL); } /* Get linked datablock and free working data. */ - ID *id = item->new_id; + ID *id = BKE_blendfile_link_append_context_item_newid_get(lapp_context, item); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); @@ -1439,291 +622,6 @@ static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UN return OPERATOR_CANCELLED; } -static void lib_relocate_do_remap(Main *bmain, - ID *old_id, - ID *new_id, - ReportList *reports, - const bool do_reload, - const short remap_flags) -{ - BLI_assert(old_id); - if (do_reload) { - /* Since we asked for placeholders in case of missing IDs, - * we expect to always get a valid one. */ - BLI_assert(new_id); - } - if (new_id) { - CLOG_INFO(&LOG, - 4, - "Before remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - BKE_libblock_remap_locked(bmain, old_id, new_id, remap_flags); - - if (old_id->flag & LIB_FAKEUSER) { - id_fake_user_clear(old_id); - id_fake_user_set(new_id); - } - - CLOG_INFO(&LOG, - 4, - "After remap of %s, old_id users: %d, new_id users: %d", - old_id->name, - old_id->us, - new_id->us); - - /* In some cases, new_id might become direct link, remove parent of library in this case. */ - if (new_id->lib->parent && (new_id->tag & LIB_TAG_INDIRECT) == 0) { - if (do_reload) { - BLI_assert_unreachable(); /* Should not happen in 'pure' reload case... */ - } - new_id->lib->parent = NULL; - } - } - - if (old_id->us > 0 && new_id && old_id->lib == new_id->lib) { - /* Note that this *should* not happen - but better be safe than sorry in this area, - * at least until we are 100% sure this cannot ever happen. - * Also, we can safely assume names were unique so far, - * so just replacing '.' by '~' should work, - * but this does not totally rules out the possibility of name collision. */ - size_t len = strlen(old_id->name); - size_t dot_pos; - bool has_num = false; - - for (dot_pos = len; dot_pos--;) { - char c = old_id->name[dot_pos]; - if (c == '.') { - break; - } - if (c < '0' || c > '9') { - has_num = false; - break; - } - has_num = true; - } - - if (has_num) { - old_id->name[dot_pos] = '~'; - } - else { - len = MIN2(len, MAX_ID_NAME - 7); - BLI_strncpy(&old_id->name[len], "~000", 7); - } - - id_sort_by_name(which_libbase(bmain, GS(old_id->name)), old_id, NULL); - - BKE_reportf( - reports, - RPT_WARNING, - "Lib Reload: Replacing all references to old data-block '%s' by reloaded one failed, " - "old one (%d remaining users) had to be kept and was renamed to '%s'", - new_id->name, - old_id->us, - old_id->name); - } -} - -static void lib_relocate_do(bContext *C, - Library *library, - WMLinkAppendData *lapp_data, - ReportList *reports, - const bool do_reload) -{ - ListBase *lbarray[INDEX_ID_MAX]; - int lba_idx; - - LinkNode *itemlink; - int item_idx; - - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - - /* Remove all IDs to be reloaded from Main. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id = lbarray[lba_idx]->first; - const short idcode = id ? GS(id->name) : 0; - - if (!id || !BKE_idtype_idcode_is_linkable(idcode)) { - /* No need to reload non-linkable datatypes, - * those will get relinked with their 'users ID'. */ - continue; - } - - for (; id; id = id->next) { - if (id->lib == library) { - WMLinkAppendDataItem *item; - - /* We remove it from current Main, and add it to items to link... */ - /* Note that non-linkable IDs (like e.g. shapekeys) are also explicitly linked here... */ - BLI_remlink(lbarray[lba_idx], id); - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(id); - if (old_key != NULL) { - BLI_remlink(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - - item = wm_link_append_data_item_add(lapp_data, id->name + 2, idcode, id); - BLI_bitmap_set_all(item->libraries, true, lapp_data->num_libraries); - - CLOG_INFO(&LOG, 4, "Datablock to seek for: %s", id->name); - } - } - } - - if (lapp_data->num_items == 0) { - /* Early out in case there is nothing to do. */ - return; - } - - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); - - /* We do not want any instantiation here! */ - wm_link_do(lapp_data, reports, bmain, NULL, NULL, NULL); - - BKE_main_lock(bmain); - - /* We add back old id to bmain. - * We need to do this in a first, separated loop, otherwise some of those may not be handled by - * ID remapping, which means they would still reference old data to be deleted... */ - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - BLI_assert(old_id); - BLI_addtail(which_libbase(bmain, GS(old_id->name)), old_id); - - /* Usual special code for ShapeKeys snowflakes... */ - Key *old_key = BKE_key_from_id(old_id); - if (old_key != NULL) { - BLI_addtail(which_libbase(bmain, GS(old_key->id.name)), &old_key->id); - } - } - - /* Since our (old) reloaded IDs were removed from main, the user count done for them in linking - * code is wrong, we need to redo it here after adding them back to main. */ - BKE_main_id_refcount_recompute(bmain, false); - - /* Note that in reload case, we also want to replace indirect usages. */ - const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_USAGE | - ID_REMAP_NO_INDIRECT_PROXY_DATA_USAGE | - (do_reload ? 0 : ID_REMAP_SKIP_INDIRECT_USAGE); - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - ID *new_id = item->new_id; - - lib_relocate_do_remap(bmain, old_id, new_id, reports, do_reload, remap_flags); - if (new_id == NULL) { - continue; - } - /* Usual special code for ShapeKeys snowflakes... */ - Key **old_key_p = BKE_key_from_id_p(old_id); - if (old_key_p == NULL) { - continue; - } - Key *old_key = *old_key_p; - Key *new_key = BKE_key_from_id(new_id); - if (old_key != NULL) { - *old_key_p = NULL; - id_us_min(&old_key->id); - lib_relocate_do_remap(bmain, &old_key->id, &new_key->id, reports, do_reload, remap_flags); - *old_key_p = old_key; - id_us_plus_no_lib(&old_key->id); - } - } - - BKE_main_unlock(bmain); - - for (item_idx = 0, itemlink = lapp_data->items.list; itemlink; - item_idx++, itemlink = itemlink->next) { - WMLinkAppendDataItem *item = itemlink->link; - ID *old_id = item->customdata; - - if (old_id->us == 0) { - BKE_id_free(bmain, old_id); - } - } - - /* Some datablocks can get reloaded/replaced 'silently' because they are not linkable - * (shape keys e.g.), so we need another loop here to clear old ones if possible. */ - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id, *id_next; - for (id = lbarray[lba_idx]->first; id; id = id_next) { - id_next = id->next; - /* XXX That check may be a bit to generic/permissive? */ - if (id->lib && (id->flag & LIB_TAG_PRE_EXISTING) && id->us == 0) { - BKE_id_free(bmain, id); - } - } - } - - /* Get rid of no more used libraries... */ - BKE_main_id_tag_idcode(bmain, ID_LI, LIB_TAG_DOIT, true); - lba_idx = set_listbasepointers(bmain, lbarray); - while (lba_idx--) { - ID *id; - for (id = lbarray[lba_idx]->first; id; id = id->next) { - if (id->lib) { - id->lib->id.tag &= ~LIB_TAG_DOIT; - } - } - } - Library *lib, *lib_next; - for (lib = which_libbase(bmain, ID_LI)->first; lib; lib = lib_next) { - lib_next = lib->id.next; - if (lib->id.tag & LIB_TAG_DOIT) { - id_us_clear_real(&lib->id); - if (lib->id.us == 0) { - BKE_id_free(bmain, (ID *)lib); - } - } - } - - /* Update overrides of reloaded linked data-blocks. */ - ID *id; - FOREACH_MAIN_ID_BEGIN (bmain, id) { - if (ID_IS_LINKED(id) || !ID_IS_OVERRIDE_LIBRARY_REAL(id) || - (id->tag & LIB_TAG_PRE_EXISTING) == 0) { - continue; - } - if ((id->override_library->reference->tag & LIB_TAG_PRE_EXISTING) == 0) { - BKE_lib_override_library_update(bmain, id); - } - } - FOREACH_MAIN_ID_END; - - /* Resync overrides if needed. */ - if (!USER_EXPERIMENTAL_TEST(&U, no_override_auto_resync)) { - BKE_lib_override_library_main_resync(bmain, - scene, - view_layer, - &(struct BlendFileReadReport){ - .reports = reports, - }); - /* We need to rebuild some of the deleted override rules (for UI feedback purpose). */ - BKE_lib_override_library_main_operations_create(bmain, true); - } - - BKE_main_collection_sync(bmain); - - BKE_main_lib_objects_recalc_all(bmain); - IMB_colormanagement_check_file_config(bmain); - - /* important we unset, otherwise these object won't - * link into other scenes from this blend file */ - BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); - - /* recreate dependency graph to include new objects */ - DEG_relations_tag_update(bmain); -} - void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) { if (!BLO_has_bfile_extension(lib->filepath_abs)) { @@ -1740,14 +638,34 @@ void WM_lib_reload(Library *lib, bContext *C, ReportList *reports) return; } - WMLinkAppendData *lapp_data = wm_link_append_data_new(BLO_LIBLINK_USE_PLACEHOLDERS | - BLO_LIBLINK_FORCE_INDIRECT); + Main *bmain = CTX_data_main(C); + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context(&lapp_params, + bmain, + BLO_LIBLINK_USE_PLACEHOLDERS | + BLO_LIBLINK_FORCE_INDIRECT, + 0, + CTX_data_scene(C), + CTX_data_view_layer(C), + NULL); + + BlendfileLinkAppendContext *lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); - wm_link_append_data_library_add(lapp_data, lib->filepath_abs); + BKE_blendfile_link_append_context_library_add(lapp_context, lib->filepath_abs, NULL); - lib_relocate_do(C, lib, lapp_data, reports, true); + BKE_blendfile_library_relocate(lapp_context, reports, lib, true); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); } @@ -1763,7 +681,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) if (lib) { Main *bmain = CTX_data_main(C); PropertyRNA *prop; - WMLinkAppendData *lapp_data; + BlendfileLinkAppendContext *lapp_context; char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; short flag = 0; @@ -1808,13 +726,17 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) return OPERATOR_CANCELLED; } + LibraryLink_Params lapp_params; + BLO_library_link_params_init_with_context( + &lapp_params, bmain, flag, 0, CTX_data_scene(C), CTX_data_view_layer(C), NULL); + if (BLI_path_cmp(lib->filepath_abs, path) == 0) { CLOG_INFO(&LOG, 4, "We are supposed to reload '%s' lib (%d)", lib->filepath, lib->id.us); do_reload = true; - lapp_data = wm_link_append_data_new(flag); - wm_link_append_data_library_add(lapp_data, path); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } else { int totfiles = 0; @@ -1834,7 +756,7 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } } - lapp_data = wm_link_append_data_new(flag); + lapp_context = BKE_blendfile_link_append_context_new(&lapp_params); if (totfiles) { RNA_BEGIN (op->ptr, itemptr, "files") { @@ -1847,27 +769,39 @@ static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) } CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } RNA_END; } else { CLOG_INFO(&LOG, 4, "\tCandidate new lib to reload datablocks from: %s", path); - wm_link_append_data_library_add(lapp_data, path); + BKE_blendfile_link_append_context_library_add(lapp_context, path, NULL); } } if (do_reload) { - lapp_data->flag |= BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT; + BKE_blendfile_link_append_context_flag_set( + lapp_context, BLO_LIBLINK_USE_PLACEHOLDERS | BLO_LIBLINK_FORCE_INDIRECT, true); } - lib_relocate_do(C, lib, lapp_data, op->reports, do_reload); + BKE_blendfile_library_relocate(lapp_context, op->reports, lib, do_reload); - wm_link_append_data_free(lapp_data); + BKE_blendfile_link_append_context_free(lapp_context); /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ BLI_strncpy(G.lib, root, FILE_MAX); + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* Important we unset, otherwise these object won't link into other scenes from this blend + * file. + */ + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, false); + + /* Recreate dependency graph to include new IDs. */ + DEG_relations_tag_update(bmain); + WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 658424b84a6..35f6ce40dba 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1394,7 +1394,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, wmWindow *win, ListBase *handlers, const char *opname, - int UNUSED(opcontext), + wmOperatorCallContext UNUSED(opcontext), IDProperty *properties, const bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1430,7 +1430,7 @@ static wmKeyMapItem *wm_keymap_item_find_handlers(const bContext *C, static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1543,7 +1543,7 @@ static wmKeyMapItem *wm_keymap_item_find_props(const bContext *C, static wmKeyMapItem *wm_keymap_item_find(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, bool is_strict, const struct wmKeyMapItemFind_Params *params, @@ -1642,7 +1642,7 @@ static bool kmi_filter_is_visible(const wmKeyMap *UNUSED(km), char *WM_key_event_operator_string(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const bool is_strict, char *result, @@ -1682,7 +1682,7 @@ static bool kmi_filter_is_visible_type_mask(const wmKeyMap *km, */ wmKeyMapItem *WM_key_event_operator(const bContext *C, const char *opname, - int opcontext, + wmOperatorCallContext opcontext, IDProperty *properties, const short include_mask, const short exclude_mask, diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 1130ad9a558..ffdc99152b1 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -1064,7 +1064,7 @@ int WM_operator_smooth_viewtx_get(const wmOperator *op) } /* invoke callback, uses enum property named "type" */ -int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext) +int WM_menu_invoke_ex(bContext *C, wmOperator *op, wmOperatorCallContext opcontext) { PropertyRNA *prop = op->type->prop; @@ -1216,7 +1216,7 @@ int WM_operator_confirm_message_ex(bContext *C, const char *title, const int icon, const char *message, - const short opcontext) + const wmOperatorCallContext opcontext) { IDProperty *properties = op->ptr->data; diff --git a/source/blender/windowmanager/intern/wm_playanim.c b/source/blender/windowmanager/intern/wm_playanim.c index fa21dbcb4bb..640fef82085 100644 --- a/source/blender/windowmanager/intern/wm_playanim.c +++ b/source/blender/windowmanager/intern/wm_playanim.c @@ -1570,7 +1570,7 @@ static char *wm_main_playanim_intern(int argc, const char **argv) /* initialize the font */ BLF_init(); ps.fontid = BLF_load_mono_default(false); - BLF_size(ps.fontid, 11, 72); + BLF_size(ps.fontid, 11.0f, 72); ps.ibufx = ibuf->x; ps.ibufy = ibuf->y; @@ -1845,7 +1845,6 @@ static char *wm_main_playanim_intern(int argc, const char **argv) } IMB_exit(); - BKE_images_exit(); DEG_free_node_types(); totblock = MEM_get_memory_blocks_in_use(); diff --git a/source/blender/windowmanager/wm_event_system.h b/source/blender/windowmanager/wm_event_system.h index 40e4d905fcd..9b0f128d071 100644 --- a/source/blender/windowmanager/wm_event_system.h +++ b/source/blender/windowmanager/wm_event_system.h @@ -32,6 +32,7 @@ struct ARegion; struct GHOST_TabletData; struct ScrArea; +enum wmOperatorCallContext; #ifdef WITH_XR_OPENXR struct wmXrActionData; @@ -175,6 +176,7 @@ void wm_dropbox_free(void); void wm_drags_exit(wmWindowManager *wm, wmWindow *win); void wm_drop_prepare(bContext *C, wmDrag *drag, wmDropBox *drop); void wm_drags_check_ops(bContext *C, const wmEvent *event); +wmOperatorCallContext wm_drop_operator_context_get(const wmDropBox *drop); void wm_drags_draw(bContext *C, wmWindow *win); #ifdef __cplusplus diff --git a/source/blender/windowmanager/xr/intern/wm_xr_operators.c b/source/blender/windowmanager/xr/intern/wm_xr_operators.c index 112312bab7b..f3470edf2f7 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_operators.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_operators.c @@ -432,10 +432,10 @@ static bool wm_xr_navigation_grab_can_do_bimanual(const wmXrActionData *actionda const XrGrabData *data) { /* Returns true if: 1) Bimanual interaction is currently occurring (i.e. inputs on both - controllers are pressed) and 2) bimanual interaction occurred on the last update. This second - part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to - two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas - are calculated). */ + * controllers are pressed) and 2) bimanual interaction occurred on the last update. This second + * part is needed to avoid "jumpy" navigation changes when transitioning from one-handed to + * two-handed interaction (see #wm_xr_grab_compute/compute_bimanual() for how navigation deltas + * are calculated). */ return (actiondata->bimanual && data->bimanual_prev); } @@ -545,7 +545,7 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven /* Check if navigation is locked. */ if (!wm_xr_navigation_grab_is_locked(data, do_bimanual)) { /* Prevent unwanted snapping (i.e. "jumpy" navigation changes when transitioning from - two-handed to one-handed interaction) at the end of a bimanual interaction. */ + * two-handed to one-handed interaction) at the end of a bimanual interaction. */ if (!wm_xr_navigation_grab_is_bimanual_ending(actiondata, data)) { wm_xr_navigation_grab_apply(xr, actiondata, data, do_bimanual); } @@ -554,9 +554,9 @@ static int wm_xr_navigation_grab_modal(bContext *C, wmOperator *op, const wmEven wm_xr_navigation_grab_bimanual_state_update(actiondata, data); /* Note: KM_PRESS and KM_RELEASE are the only two values supported by XR events during event - dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal - handling starts when an input is "pressed" (action state exceeds the action threshold) and - ends when the input is "released" (state falls below the threshold). */ + * dispatching (see #wm_xr_session_action_states_interpret()). For modal XR operators, modal + * handling starts when an input is "pressed" (action state exceeds the action threshold) and + * ends when the input is "released" (state falls below the threshold). */ switch (event->val) { case KM_PRESS: return OPERATOR_RUNNING_MODAL; diff --git a/source/creator/creator.c b/source/creator/creator.c index 7c99f954bfc..6daaea38c34 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -414,7 +414,6 @@ int main(int argc, BKE_idtype_init(); BKE_cachefiles_init(); - BKE_images_init(); BKE_modifier_init(); BKE_gpencil_modifier_init(); BKE_shaderfx_init(); @@ -552,7 +551,8 @@ int main(int argc, WM_exit(C); } else { - if (!G.file_loaded) { + /* When no file is loaded, show the splash screen. */ + if (!G.relbase_valid) { WM_init_splash(C); } WM_main(C); diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 943646daa81..896d29e0583 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -2008,8 +2008,6 @@ static int arg_handle_load_file(int UNUSED(argc), const char **argv, void *data) } } - G.file_loaded = 1; - return 0; } diff --git a/tests/gtests/runner/CMakeLists.txt b/tests/gtests/runner/CMakeLists.txt index b18eff59016..4500aa7b30f 100644 --- a/tests/gtests/runner/CMakeLists.txt +++ b/tests/gtests/runner/CMakeLists.txt @@ -56,7 +56,7 @@ setup_platform_linker_libs(blender_test) if(WIN32) foreach(_lib ${_test_libs}) # Both target_link_libraries and target_link_options are required here - # target_link_libraries will add any dependend libraries, while just setting + # target_link_libraries will add any dependent libraries, while just setting # the wholearchive flag in target link options will not. target_link_libraries(blender_test ${_lib}) target_link_options(blender_test PRIVATE /wholearchive:$<TARGET_FILE:${_lib}>) diff --git a/tests/performance/api/graph.py b/tests/performance/api/graph.py index b04cd367449..f4d45fa858c 100644 --- a/tests/performance/api/graph.py +++ b/tests/performance/api/graph.py @@ -75,7 +75,7 @@ class TestGraph: revision_dates[revision] = int(entry.date) # Google Charts JSON data layout is like a spreadsheat table, with - # colums, rows and cells. We create one column for revision labels, + # columns, rows, and cells. We create one column for revision labels, # and one column for each test. cols = [] if chart_type == 'line': diff --git a/tests/performance/benchmark b/tests/performance/benchmark index a58c339e9f8..80556674dcc 100755 --- a/tests/performance/benchmark +++ b/tests/performance/benchmark @@ -4,6 +4,7 @@ import api import argparse import fnmatch +import glob import pathlib import shutil import sys @@ -228,6 +229,9 @@ def cmd_reset(env: api.TestEnvironment, argv: List): config.queue.write() + if args.test == '*': + shutil.rmtree(config.logs_dir) + def cmd_run(env: api.TestEnvironment, argv: List, update_only: bool): # Run tests. parser = argparse.ArgumentParser() @@ -274,7 +278,17 @@ def cmd_graph(argv: List): parser.add_argument('-o', '--output', type=str, required=True) args = parser.parse_args(argv) - graph = api.TestGraph([pathlib.Path(path) for path in args.json_file]) + # For directories, use all json files in the directory. + json_files = [] + for path in args.json_file: + path = pathlib.Path(path) + if path.is_dir(): + for filepath in glob.iglob(str(path / '*.json')): + json_files.append(pathlib.Path(filepath)) + else: + json_files.append(path) + + graph = api.TestGraph(json_files) graph.write(pathlib.Path(args.output)) def main(): diff --git a/tests/python/CMakeLists.txt b/tests/python/CMakeLists.txt index 1927223cf32..fa63bdadd80 100644 --- a/tests/python/CMakeLists.txt +++ b/tests/python/CMakeLists.txt @@ -651,7 +651,6 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS) shader shadow_catcher sss - volume ) if(WITH_OPENSUBDIV) @@ -663,7 +662,7 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS) endif() if(WITH_MOD_FLUID) - list(APPEND render_tests motion_blur reports) + list(APPEND render_tests motion_blur reports volume) endif() if(WITH_OPENVDB) diff --git a/tests/python/bl_blendfile_liblink.py b/tests/python/bl_blendfile_liblink.py index ab26059e944..4cf81c9beae 100644 --- a/tests/python/bl_blendfile_liblink.py +++ b/tests/python/bl_blendfile_liblink.py @@ -109,7 +109,7 @@ class TestBlendLibLinkSaveLoadBasic(TestBlendLibLinkHelper): assert(len(bpy.data.meshes) == 0) assert(orig_data != read_data) - # Simple link of a single ObData with obdata instanciation. + # Simple link of a single ObData with obdata instantiation. self.reset_blender() link_dir = os.path.join(output_lib_path, "Mesh") @@ -147,7 +147,7 @@ class TestBlendLibLinkSaveLoadBasic(TestBlendLibLinkHelper): assert(orig_data == read_data) - # Simple link of a single Collection, with Empty-instanciation. + # Simple link of a single Collection, with Empty-instantiation. self.reset_blender() link_dir = os.path.join(output_lib_path, "Collection") @@ -166,7 +166,7 @@ class TestBlendLibLinkSaveLoadBasic(TestBlendLibLinkHelper): assert(orig_data == read_data) - # Simple link of a single Collection, with ViewLayer-instanciation. + # Simple link of a single Collection, with ViewLayer-instantiation. self.reset_blender() link_dir = os.path.join(output_lib_path, "Collection") @@ -216,7 +216,7 @@ class TestBlendLibAppendBasic(TestBlendLibLinkHelper): assert(len(bpy.data.objects) == 0) assert(len(bpy.data.collections) == 0) # Scene's master collection is not listed here - # Simple append of a single ObData with obdata instanciation. + # Simple append of a single ObData with obdata instantiation. self.reset_blender() link_dir = os.path.join(output_lib_path, "Mesh") @@ -370,10 +370,110 @@ class TestBlendLibAppendReuseID(TestBlendLibLinkHelper): assert(len(bpy.data.collections) == 0) # Scene's master collection is not listed here +class TestBlendLibLibraryReload(TestBlendLibLinkHelper): + + def __init__(self, args): + self.args = args + + def test_link_reload(self): + output_dir = self.args.output_dir + output_lib_path = self.init_lib_data_basic() + + # Simple link of a single Object, and reload. + self.reset_blender() + + link_dir = os.path.join(output_lib_path, "Object") + bpy.ops.wm.link(directory=link_dir, filename="LibMesh") + + assert(len(bpy.data.meshes) == 1) + assert(len(bpy.data.objects) == 1) + assert(len(bpy.data.collections) == 0) # Scene's master collection is not listed here + + orig_data = self.blender_data_to_tuple(bpy.data, "orig_data") + + bpy.ops.wm.lib_reload(library=bpy.data.objects[0].name) + + reload_data = self.blender_data_to_tuple(bpy.data, "reload_data") + + print(orig_data) + print(reload_data) + assert(orig_data == reload_data) + + + +class TestBlendLibLibraryRelocate(TestBlendLibLinkHelper): + + def __init__(self, args): + self.args = args + + def test_link_relocate(self): + output_dir = self.args.output_dir + output_lib_path = self.init_lib_data_basic() + + # Simple link of a single Object, and reload. + self.reset_blender() + + link_dir = os.path.join(output_lib_path, "Object") + bpy.ops.wm.link(directory=link_dir, filename="LibMesh") + + assert(len(bpy.data.meshes) == 1) + assert(len(bpy.data.objects) == 1) + assert(len(bpy.data.collections) == 0) # Scene's master collection is not listed here + + orig_data = self.blender_data_to_tuple(bpy.data, "orig_data") + + lib_path, lib_ext = os.path.splitext(output_lib_path) + new_lib_path = lib_path + "_relocate" + lib_ext + os.replace(output_lib_path, new_lib_path) + + bpy.ops.wm.lib_relocate(library=bpy.data.objects[0].name, directory="", filename=new_lib_path) + + relocate_data = self.blender_data_to_tuple(bpy.data, "relocate_data") + + print(orig_data) + print(relocate_data) + assert(orig_data == relocate_data) + + +class TestBlendLibDataLibrariesLoad(TestBlendLibLinkHelper): + + def __init__(self, args): + self.args = args + + def test_link_relocate(self): + output_dir = self.args.output_dir + output_lib_path = self.init_lib_data_basic() + + # Simple link of a single Object, and reload. + self.reset_blender() + + with bpy.data.libraries.load(filepath=output_lib_path) as lib_ctx: + lib_src, lib_link = lib_ctx + + assert(len(lib_src.meshes) == 1) + assert(len(lib_src.objects) == 1) + assert(len(lib_src.collections) == 1) + + assert(len(lib_link.meshes) == 0) + assert(len(lib_link.objects) == 0) + assert(len(lib_link.collections) == 0) + + lib_link.collections.append(lib_src.collections[0]) + + # Linking happens when living the context manager. + + assert(len(bpy.data.meshes) == 1) + assert(len(bpy.data.objects) == 1) # This code does no instantiation. + assert(len(bpy.data.collections) == 1) + + TESTS = ( TestBlendLibLinkSaveLoadBasic, TestBlendLibAppendBasic, TestBlendLibAppendReuseID, + TestBlendLibLibraryReload, + TestBlendLibLibraryRelocate, + TestBlendLibDataLibrariesLoad, ) diff --git a/tests/python/bl_blendfile_library_overrides.py b/tests/python/bl_blendfile_library_overrides.py index 3c7c77ce339..e0da1082ee0 100644 --- a/tests/python/bl_blendfile_library_overrides.py +++ b/tests/python/bl_blendfile_library_overrides.py @@ -59,7 +59,7 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): self.assertIsNone(local_id.data.override_library) assert(len(local_id.override_library.properties) == 0) - ##### Generate an override property & operation automaticaly by editing the local override data. + ##### Generate an override property & operation automatically by editing the local override data. local_id.location.y = 1.0 local_id.override_library.operations_update() assert(len(local_id.override_library.properties) == 1) @@ -68,7 +68,7 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): assert(len(override_prop.operations) == 1) override_operation = override_prop.operations[0] assert(override_operation.operation == 'REPLACE') - # Setting location.y overridded all elements in the location array. -1 is a wildcard. + # Setting location.y overrode all elements in the location array. -1 is a wildcard. assert(override_operation.subitem_local_index == -1) ##### Reset the override to its linked reference data. @@ -86,7 +86,7 @@ class TestLibraryOverrides(TestHelper, unittest.TestCase): assert(len(override_prop.operations) == 1) override_operation = override_prop.operations[0] assert(override_operation.operation == 'REPLACE') - # Setting location.y overridded all elements in the location array. -1 is a wildcard. + # Setting location.y overrode all elements in the location array. -1 is a wildcard. assert(override_operation.subitem_local_index == -1) override_property = local_id.override_library.properties[0] diff --git a/tests/python/bl_keymap_validate.py b/tests/python/bl_keymap_validate.py index 88c61df6125..ebc35c1178c 100644 --- a/tests/python/bl_keymap_validate.py +++ b/tests/python/bl_keymap_validate.py @@ -34,7 +34,7 @@ This catches the following kinds of issues: An escape key could have the value "NORTH" instead of "PRESS". This works by taking the keymap data (before it's loaded into Blender), -then comparing it with that same keymap after exporting and imporing. +then comparing it with that same keymap after exporting and importing. NOTE: |