diff options
726 files changed, 22857 insertions, 13108 deletions
diff --git a/.gitmodules b/.gitmodules index 132f6cffada..0b8228e3f14 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,3 +10,7 @@ path = release/datafiles/locale url = ../blender-translations.git ignore = all +[submodule "source/tools"] + path = source/tools + url = ../blender-dev-tools.git + ignore = all diff --git a/CMakeLists.txt b/CMakeLists.txt index 1c933d38ab9..1dfa838a5a2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1283,11 +1283,21 @@ elseif(WIN32) if(MSVC) # Minimum MSVC Version - set(_min_ver "18.0.31101") - if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) - message(FATAL_ERROR - "Visual Studio 2013 (Update 4, ${_min_ver}) required, " - "found (${CMAKE_CXX_COMPILER_VERSION})") + if(MSVC_VERSION EQUAL 1800) + set(_min_ver "18.0.31101") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) + message(FATAL_ERROR + "Visual Studio 2013 (Update 4, ${_min_ver}) required, " + "found (${CMAKE_CXX_COMPILER_VERSION})") + endif() + endif() + if(MSVC_VERSION EQUAL 1900) + set(_min_ver "19.0.24210") + if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${_min_ver}) + message(FATAL_ERROR + "Visual Studio 2015 (Update 3, ${_min_ver}) required, " + "found (${CMAKE_CXX_COMPILER_VERSION})") + endif() endif() unset(_min_ver) @@ -1353,17 +1363,6 @@ elseif(WIN32) set(PLATFORM_LINKFLAGS_DEBUG "/IGNORE:4099 /NODEFAULTLIB:libcmt.lib /NODEFAULTLIB:libc.lib") - # Use dynamic loading for OpenMP - if(WITH_OPENMP) - if(MSVC_VERSION EQUAL 1800) - set(OPENMP_DLL_NAME "vcomp120") - else() - set(OPENMP_DLL_NAME "vcomp140") - endif() - set(PLATFORM_LINKFLAGS "${PLATFORM_LINKFLAGS} /DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") - set(PLATFORM_LINKFLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG} /DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib") - endif() - if(NOT DEFINED LIBDIR) # Setup 64bit and 64bit windows systems @@ -3162,6 +3161,14 @@ add_subdirectory(tests) # CPack for generating packages include(build_files/cmake/packaging.cmake) +#----------------------------------------------------------------------------- +# Use dynamic loading for OpenMP +if(WITH_BLENDER) + openmp_delayload(blender) +endif(WITH_BLENDER) +if(WITH_PLAYER) + openmp_delayload(blenderplayer) +endif(WITH_PLAYER) #----------------------------------------------------------------------------- # Print Final Configuration diff --git a/GNUmakefile b/GNUmakefile index d9c895c214a..1fda1a25a92 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -182,14 +182,20 @@ help: .FORCE @echo " * package_archive - build an archive package" @echo "" @echo "Testing Targets (not associated with building blender)" - @echo " * test - run ctest, currently tests import/export, operator execution and that python modules load" - @echo " * test_cmake - runs our own cmake file checker which detects errors in the cmake file list definitions" - @echo " * test_pep8 - checks all python script are pep8 which are tagged to use the stricter formatting" + @echo " * test - run ctest, currently tests import/export," + @echo " operator execution and that python modules load" + @echo " * test_cmake - runs our own cmake file checker" + @echo " which detects errors in the cmake file list definitions" + @echo " * test_pep8 - checks all python script are pep8" + @echo " which are tagged to use the stricter formatting" @echo " * test_deprecated - checks for deprecation tags in our code which may need to be removed" - @echo " * test_style_c - checks C/C++ conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_c - checks C/C++ conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" @echo " * test_style_c_qtc - same as test_style but outputs QtCreator tasks format" - @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" - @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide: http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_osl - checks OpenShadingLanguage conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" + @echo " * test_style_osl_qtc - checks OpenShadingLanguage conforms with blenders style guide:" + @echo " http://wiki.blender.org/index.php/Dev:Doc/CodeStyle" @echo "" @echo "Static Source Code Checking (not associated with building blender)" @echo " * check_cppcheck - run blender source through cppcheck (C & C++)" @@ -405,7 +411,8 @@ update: .FORCE # Simple version of ./doc/python_api/sphinx_doc_gen.sh with no PDF generation. doc_py: .FORCE - "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/python_api/sphinx_doc_gen.py + "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \ + --python doc/python_api/sphinx_doc_gen.py cd doc/python_api ; sphinx-build -b html sphinx-in sphinx-out @echo "docs written into: '$(BLENDER_DIR)/doc/python_api/sphinx-out/contents.html'" @@ -414,7 +421,8 @@ doc_doxy: .FORCE @echo "docs written into: '$(BLENDER_DIR)/doc/doxygen/html/index.html'" doc_dna: .FORCE - "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup --python doc/blender_file_format/BlendFileDnaExporter_25.py + "$(BUILD_DIR)/bin/blender" --background -noaudio --factory-startup \ + --python doc/blender_file_format/BlendFileDnaExporter_25.py @echo "docs written into: '$(BLENDER_DIR)/doc/blender_file_format/dna.html'" doc_man: .FORCE diff --git a/build_files/build_environment/install_deps.sh b/build_files/build_environment/install_deps.sh index e380362a11e..068ac665623 100755 --- a/build_files/build_environment/install_deps.sh +++ b/build_files/build_environment/install_deps.sh @@ -321,7 +321,7 @@ LLVM_FORCE_REBUILD=false LLVM_SKIP=false # OSL needs to be compiled for now! -OSL_VERSION="1.7.1" +OSL_VERSION="1.7.3" OSL_VERSION_MIN=$OSL_VERSION OSL_FORCE_BUILD=false OSL_FORCE_REBUILD=false @@ -1742,7 +1742,7 @@ compile_OSL() { fi # To be changed each time we make edits that would modify the compiled result! - osl_magic=20 + osl_magic=21 _init_osl # Clean install if needed! diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake index fc9ac88f465..eb4282fd1d9 100644 --- a/build_files/cmake/macros.cmake +++ b/build_files/cmake/macros.cmake @@ -196,8 +196,33 @@ function(blender_source_group endfunction() +# Support per-target CMake flags +# Read from: CMAKE_C_FLAGS_**** (made upper case) when set. +# +# 'name' should alway match the target name, +# use this macro before add_library or add_executable. +# +# Optionally takes an arg passed to set(), eg PARENT_SCOPE. +macro(add_cc_flags_custom_test + name + ) + + string(TOUPPER ${name} _name_upper) + if(DEFINED CMAKE_C_FLAGS_${_name_upper}) + message(STATUS "Using custom CFLAGS: CMAKE_C_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CMAKE_C_FLAGS_${_name_upper}}" ${ARGV1}) + endif() + if(DEFINED CMAKE_CXX_FLAGS_${_name_upper}) + message(STATUS "Using custom CXXFLAGS: CMAKE_CXX_FLAGS_${_name_upper} in \"${CMAKE_CURRENT_SOURCE_DIR}\"") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${_name_upper}}" ${ARGV1}) + endif() + unset(_name_upper) + +endmacro() + + # only MSVC uses SOURCE_GROUP -function(blender_add_lib_nolist +function(blender_add_lib__impl name sources includes @@ -225,6 +250,18 @@ function(blender_add_lib_nolist endfunction() +function(blender_add_lib_nolist + name + sources + includes + includes_sys + ) + + add_cc_flags_custom_test(${name} PARENT_SCOPE) + + blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}") +endfunction() + function(blender_add_lib name sources @@ -232,7 +269,9 @@ function(blender_add_lib includes_sys ) - blender_add_lib_nolist(${name} "${sources}" "${includes}" "${includes_sys}") + add_cc_flags_custom_test(${name} PARENT_SCOPE) + + blender_add_lib__impl(${name} "${sources}" "${includes}" "${includes_sys}") set_property(GLOBAL APPEND PROPERTY BLENDER_LINK_LIBS ${name}) endfunction() @@ -1515,3 +1554,21 @@ function(print_all_vars) message("${_var}=${${_var}}") endforeach() endfunction() + +macro(openmp_delayload + projectname + ) + if(MSVC) + if(WITH_OPENMP) + if(MSVC_VERSION EQUAL 1800) + set(OPENMP_DLL_NAME "vcomp120") + else() + set(OPENMP_DLL_NAME "vcomp140") + endif() + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELEASE "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_DEBUG "/DELAYLOAD:${OPENMP_DLL_NAME}d.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + SET_TARGET_PROPERTIES(${projectname} PROPERTIES LINK_FLAGS_MINSIZEREL "/DELAYLOAD:${OPENMP_DLL_NAME}.dll delayimp.lib") + endif(WITH_OPENMP) + endif(MSVC) +endmacro() diff --git a/build_files/package_spec/pacman/PKGBUILD b/build_files/package_spec/pacman/PKGBUILD index 961e35578b9..aea5acd13e4 100644 --- a/build_files/package_spec/pacman/PKGBUILD +++ b/build_files/package_spec/pacman/PKGBUILD @@ -2,11 +2,9 @@ # custom blender vars blender_srcdir=$(dirname $startdir)"/../.." -# value may be formatted: 35042:35051M -blender_revision=$(svnversion $blender_srcdir | cut -d: -f2 | awk '{print $3}') -blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}') +blender_version=$(grep "BLENDER_VERSION\s" $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h | awk '{print $3}') blender_version=$(expr $blender_version / 100).$(expr $blender_version % 100) # 256 -> 2.56 -blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender.h) +blender_version_char=$(sed -ne 's/.*BLENDER_VERSION_CHAR.*\([a-z]\)$/\1/p' $blender_srcdir/source/blender/blenkernel/BKE_blender_version.h) # blender_subversion=$(grep BLENDER_SUBVERSION $blender_srcdir/source/blender/blenkernel/BKE_blender.h | awk '{print $3}') # map the version a -> 1 @@ -27,7 +25,9 @@ arch=('i686' 'x86_64') url="www.blender.org" license=('GPL') groups=() -depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.4' 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' 'libsndfile' 'ffmpeg') +depends=('libjpeg' 'libpng' 'openjpeg' 'libtiff' 'openexr' 'python>=3.5' + 'gettext' 'libxi' 'libxmu' 'mesa' 'freetype2' 'openal' 'sdl' + 'libsndfile' 'ffmpeg') makedepends=('cmake' 'git') optdepends=() provides=() diff --git a/doc/python_api/rst/bge.texture.rst b/doc/python_api/rst/bge.texture.rst index f5d325f7ce8..49f6c4469a4 100644 --- a/doc/python_api/rst/bge.texture.rst +++ b/doc/python_api/rst/bge.texture.rst @@ -1033,7 +1033,7 @@ Texture classes :type: bool - .. method:: refresh(refresh_source=True, timestamp=-1.0) + .. method:: refresh(refresh_source, timestamp=-1.0) Refresh texture from source. diff --git a/extern/CMakeLists.txt b/extern/CMakeLists.txt index 58e0c68148b..b046e9626b6 100644 --- a/extern/CMakeLists.txt +++ b/extern/CMakeLists.txt @@ -29,6 +29,14 @@ add_subdirectory(curve_fit_nd) # Otherwise we get warnings here that we cant fix in external projects remove_strict_flags() +# Not a strict flag, but noisy for code we don't maintain +if(CMAKE_COMPILER_IS_GNUCC) + remove_cc_flag( + "-Wmisleading-indentation" + ) +endif() + + add_subdirectory(rangetree) add_subdirectory(wcwidth) diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py index 140862721a8..193ef0cf505 100644 --- a/intern/cycles/blender/addon/properties.py +++ b/intern/cycles/blender/addon/properties.py @@ -503,6 +503,11 @@ class CyclesRenderSettings(bpy.types.PropertyGroup): description="Use BVH spatial splits: longer builder time, faster render", default=False, ) + cls.debug_use_hair_bvh = BoolProperty( + name="Use Hair BVH", + description="Use special type BVH optimized for hair. Uses more ram but renders faster", + default=True, + ) cls.tile_order = EnumProperty( name="Tile Order", description="Tile order for rendering", diff --git a/intern/cycles/blender/addon/ui.py b/intern/cycles/blender/addon/ui.py index 0961c349fc3..10c8959172d 100644 --- a/intern/cycles/blender/addon/ui.py +++ b/intern/cycles/blender/addon/ui.py @@ -383,7 +383,6 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): sub.prop(cscene, "use_progressive_refine") subsub = sub.column(align=True) - subsub.enabled = not rd.use_border subsub.prop(rd, "use_save_buffers") col = split.column(align=True) @@ -402,6 +401,7 @@ class CyclesRender_PT_performance(CyclesButtonsPanel, Panel): col.label(text="Acceleration structure:") col.prop(cscene, "debug_use_spatial_splits") + col.prop(cscene, "debug_use_hair_bvh") class CyclesRender_PT_layer_options(CyclesButtonsPanel, Panel): @@ -1663,104 +1663,62 @@ def draw_pause(self, context): def get_panels(): - types = bpy.types - panels = [ - "RENDER_PT_render", - "RENDER_PT_output", - "RENDER_PT_encoding", - "RENDER_PT_dimensions", - "RENDER_PT_stamp", - "RENDER_PT_freestyle", - "RENDERLAYER_PT_layers", - "RENDERLAYER_PT_freestyle", - "RENDERLAYER_PT_freestyle_lineset", - "RENDERLAYER_PT_freestyle_linestyle", - "SCENE_PT_scene", - "SCENE_PT_color_management", - "SCENE_PT_custom_props", - "SCENE_PT_audio", - "SCENE_PT_unit", - "SCENE_PT_keying_sets", - "SCENE_PT_keying_set_paths", - "SCENE_PT_physics", - "WORLD_PT_context_world", - "WORLD_PT_custom_props", - "DATA_PT_context_mesh", - "DATA_PT_context_camera", - "DATA_PT_context_lamp", - "DATA_PT_context_speaker", - "DATA_PT_normals", - "DATA_PT_texture_space", - "DATA_PT_curve_texture_space", - "DATA_PT_mball_texture_space", - "DATA_PT_vertex_groups", - "DATA_PT_shape_keys", - "DATA_PT_uv_texture", - "DATA_PT_vertex_colors", - "DATA_PT_camera", - "DATA_PT_camera_display", - "DATA_PT_camera_stereoscopy", - "DATA_PT_camera_safe_areas", - "DATA_PT_lens", - "DATA_PT_speaker", - "DATA_PT_distance", - "DATA_PT_cone", - "DATA_PT_customdata", - "DATA_PT_custom_props_mesh", - "DATA_PT_custom_props_camera", - "DATA_PT_custom_props_lamp", - "DATA_PT_custom_props_speaker", - "DATA_PT_custom_props_arm", - "DATA_PT_custom_props_curve", - "DATA_PT_custom_props_lattice", - "DATA_PT_custom_props_metaball", - "TEXTURE_PT_preview", - "TEXTURE_PT_custom_props", - "TEXTURE_PT_clouds", - "TEXTURE_PT_wood", - "TEXTURE_PT_marble", - "TEXTURE_PT_magic", - "TEXTURE_PT_blend", - "TEXTURE_PT_stucci", - "TEXTURE_PT_image", - "TEXTURE_PT_image_sampling", - "TEXTURE_PT_image_mapping", - "TEXTURE_PT_musgrave", - "TEXTURE_PT_voronoi", - "TEXTURE_PT_distortednoise", - "TEXTURE_PT_voxeldata", - "TEXTURE_PT_pointdensity", - "TEXTURE_PT_pointdensity_turbulence", - "TEXTURE_PT_mapping", - "TEXTURE_PT_ocean", - "TEXTURE_PT_influence", - "TEXTURE_PT_colors", - "PARTICLE_PT_context_particles", - "PARTICLE_PT_custom_props", - "PARTICLE_PT_emission", - "PARTICLE_PT_hair_dynamics", - "PARTICLE_PT_cache", - "PARTICLE_PT_velocity", - "PARTICLE_PT_rotation", - "PARTICLE_PT_physics", - "SCENE_PT_rigid_body_world", - "SCENE_PT_rigid_body_cache", - "SCENE_PT_rigid_body_field_weights", - "PARTICLE_PT_boidbrain", - "PARTICLE_PT_render", - "PARTICLE_PT_draw", - "PARTICLE_PT_children", - "PARTICLE_PT_field_weights", - "PARTICLE_PT_force_fields", - "PARTICLE_PT_vertexgroups", - "MATERIAL_PT_custom_props", - "MATERIAL_PT_freestyle_line", - "BONE_PT_custom_props", - "OBJECT_PT_custom_props", - ] - - return [getattr(types, p) for p in panels if hasattr(types, p)] - + exclude_panels = { + 'DATA_PT_area', + 'DATA_PT_camera_dof', + 'DATA_PT_falloff_curve', + 'DATA_PT_lamp', + 'DATA_PT_preview', + 'DATA_PT_shadow', + 'DATA_PT_spot', + 'DATA_PT_sunsky', + 'MATERIAL_PT_context_material', + 'MATERIAL_PT_diffuse', + 'MATERIAL_PT_flare', + 'MATERIAL_PT_halo', + 'MATERIAL_PT_mirror', + 'MATERIAL_PT_options', + 'MATERIAL_PT_pipeline', + 'MATERIAL_PT_preview', + 'MATERIAL_PT_shading', + 'MATERIAL_PT_shadow', + 'MATERIAL_PT_specular', + 'MATERIAL_PT_sss', + 'MATERIAL_PT_strand', + 'MATERIAL_PT_transp', + 'MATERIAL_PT_volume_density', + 'MATERIAL_PT_volume_integration', + 'MATERIAL_PT_volume_lighting', + 'MATERIAL_PT_volume_options', + 'MATERIAL_PT_volume_shading', + 'MATERIAL_PT_volume_transp', + 'RENDERLAYER_PT_layer_options', + 'RENDERLAYER_PT_layer_passes', + 'RENDERLAYER_PT_views', + 'RENDER_PT_antialiasing', + 'RENDER_PT_bake', + 'RENDER_PT_motion_blur', + 'RENDER_PT_performance', + 'RENDER_PT_post_processing', + 'RENDER_PT_shading', + 'SCENE_PT_simplify', + 'TEXTURE_PT_context_texture', + 'WORLD_PT_ambient_occlusion', + 'WORLD_PT_environment_lighting', + 'WORLD_PT_gather', + 'WORLD_PT_indirect_lighting', + 'WORLD_PT_mist', + 'WORLD_PT_preview', + 'WORLD_PT_world' + } + + panels = [] + for panel in bpy.types.Panel.__subclasses__(): + if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES: + if panel.__name__ not in exclude_panels: + panels.append(panel) + + return panels def register(): bpy.types.RENDER_PT_render.append(draw_device) @@ -1769,10 +1727,10 @@ def register(): for panel in get_panels(): panel.COMPAT_ENGINES.add('CYCLES') - def unregister(): bpy.types.RENDER_PT_render.remove(draw_device) bpy.types.VIEW3D_HT_header.remove(draw_pause) for panel in get_panels(): - panel.COMPAT_ENGINES.remove('CYCLES') + if 'CYCLES' in panel.COMPAT_ENGINES: + panel.COMPAT_ENGINES.remove('CYCLES') diff --git a/intern/cycles/blender/blender_mesh.cpp b/intern/cycles/blender/blender_mesh.cpp index 80db51148e6..ec11a893b5a 100644 --- a/intern/cycles/blender/blender_mesh.cpp +++ b/intern/cycles/blender/blender_mesh.cpp @@ -680,6 +680,43 @@ static void create_subd_mesh(Scene *scene, /* Sync */ +static void sync_mesh_fluid_motion(BL::Object& b_ob, Scene *scene, Mesh *mesh) +{ + if(scene->need_motion() == Scene::MOTION_NONE) + return; + + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + + if(!b_fluid_domain) + return; + + /* If the mesh has modifiers following the fluid domain we can't export motion. */ + if(b_fluid_domain.fluid_mesh_vertices.length() != mesh->verts.size()) + return; + + /* Find or add attribute */ + float3 *P = &mesh->verts[0]; + Attribute *attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if(!attr_mP) { + attr_mP = mesh->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + float relative_time = motion_times[step] * scene->motion_shutter_time() * 0.5f; + float3 *mP = attr_mP->data_float3() + step*mesh->verts.size(); + + BL::DomainFluidSettings::fluid_mesh_vertices_iterator fvi; + int i = 0; + + for(b_fluid_domain.fluid_mesh_vertices.begin(fvi); fvi != b_fluid_domain.fluid_mesh_vertices.end(); ++fvi, ++i) { + mP[i] = P[i] + get_float3(fvi->velocity()) * relative_time; + } + } +} + Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, bool object_updated, bool hide_tris) @@ -801,7 +838,7 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, } /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } } mesh->geometry_flags = requested_geometry_flags; @@ -821,6 +858,9 @@ Mesh *BlenderSync::sync_mesh(BL::Object& b_ob, mesh->displacement_method = Mesh::DISPLACE_BOTH; } + /* fluid motion */ + sync_mesh_fluid_motion(b_ob, scene, mesh); + /* tag update */ bool rebuild = false; @@ -910,6 +950,11 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, * would need a more extensive check to see which objects are animated */ BL::Mesh b_mesh(PointerRNA_NULL); + /* fluid motion is exported immediate with mesh, skip here */ + BL::DomainFluidSettings b_fluid_domain = object_fluid_domain_find(b_ob); + if (b_fluid_domain) + return; + if(ccl::BKE_object_is_deform_modified(b_ob, b_scene, preview)) { /* get derived mesh */ b_mesh = object_to_mesh(b_data, b_ob, b_scene, true, !preview, false); @@ -1013,7 +1058,7 @@ void BlenderSync::sync_mesh_motion(BL::Object& b_ob, sync_curves(mesh, b_mesh, b_ob, true, time_index); /* free derived mesh */ - b_data.meshes.remove(b_mesh); + b_data.meshes.remove(b_mesh, false); } CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_object.cpp b/intern/cycles/blender/blender_object.cpp index 80768c096e3..22a0b3988c8 100644 --- a/intern/cycles/blender/blender_object.cpp +++ b/intern/cycles/blender/blender_object.cpp @@ -253,11 +253,10 @@ static bool object_boundbox_clip(Scene *scene, boundbox[3 * i + 1], boundbox[3 * i + 2]); p = transform_point(&tfm, p); - p = transform_point(&worldtondc, p); + p = transform_perspective(&worldtondc, p); if(p.z >= -margin) { all_behind = false; } - p /= p.z; bb_min = min(bb_min, p); bb_max = max(bb_max, p); } @@ -720,12 +719,7 @@ void BlenderSync::sync_motion(BL::RenderSettings& b_render, << relative_time << "."; /* fixed shutter time to get previous and next frame for motion pass */ - float shuttertime; - - if(scene->need_motion() == Scene::MOTION_PASS) - shuttertime = 2.0f; - else - shuttertime = scene->camera->shuttertime; + float shuttertime = scene->motion_shutter_time(); /* compute frame and subframe time */ float time = frame_center + frame_center_delta + relative_time * shuttertime * 0.5f; diff --git a/intern/cycles/blender/blender_shader.cpp b/intern/cycles/blender/blender_shader.cpp index 78a28b7feed..64559804ccb 100644 --- a/intern/cycles/blender/blender_shader.cpp +++ b/intern/cycles/blender/blender_shader.cpp @@ -393,6 +393,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfAnisotropic::distribution_GGX: aniso->distribution = CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID; break; + case BL::ShaderNodeBsdfAnisotropic::distribution_MULTI_GGX: + aniso->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID; + break; case BL::ShaderNodeBsdfAnisotropic::distribution_ASHIKHMIN_SHIRLEY: aniso->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; break; @@ -437,7 +440,10 @@ static ShaderNode *add_node(Scene *scene, glossy->distribution = CLOSURE_BSDF_MICROFACET_GGX_ID; break; case BL::ShaderNodeBsdfGlossy::distribution_ASHIKHMIN_SHIRLEY: - glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID; + glossy->distribution = CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID; + break; + case BL::ShaderNodeBsdfGlossy::distribution_MULTI_GGX: + glossy->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; break; } node = glossy; @@ -455,6 +461,9 @@ static ShaderNode *add_node(Scene *scene, case BL::ShaderNodeBsdfGlass::distribution_GGX: glass->distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID; break; + case BL::ShaderNodeBsdfGlass::distribution_MULTI_GGX: + glass->distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + break; } node = glass; } diff --git a/intern/cycles/blender/blender_sync.cpp b/intern/cycles/blender/blender_sync.cpp index 33084f1c163..e7e57b2be36 100644 --- a/intern/cycles/blender/blender_sync.cpp +++ b/intern/cycles/blender/blender_sync.cpp @@ -492,6 +492,7 @@ SceneParams BlenderSync::get_scene_params(BL::Scene& b_scene, SceneParams::BVH_STATIC); params.use_bvh_spatial_split = RNA_boolean_get(&cscene, "debug_use_spatial_splits"); + params.use_bvh_unaligned_nodes = RNA_boolean_get(&cscene, "debug_use_hair_bvh"); if(background && params.shadingsystem != SHADINGSYSTEM_OSL) params.persistent_data = r.use_persistent_data(); diff --git a/intern/cycles/blender/blender_sync.h b/intern/cycles/blender/blender_sync.h index d690adb5662..b8b9597914e 100644 --- a/intern/cycles/blender/blender_sync.h +++ b/intern/cycles/blender/blender_sync.h @@ -131,7 +131,9 @@ private: Transform& tfm, bool *use_portal); void sync_background_light(bool use_portal); - void sync_mesh_motion(BL::Object& b_ob, Object *object, float motion_time); + void sync_mesh_motion(BL::Object& b_ob, + Object *object, + float motion_time); void sync_camera_motion(BL::RenderSettings& b_render, BL::Object& b_ob, int width, int height, diff --git a/intern/cycles/blender/blender_util.h b/intern/cycles/blender/blender_util.h index 2510cebcdc0..188d23d0c59 100644 --- a/intern/cycles/blender/blender_util.h +++ b/intern/cycles/blender/blender_util.h @@ -519,6 +519,23 @@ static inline BL::SmokeDomainSettings object_smoke_domain_find(BL::Object& b_ob) return BL::SmokeDomainSettings(PointerRNA_NULL); } +static inline BL::DomainFluidSettings object_fluid_domain_find(BL::Object b_ob) +{ + BL::Object::modifiers_iterator b_mod; + + for(b_ob.modifiers.begin(b_mod); b_mod != b_ob.modifiers.end(); ++b_mod) { + if(b_mod->is_a(&RNA_FluidSimulationModifier)) { + BL::FluidSimulationModifier b_fmd(*b_mod); + BL::FluidSettings fss = b_fmd.settings(); + + if(fss.type() == BL::FluidSettings::type_DOMAIN) + return (BL::DomainFluidSettings)b_fmd.settings(); + } + } + + return BL::DomainFluidSettings(PointerRNA_NULL); +} + /* ID Map * * Utility class to keep in sync with blender data. diff --git a/intern/cycles/bvh/CMakeLists.txt b/intern/cycles/bvh/CMakeLists.txt index 5729fa6113d..92e48f0d87f 100644 --- a/intern/cycles/bvh/CMakeLists.txt +++ b/intern/cycles/bvh/CMakeLists.txt @@ -19,6 +19,7 @@ set(SRC bvh_node.cpp bvh_sort.cpp bvh_split.cpp + bvh_unaligned.cpp ) set(SRC_HEADERS @@ -29,6 +30,7 @@ set(SRC_HEADERS bvh_params.h bvh_sort.h bvh_split.h + bvh_unaligned.h ) include_directories(${INC}) diff --git a/intern/cycles/bvh/bvh.cpp b/intern/cycles/bvh/bvh.cpp index fa2b9ae7279..1bb3e95c810 100644 --- a/intern/cycles/bvh/bvh.cpp +++ b/intern/cycles/bvh/bvh.cpp @@ -24,6 +24,7 @@ #include "bvh_build.h" #include "bvh_node.h" #include "bvh_params.h" +#include "bvh_unaligned.h" #include "util_debug.h" #include "util_foreach.h" @@ -121,7 +122,7 @@ void BVH::refit(Progress& progress) /* Triangles */ -void BVH::pack_triangle(int idx, float4 storage[3]) +void BVH::pack_triangle(int idx, float4 tri_verts[3]) { int tob = pack.prim_object[idx]; assert(tob >= 0 && tob < objects.size()); @@ -129,49 +130,58 @@ void BVH::pack_triangle(int idx, float4 storage[3]) int tidx = pack.prim_index[idx]; Mesh::Triangle t = mesh->get_triangle(tidx); - const float3* vpos = &mesh->verts[0]; + const float3 *vpos = &mesh->verts[0]; float3 v0 = vpos[t.v[0]]; float3 v1 = vpos[t.v[1]]; float3 v2 = vpos[t.v[2]]; - storage[0] = float3_to_float4(v0); - storage[1] = float3_to_float4(v1); - storage[2] = float3_to_float4(v2); + tri_verts[0] = float3_to_float4(v0); + tri_verts[1] = float3_to_float4(v1); + tri_verts[2] = float3_to_float4(v2); } void BVH::pack_primitives() { - int nsize = TRI_NODE_SIZE; - size_t tidx_size = pack.prim_index.size(); - - pack.tri_storage.clear(); - pack.tri_storage.resize(tidx_size * nsize); + const size_t tidx_size = pack.prim_index.size(); + size_t num_prim_triangles = 0; + /* Count number of triangles primitives in BVH. */ + for(unsigned int i = 0; i < tidx_size; i++) { + if((pack.prim_index[i] != -1)) { + if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + ++num_prim_triangles; + } + } + } + /* Reserve size for arrays. */ + pack.prim_tri_index.clear(); + pack.prim_tri_index.resize(tidx_size); + pack.prim_tri_verts.clear(); + pack.prim_tri_verts.resize(num_prim_triangles * 3); pack.prim_visibility.clear(); pack.prim_visibility.resize(tidx_size); - + /* Fill in all the arrays. */ + size_t prim_triangle_index = 0; for(unsigned int i = 0; i < tidx_size; i++) { if(pack.prim_index[i] != -1) { - float4 storage[3]; + int tob = pack.prim_object[i]; + Object *ob = objects[tob]; - if(pack.prim_type[i] & PRIMITIVE_TRIANGLE) { - pack_triangle(i, storage); + if((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + pack_triangle(i, (float4*)&pack.prim_tri_verts[3 * prim_triangle_index]); + pack.prim_tri_index[i] = 3 * prim_triangle_index; + ++prim_triangle_index; } else { - /* Avoid use of uninitialized memory. */ - memset(&storage, 0, sizeof(storage)); + pack.prim_tri_index[i] = -1; } - memcpy(&pack.tri_storage[i * nsize], storage, sizeof(float4)*3); - - int tob = pack.prim_object[i]; - Object *ob = objects[tob]; pack.prim_visibility[i] = ob->visibility; if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) pack.prim_visibility[i] |= PATH_RAY_CURVE; } else { - memset(&pack.tri_storage[i * nsize], 0, sizeof(float4)*3); + pack.prim_tri_index[i] = -1; pack.prim_visibility[i] = 0; } } @@ -183,13 +193,13 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) { /* The BVH's for instances are built separately, but for traversal all * BVH's are stored in global arrays. This function merges them into the - * top level BVH, adjusting indexes and offsets where appropriate. */ - bool use_qbvh = params.use_qbvh; - size_t nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE; - size_t nsize_leaf = (use_qbvh)? BVH_QNODE_LEAF_SIZE: BVH_NODE_LEAF_SIZE; + * top level BVH, adjusting indexes and offsets where appropriate. + */ + const bool use_qbvh = params.use_qbvh; - /* adjust primitive index to point to the triangle in the global array, for - * meshes with transform applied and already in the top level BVH */ + /* Adjust primitive index to point to the triangle in the global array, for + * meshes with transform applied and already in the top level BVH. + */ for(size_t i = 0; i < pack.prim_index.size(); i++) if(pack.prim_index[i] != -1) { if(pack.prim_type[i] & PRIMITIVE_ALL_CURVE) @@ -208,10 +218,10 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) /* reserve */ size_t prim_index_size = pack.prim_index.size(); - size_t tri_storage_size = pack.tri_storage.size(); + size_t prim_tri_verts_size = pack.prim_tri_verts.size(); size_t pack_prim_index_offset = prim_index_size; - size_t pack_tri_storage_offset = tri_storage_size; + size_t pack_prim_tri_verts_offset = prim_tri_verts_size; size_t pack_nodes_offset = nodes_size; size_t pack_leaf_nodes_offset = leaf_nodes_size; size_t object_offset = 0; @@ -225,7 +235,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) if(mesh->need_build_bvh()) { if(mesh_map.find(mesh) == mesh_map.end()) { prim_index_size += bvh->pack.prim_index.size(); - tri_storage_size += bvh->pack.tri_storage.size(); + prim_tri_verts_size += bvh->pack.prim_tri_verts.size(); nodes_size += bvh->pack.nodes.size(); leaf_nodes_size += bvh->pack.leaf_nodes.size(); @@ -240,7 +250,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) pack.prim_type.resize(prim_index_size); pack.prim_object.resize(prim_index_size); pack.prim_visibility.resize(prim_index_size); - pack.tri_storage.resize(tri_storage_size); + pack.prim_tri_verts.resize(prim_tri_verts_size); + pack.prim_tri_index.resize(prim_index_size); pack.nodes.resize(nodes_size); pack.leaf_nodes.resize(leaf_nodes_size); pack.object_node.resize(objects.size()); @@ -249,7 +260,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) int *pack_prim_type = (pack.prim_type.size())? &pack.prim_type[0]: NULL; int *pack_prim_object = (pack.prim_object.size())? &pack.prim_object[0]: NULL; uint *pack_prim_visibility = (pack.prim_visibility.size())? &pack.prim_visibility[0]: NULL; - float4 *pack_tri_storage = (pack.tri_storage.size())? &pack.tri_storage[0]: NULL; + float4 *pack_prim_tri_verts = (pack.prim_tri_verts.size())? &pack.prim_tri_verts[0]: NULL; + uint *pack_prim_tri_index = (pack.prim_tri_index.size())? &pack.prim_tri_index[0]: NULL; int4 *pack_nodes = (pack.nodes.size())? &pack.nodes[0]: NULL; int4 *pack_leaf_nodes = (pack.leaf_nodes.size())? &pack.leaf_nodes[0]: NULL; @@ -277,8 +289,8 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) BVH *bvh = mesh->bvh; - int noffset = nodes_offset/nsize; - int noffset_leaf = nodes_leaf_offset/nsize_leaf; + int noffset = nodes_offset; + int noffset_leaf = nodes_leaf_offset; int mesh_tri_offset = mesh->tri_offset; int mesh_curve_offset = mesh->curve_offset; @@ -290,18 +302,24 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) mesh_map[mesh] = pack.object_node[object_offset-1]; - /* merge primitive and object indexes */ + /* merge primitive, object and triangle indexes */ if(bvh->pack.prim_index.size()) { size_t bvh_prim_index_size = bvh->pack.prim_index.size(); int *bvh_prim_index = &bvh->pack.prim_index[0]; int *bvh_prim_type = &bvh->pack.prim_type[0]; uint *bvh_prim_visibility = &bvh->pack.prim_visibility[0]; + uint *bvh_prim_tri_index = &bvh->pack.prim_tri_index[0]; for(size_t i = 0; i < bvh_prim_index_size; i++) { - if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) + if(bvh->pack.prim_type[i] & PRIMITIVE_ALL_CURVE) { pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_curve_offset; - else + pack_prim_tri_index[pack_prim_index_offset] = -1; + } + else { pack_prim_index[pack_prim_index_offset] = bvh_prim_index[i] + mesh_tri_offset; + pack_prim_tri_index[pack_prim_index_offset] = + bvh_prim_tri_index[i] + pack_prim_tri_verts_offset; + } pack_prim_type[pack_prim_index_offset] = bvh_prim_type[i]; pack_prim_visibility[pack_prim_index_offset] = bvh_prim_visibility[i]; @@ -310,50 +328,64 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) } } - /* merge triangle intersection data */ - if(bvh->pack.tri_storage.size()) { - memcpy(pack_tri_storage + pack_tri_storage_offset, - &bvh->pack.tri_storage[0], - bvh->pack.tri_storage.size()*sizeof(float4)); - pack_tri_storage_offset += bvh->pack.tri_storage.size(); + /* Merge triangle vertices data. */ + if(bvh->pack.prim_tri_verts.size()) { + const size_t prim_tri_size = bvh->pack.prim_tri_verts.size(); + memcpy(pack_prim_tri_verts + pack_prim_tri_verts_offset, + &bvh->pack.prim_tri_verts[0], + prim_tri_size*sizeof(float4)); + pack_prim_tri_verts_offset += prim_tri_size; } /* merge nodes */ if(bvh->pack.leaf_nodes.size()) { int4 *leaf_nodes_offset = &bvh->pack.leaf_nodes[0]; size_t leaf_nodes_offset_size = bvh->pack.leaf_nodes.size(); - for(size_t i = 0, j = 0; i < leaf_nodes_offset_size; i+=nsize_leaf, j++) { + for(size_t i = 0, j = 0; + i < leaf_nodes_offset_size; + i+= BVH_NODE_LEAF_SIZE, j++) + { int4 data = leaf_nodes_offset[i]; data.x += prim_offset; data.y += prim_offset; pack_leaf_nodes[pack_leaf_nodes_offset] = data; - for(int j = 1; j < nsize_leaf; ++j) { + for(int j = 1; j < BVH_NODE_LEAF_SIZE; ++j) { pack_leaf_nodes[pack_leaf_nodes_offset + j] = leaf_nodes_offset[i + j]; } - pack_leaf_nodes_offset += nsize_leaf; + pack_leaf_nodes_offset += BVH_NODE_LEAF_SIZE; } } if(bvh->pack.nodes.size()) { - /* For QBVH we're packing a child bbox into 6 float4, - * and for regular BVH they're packed into 3 float4. - */ - size_t nsize_bbox = (use_qbvh)? 6: 3; int4 *bvh_nodes = &bvh->pack.nodes[0]; - size_t bvh_nodes_size = bvh->pack.nodes.size(); + size_t bvh_nodes_size = bvh->pack.nodes.size(); + + for(size_t i = 0, j = 0; i < bvh_nodes_size; j++) { + size_t nsize, nsize_bbox; + if(bvh_nodes[i].x & PATH_RAY_NODE_UNALIGNED) { + nsize = use_qbvh + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_UNALIGNED_NODE_SIZE; + nsize_bbox = (use_qbvh)? 13: 0; + } + else { + nsize = (use_qbvh)? BVH_QNODE_SIZE: BVH_NODE_SIZE; + nsize_bbox = (use_qbvh)? 7: 0; + } - for(size_t i = 0, j = 0; i < bvh_nodes_size; i+=nsize, j++) { - memcpy(pack_nodes + pack_nodes_offset, bvh_nodes + i, nsize_bbox*sizeof(int4)); + memcpy(pack_nodes + pack_nodes_offset, + bvh_nodes + i, + nsize_bbox*sizeof(int4)); - /* modify offsets into arrays */ + /* Modify offsets into arrays */ int4 data = bvh_nodes[i + nsize_bbox]; - data.x += (data.x < 0)? -noffset_leaf: noffset; - data.y += (data.y < 0)? -noffset_leaf: noffset; + data.z += (data.z < 0)? -noffset_leaf: noffset; + data.w += (data.w < 0)? -noffset_leaf: noffset; if(use_qbvh) { - data.z += (data.z < 0)? -noffset_leaf: noffset; - data.w += (data.w < 0)? -noffset_leaf: noffset; + data.x += (data.x < 0)? -noffset_leaf: noffset; + data.y += (data.y < 0)? -noffset_leaf: noffset; } pack_nodes[pack_nodes_offset + nsize_bbox] = data; @@ -366,6 +398,7 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) sizeof(int4) * (nsize - (nsize_bbox+1))); pack_nodes_offset += nsize; + i += nsize; } } @@ -377,12 +410,20 @@ void BVH::pack_instances(size_t nodes_size, size_t leaf_nodes_size) /* Regular BVH */ +static bool node_bvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + return node0->is_unaligned() || node1->is_unaligned(); +} + RegularBVH::RegularBVH(const BVHParams& params_, const vector<Object*>& objects_) : BVH(params_, objects_) { } -void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) +void RegularBVH::pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf) { float4 data[BVH_NODE_LEAF_SIZE]; memset(data, 0, sizeof(data)); @@ -401,54 +442,130 @@ void RegularBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); } - memcpy(&pack.leaf_nodes[e.idx * BVH_NODE_LEAF_SIZE], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_NODE_LEAF_SIZE); +} + +void RegularBVH::pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) +{ + if (e0.node->is_unaligned() || e1.node->is_unaligned()) { + pack_unaligned_inner(e, e0, e1); + } else { + pack_aligned_inner(e, e0, e1); + } } -void RegularBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1) +void RegularBVH::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) { - pack_node(e.idx, e0.node->m_bounds, e1.node->m_bounds, e0.encodeIdx(), e1.encodeIdx(), e0.node->m_visibility, e1.node->m_visibility); + pack_aligned_node(e.idx, + e0.node->m_bounds, e1.node->m_bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->m_visibility, e1.node->m_visibility); } -void RegularBVH::pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1) +void RegularBVH::pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1) { int4 data[BVH_NODE_SIZE] = { + make_int4(visibility0 & ~PATH_RAY_NODE_UNALIGNED, + visibility1 & ~PATH_RAY_NODE_UNALIGNED, c0, c1), make_int4(__float_as_int(b0.min.x), __float_as_int(b1.min.x), __float_as_int(b0.max.x), __float_as_int(b1.max.x)), make_int4(__float_as_int(b0.min.y), __float_as_int(b1.min.y), __float_as_int(b0.max.y), __float_as_int(b1.max.y)), make_int4(__float_as_int(b0.min.z), __float_as_int(b1.min.z), __float_as_int(b0.max.z), __float_as_int(b1.max.z)), - make_int4(c0, c1, visibility0, visibility1) }; - memcpy(&pack.nodes[idx * BVH_NODE_SIZE], data, sizeof(int4)*BVH_NODE_SIZE); + memcpy(&pack.nodes[idx], data, sizeof(int4)*BVH_NODE_SIZE); } -void RegularBVH::pack_nodes(const BVHNode *root) +void RegularBVH::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1) { - size_t tot_node_size = root->getSubtreeSize(BVH_STAT_NODE_COUNT); - size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - size_t node_size = tot_node_size - leaf_node_size; + pack_unaligned_node(e.idx, + e0.node->get_aligned_space(), + e1.node->get_aligned_space(), + e0.node->m_bounds, + e1.node->m_bounds, + e0.encodeIdx(), e1.encodeIdx(), + e0.node->m_visibility, e1.node->m_visibility); +} - /* resize arrays */ - pack.nodes.clear(); +void RegularBVH::pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& bounds0, + const BoundBox& bounds1, + int c0, int c1, + uint visibility0, uint visibility1) +{ + float4 data[BVH_UNALIGNED_NODE_SIZE]; + Transform space0 = BVHUnaligned::compute_node_transform(bounds0, + aligned_space0); + Transform space1 = BVHUnaligned::compute_node_transform(bounds1, + aligned_space1); + data[0] = make_float4(__int_as_float(visibility0 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(visibility1 | PATH_RAY_NODE_UNALIGNED), + __int_as_float(c0), + __int_as_float(c1)); + + data[1] = space0.x; + data[2] = space0.y; + data[3] = space0.z; + data[4] = space1.x; + data[5] = space1.y; + data[6] = space1.z; + + memcpy(&pack.nodes[idx], data, sizeof(float4)*BVH_UNALIGNED_NODE_SIZE); +} - /* for top level BVH, first merge existing BVH's so we know the offsets */ +void RegularBVH::pack_nodes(const BVHNode *root) +{ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_NODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_NODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_NODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_NODE_SIZE; + } + /* Resize arrays */ + pack.nodes.clear(); + pack.leaf_nodes.clear(); + /* For top level BVH, first merge existing BVH's so we know the offsets. */ if(params.top_level) { - pack_instances(node_size*BVH_NODE_SIZE, - leaf_node_size*BVH_NODE_LEAF_SIZE); + pack_instances(node_size, num_leaf_nodes*BVH_NODE_LEAF_SIZE); } else { - pack.nodes.resize(node_size*BVH_NODE_SIZE); - pack.leaf_nodes.resize(leaf_node_size*BVH_NODE_LEAF_SIZE); + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_NODE_LEAF_SIZE); } int nextNodeIdx = 0, nextLeafNodeIdx = 0; vector<BVHStackEntry> stack; stack.reserve(BVHParams::MAX_DEPTH*2); - if(root->is_leaf()) + if(root->is_leaf()) { stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); - else - stack.push_back(BVHStackEntry(root, nextNodeIdx++)); + } + else { + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_bvh_is_unaligned(root) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } while(stack.size()) { BVHStackEntry e = stack.back(); @@ -456,20 +573,31 @@ void RegularBVH::pack_nodes(const BVHNode *root) if(e.node->is_leaf()) { /* leaf node */ - const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node); + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); pack_leaf(e, leaf); } else { /* innner node */ - int idx0 = (e.node->get_child(0)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++); - int idx1 = (e.node->get_child(1)->is_leaf())? (nextLeafNodeIdx++) : (nextNodeIdx++); - stack.push_back(BVHStackEntry(e.node->get_child(0), idx0)); - stack.push_back(BVHStackEntry(e.node->get_child(1), idx1)); + int idx[2]; + for (int i = 0; i < 2; ++i) { + if (e.node->get_child(i)->is_leaf()) { + idx[i] = nextLeafNodeIdx++; + } + else { + idx[i] = nextNodeIdx; + nextNodeIdx += node_bvh_is_unaligned(e.node->get_child(i)) + ? BVH_UNALIGNED_NODE_SIZE + : BVH_NODE_SIZE; + } + } + + stack.push_back(BVHStackEntry(e.node->get_child(0), idx[0])); + stack.push_back(BVHStackEntry(e.node->get_child(1), idx[1])); pack_inner(e, stack[stack.size()-2], stack[stack.size()-1]); } } - + assert(node_size == nextNodeIdx); /* root index to start traversal at, to handle case of single leaf node */ pack.root_index = (root->is_leaf())? -1: 0; } @@ -486,7 +614,7 @@ void RegularBVH::refit_nodes() void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { if(leaf) { - int4 *data = &pack.leaf_nodes[idx*BVH_NODE_LEAF_SIZE]; + int4 *data = &pack.leaf_nodes[idx]; int c0 = data[0].x; int c1 = data[0].y; /* refit leaf node */ @@ -560,14 +688,12 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility leaf_data[0].y = __int_as_float(c1); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(data[0].w); - memcpy(&pack.leaf_nodes[idx * BVH_NODE_LEAF_SIZE], - leaf_data, - sizeof(float4)*BVH_NODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_NODE_LEAF_SIZE); } else { - int4 *data = &pack.nodes[idx*BVH_NODE_SIZE]; - int c0 = data[3].x; - int c1 = data[3].y; + int4 *data = &pack.nodes[idx]; + int c0 = data[0].z; + int c1 = data[0].w; /* refit inner node, set bbox from children */ BoundBox bbox0 = BoundBox::empty, bbox1 = BoundBox::empty; uint visibility0 = 0, visibility1 = 0; @@ -575,7 +701,7 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility refit_node((c0 < 0)? -c0-1: c0, (c0 < 0), bbox0, visibility0); refit_node((c1 < 0)? -c1-1: c1, (c1 < 0), bbox1, visibility1); - pack_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1); + pack_aligned_node(idx, bbox0, bbox1, c0, c1, visibility0, visibility1); bbox.grow(bbox0); bbox.grow(bbox1); @@ -585,6 +711,33 @@ void RegularBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility /* QBVH */ +/* Can we avoid this somehow or make more generic? + * + * Perhaps we can merge nodes in actual tree and make our + * life easier all over the place. + */ +static bool node_qbvh_is_unaligned(const BVHNode *node) +{ + const BVHNode *node0 = node->get_child(0), + *node1 = node->get_child(1); + bool has_unaligned = false; + if(node0->is_leaf()) { + has_unaligned |= node0->is_unaligned(); + } + else { + has_unaligned |= node0->get_child(0)->is_unaligned(); + has_unaligned |= node0->get_child(1)->is_unaligned(); + } + if(node1->is_leaf()) { + has_unaligned |= node1->is_unaligned(); + } + else { + has_unaligned |= node1->get_child(0)->is_unaligned(); + has_unaligned |= node1->get_child(1)->is_unaligned(); + } + return has_unaligned; +} + QBVH::QBVH(const BVHParams& params_, const vector<Object*>& objects_) : BVH(params_, objects_) { @@ -610,66 +763,153 @@ void QBVH::pack_leaf(const BVHStackEntry& e, const LeafNode *leaf) data[0].w = __uint_as_float(pack.prim_type[leaf->m_lo]); } - memcpy(&pack.leaf_nodes[e.idx * BVH_QNODE_LEAF_SIZE], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[e.idx], data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); +} + +void QBVH::pack_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + bool has_unaligned = false; + /* Check whether we have to create unaligned node or all nodes are aligned + * and we can cut some corner here. + */ + if(params.use_unaligned_nodes) { + for(int i = 0; i < num; i++) { + if(en[i].node->is_unaligned()) { + has_unaligned = true; + break; + } + } + } + if(has_unaligned) { + /* There's no unaligned children, pack into AABB node. */ + pack_unaligned_inner(e, en, num); + } + else { + /* Create unaligned node with orientation transform for each of the + * children. + */ + pack_aligned_inner(e, en, num); + } } -void QBVH::pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num) +void QBVH::pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) { float4 data[BVH_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + data[0].x = __uint_as_float(e.node->m_visibility & ~PATH_RAY_NODE_UNALIGNED); for(int i = 0; i < num; i++) { float3 bb_min = en[i].node->m_bounds.min; float3 bb_max = en[i].node->m_bounds.max; - data[0][i] = bb_min.x; - data[1][i] = bb_max.x; - data[2][i] = bb_min.y; - data[3][i] = bb_max.y; - data[4][i] = bb_min.z; - data[5][i] = bb_max.z; + data[1][i] = bb_min.x; + data[2][i] = bb_max.x; + data[3][i] = bb_min.y; + data[4][i] = bb_max.y; + data[5][i] = bb_min.z; + data[6][i] = bb_max.z; - data[6][i] = __int_as_float(en[i].encodeIdx()); + data[7][i] = __int_as_float(en[i].encodeIdx()); } for(int i = num; i < 4; i++) { /* We store BB which would never be recorded as intersection * so kernel might safely assume there are always 4 child nodes. */ - data[0][i] = FLT_MAX; - data[1][i] = -FLT_MAX; + data[1][i] = FLT_MAX; + data[2][i] = -FLT_MAX; - data[2][i] = FLT_MAX; - data[3][i] = -FLT_MAX; + data[3][i] = FLT_MAX; + data[4][i] = -FLT_MAX; - data[4][i] = FLT_MAX; - data[5][i] = -FLT_MAX; + data[5][i] = FLT_MAX; + data[6][i] = -FLT_MAX; - data[6][i] = __int_as_float(0); + data[7][i] = __int_as_float(0); } - memcpy(&pack.nodes[e.idx * BVH_QNODE_SIZE], data, sizeof(float4)*BVH_QNODE_SIZE); + memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_QNODE_SIZE); +} + +void QBVH::pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num) +{ + float4 data[BVH_UNALIGNED_QNODE_SIZE]; + memset(data, 0, sizeof(data)); + + data[0].x = __uint_as_float(e.node->m_visibility | PATH_RAY_NODE_UNALIGNED); + + for(int i = 0; i < num; i++) { + Transform space = BVHUnaligned::compute_node_transform( + en[i].node->m_bounds, + en[i].node->get_aligned_space()); + + data[1][i] = space.x.x; + data[2][i] = space.x.y; + data[3][i] = space.x.z; + + data[4][i] = space.y.x; + data[5][i] = space.y.y; + data[6][i] = space.y.z; + + data[7][i] = space.z.x; + data[8][i] = space.z.y; + data[9][i] = space.z.z; + + data[10][i] = space.x.w; + data[11][i] = space.y.w; + data[12][i] = space.z.w; + + data[13][i] = __int_as_float(en[i].encodeIdx()); + } + + for(int i = num; i < 4; i++) { + /* We store BB which would never be recorded as intersection + * so kernel might safely assume there are always 4 child nodes. + */ + for(int j = 1; j < 13; ++j) { + data[j][i] = 0.0f; + } + data[13][i] = __int_as_float(0); + } + + memcpy(&pack.nodes[e.idx], data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); } /* Quad SIMD Nodes */ void QBVH::pack_nodes(const BVHNode *root) { - size_t tot_node_size = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); - size_t leaf_node_size = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); - size_t node_size = tot_node_size - leaf_node_size; - - /* resize arrays */ + /* Calculate size of the arrays required. */ + const size_t num_nodes = root->getSubtreeSize(BVH_STAT_QNODE_COUNT); + const size_t num_leaf_nodes = root->getSubtreeSize(BVH_STAT_LEAF_COUNT); + assert(num_leaf_nodes <= num_nodes); + const size_t num_inner_nodes = num_nodes - num_leaf_nodes; + size_t node_size; + if(params.use_unaligned_nodes) { + const size_t num_unaligned_nodes = + root->getSubtreeSize(BVH_STAT_UNALIGNED_INNER_QNODE_COUNT); + node_size = (num_unaligned_nodes * BVH_UNALIGNED_QNODE_SIZE) + + (num_inner_nodes - num_unaligned_nodes) * BVH_QNODE_SIZE; + } + else { + node_size = num_inner_nodes * BVH_QNODE_SIZE; + } + /* Resize arrays. */ pack.nodes.clear(); pack.leaf_nodes.clear(); - - /* for top level BVH, first merge existing BVH's so we know the offsets */ + /* For top level BVH, first merge existing BVH's so we know the offsets. */ if(params.top_level) { - pack_instances(node_size*BVH_QNODE_SIZE, - leaf_node_size*BVH_QNODE_LEAF_SIZE); + pack_instances(node_size, num_leaf_nodes*BVH_QNODE_LEAF_SIZE); } else { - pack.nodes.resize(node_size*BVH_QNODE_SIZE); - pack.leaf_nodes.resize(leaf_node_size*BVH_QNODE_LEAF_SIZE); + pack.nodes.resize(node_size); + pack.leaf_nodes.resize(num_leaf_nodes*BVH_QNODE_LEAF_SIZE); } int nextNodeIdx = 0, nextLeafNodeIdx = 0; @@ -680,7 +920,10 @@ void QBVH::pack_nodes(const BVHNode *root) stack.push_back(BVHStackEntry(root, nextLeafNodeIdx++)); } else { - stack.push_back(BVHStackEntry(root, nextNodeIdx++)); + stack.push_back(BVHStackEntry(root, nextNodeIdx)); + nextNodeIdx += node_qbvh_is_unaligned(root) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; } while(stack.size()) { @@ -689,19 +932,17 @@ void QBVH::pack_nodes(const BVHNode *root) if(e.node->is_leaf()) { /* leaf node */ - const LeafNode* leaf = reinterpret_cast<const LeafNode*>(e.node); + const LeafNode *leaf = reinterpret_cast<const LeafNode*>(e.node); pack_leaf(e, leaf); } else { - /* inner node */ + /* Inner node. */ const BVHNode *node = e.node; const BVHNode *node0 = node->get_child(0); const BVHNode *node1 = node->get_child(1); - - /* collect nodes */ + /* Collect nodes. */ const BVHNode *nodes[4]; int numnodes = 0; - if(node0->is_leaf()) { nodes[numnodes++] = node0; } @@ -709,7 +950,6 @@ void QBVH::pack_nodes(const BVHNode *root) nodes[numnodes++] = node0->get_child(0); nodes[numnodes++] = node0->get_child(1); } - if(node1->is_leaf()) { nodes[numnodes++] = node1; } @@ -717,25 +957,26 @@ void QBVH::pack_nodes(const BVHNode *root) nodes[numnodes++] = node1->get_child(0); nodes[numnodes++] = node1->get_child(1); } - - /* push entries on the stack */ - for(int i = 0; i < numnodes; i++) { + /* Push entries on the stack. */ + for(int i = 0; i < numnodes; ++i) { int idx; if(nodes[i]->is_leaf()) { idx = nextLeafNodeIdx++; } else { - idx = nextNodeIdx++; + idx = nextNodeIdx; + nextNodeIdx += node_qbvh_is_unaligned(nodes[i]) + ? BVH_UNALIGNED_QNODE_SIZE + : BVH_QNODE_SIZE; } stack.push_back(BVHStackEntry(nodes[i], idx)); } - - /* set node */ + /* Set node. */ pack_inner(e, &stack[stack.size()-numnodes], numnodes); } } - - /* root index to start traversal at, to handle case of single leaf node */ + assert(node_size == nextNodeIdx); + /* Root index to start traversal at, to handle case of single leaf node. */ pack.root_index = (root->is_leaf())? -1: 0; } @@ -751,7 +992,7 @@ void QBVH::refit_nodes() void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) { if(leaf) { - int4 *data = &pack.leaf_nodes[idx*BVH_QNODE_LEAF_SIZE]; + int4 *data = &pack.leaf_nodes[idx]; int4 c = data[0]; /* Refit leaf node. */ for(int prim = c.x; prim < c.y; prim++) { @@ -833,13 +1074,18 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) leaf_data[0].y = __int_as_float(c.y); leaf_data[0].z = __uint_as_float(visibility); leaf_data[0].w = __uint_as_float(c.w); - memcpy(&pack.leaf_nodes[idx * BVH_QNODE_LEAF_SIZE], - leaf_data, - sizeof(float4)*BVH_QNODE_LEAF_SIZE); + memcpy(&pack.leaf_nodes[idx], leaf_data, sizeof(float4)*BVH_QNODE_LEAF_SIZE); } else { - int4 *data = &pack.nodes[idx*BVH_QNODE_SIZE]; - int4 c = data[6]; + int4 *data = &pack.nodes[idx]; + bool is_unaligned = (data[0].x & PATH_RAY_NODE_UNALIGNED) != 0; + int4 c; + if(is_unaligned) { + c = data[13]; + } + else { + c = data[7]; + } /* Refit inner node, set bbox from children. */ BoundBox child_bbox[4] = {BoundBox::empty, BoundBox::empty, @@ -858,21 +1104,62 @@ void QBVH::refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility) } } - float4 inner_data[BVH_QNODE_SIZE]; - for(int i = 0; i < 4; ++i) { - float3 bb_min = child_bbox[i].min; - float3 bb_max = child_bbox[i].max; - inner_data[0][i] = bb_min.x; - inner_data[1][i] = bb_max.x; - inner_data[2][i] = bb_min.y; - inner_data[3][i] = bb_max.y; - inner_data[4][i] = bb_min.z; - inner_data[5][i] = bb_max.z; - inner_data[6][i] = __int_as_float(c[i]); + /* TODO(sergey): To be de-duplicated with pack_inner(), + * but for that need some sort of pack_node(). which operates with + * direct data, not stack element. + */ + if(is_unaligned) { + Transform aligned_space = transform_identity(); + float4 inner_data[BVH_UNALIGNED_QNODE_SIZE]; + inner_data[0] = make_float4( + __int_as_float(visibility | PATH_RAY_NODE_UNALIGNED), + 0.0f, + 0.0f, + 0.0f); + for(int i = 0; i < 4; ++i) { + Transform space = BVHUnaligned::compute_node_transform( + child_bbox[i], + aligned_space); + inner_data[1][i] = space.x.x; + inner_data[2][i] = space.x.y; + inner_data[3][i] = space.x.z; + + inner_data[4][i] = space.y.x; + inner_data[5][i] = space.y.y; + inner_data[6][i] = space.y.z; + + inner_data[7][i] = space.z.x; + inner_data[8][i] = space.z.y; + inner_data[9][i] = space.z.z; + + inner_data[10][i] = space.x.w; + inner_data[11][i] = space.y.w; + inner_data[12][i] = space.z.w; + + inner_data[13][i] = __int_as_float(c[i]); + } + memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_UNALIGNED_QNODE_SIZE); + } + else { + float4 inner_data[BVH_QNODE_SIZE]; + inner_data[0] = make_float4( + __int_as_float(visibility & ~PATH_RAY_NODE_UNALIGNED), + 0.0f, + 0.0f, + 0.0f); + for(int i = 0; i < 4; ++i) { + float3 bb_min = child_bbox[i].min; + float3 bb_max = child_bbox[i].max; + inner_data[1][i] = bb_min.x; + inner_data[2][i] = bb_max.x; + inner_data[3][i] = bb_min.y; + inner_data[4][i] = bb_max.y; + inner_data[5][i] = bb_min.z; + inner_data[6][i] = bb_max.z; + inner_data[7][i] = __int_as_float(c[i]); + } + memcpy(&pack.nodes[idx], inner_data, sizeof(float4)*BVH_QNODE_SIZE); } - memcpy(&pack.nodes[idx * BVH_QNODE_SIZE], - inner_data, - sizeof(float4)*BVH_QNODE_SIZE); } } diff --git a/intern/cycles/bvh/bvh.h b/intern/cycles/bvh/bvh.h index 6076c25ca31..16752076f6a 100644 --- a/intern/cycles/bvh/bvh.h +++ b/intern/cycles/bvh/bvh.h @@ -35,11 +35,14 @@ class Progress; #define BVH_NODE_SIZE 4 #define BVH_NODE_LEAF_SIZE 1 -#define BVH_QNODE_SIZE 7 +#define BVH_QNODE_SIZE 8 #define BVH_QNODE_LEAF_SIZE 1 #define BVH_ALIGN 4096 #define TRI_NODE_SIZE 3 +#define BVH_UNALIGNED_NODE_SIZE 7 +#define BVH_UNALIGNED_QNODE_SIZE 14 + /* Packed BVH * * BVH stored as it will be used for traversal on the rendering device. */ @@ -52,8 +55,10 @@ struct PackedBVH { array<int4> leaf_nodes; /* object index to BVH node index mapping for instances */ array<int> object_node; - /* Aligned triangle storage for fatser lookup in the kernel. */ - array<float4> tri_storage; + /* Mapping from primitive index to index in triangle array. */ + array<uint> prim_tri_index; + /* Continuous storage of triangle vertices. */ + array<float4> prim_tri_verts; /* primitive type - triangle or strand */ array<int> prim_type; /* visibility visibilitys for primitives */ @@ -91,7 +96,7 @@ public: protected: BVH(const BVHParams& params, const vector<Object*>& objects); - /* triangles and strands*/ + /* triangles and strands */ void pack_primitives(); void pack_triangle(int idx, float4 storage[3]); @@ -115,9 +120,32 @@ protected: /* pack */ void pack_nodes(const BVHNode *root); - void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); - void pack_inner(const BVHStackEntry& e, const BVHStackEntry& e0, const BVHStackEntry& e1); - void pack_node(int idx, const BoundBox& b0, const BoundBox& b1, int c0, int c1, uint visibility0, uint visibility1); + + void pack_leaf(const BVHStackEntry& e, + const LeafNode *leaf); + void pack_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_aligned_node(int idx, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); + + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry& e0, + const BVHStackEntry& e1); + void pack_unaligned_node(int idx, + const Transform& aligned_space0, + const Transform& aligned_space1, + const BoundBox& b0, + const BoundBox& b1, + int c0, int c1, + uint visibility0, uint visibility1); /* refit */ void refit_nodes(); @@ -136,9 +164,17 @@ protected: /* pack */ void pack_nodes(const BVHNode *root); + void pack_leaf(const BVHStackEntry& e, const LeafNode *leaf); void pack_inner(const BVHStackEntry& e, const BVHStackEntry *en, int num); + void pack_aligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + void pack_unaligned_inner(const BVHStackEntry& e, + const BVHStackEntry *en, + int num); + /* refit */ void refit_nodes(); void refit_node(int idx, bool leaf, BoundBox& bbox, uint& visibility); diff --git a/intern/cycles/bvh/bvh_binning.cpp b/intern/cycles/bvh/bvh_binning.cpp index b07e870d759..5ddd7349f7b 100644 --- a/intern/cycles/bvh/bvh_binning.cpp +++ b/intern/cycles/bvh/bvh_binning.cpp @@ -52,12 +52,35 @@ __forceinline int get_best_dimension(const float4& bestSAH) /* BVH Object Binning */ -BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) -: BVHRange(job), splitSAH(FLT_MAX), dim(0), pos(0) +BVHObjectBinning::BVHObjectBinning(const BVHRange& job, + BVHReference *prims, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) +: BVHRange(job), + splitSAH(FLT_MAX), + dim(0), + pos(0), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { + if(aligned_space_ == NULL) { + bounds_ = bounds(); + cent_bounds_ = cent_bounds(); + } + else { + /* TODO(sergey): With some additional storage we can avoid + * need in re-calculating this. + */ + bounds_ = unaligned_heuristic->compute_aligned_boundbox( + *this, + prims, + *aligned_space, + ¢_bounds_); + } + /* compute number of bins to use and precompute scaling factor for binning */ num_bins = min(size_t(MAX_BINS), size_t(4.0f + 0.05f*size())); - scale = rcp(cent_bounds().size()) * make_float3((float)num_bins); + scale = rcp(cent_bounds_.size()) * make_float3((float)num_bins); /* initialize binning counter and bounds */ BoundBox bin_bounds[MAX_BINS][4]; /* bounds for every bin in every dimension */ @@ -79,30 +102,34 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) const BVHReference& prim0 = prims[start() + i + 0]; const BVHReference& prim1 = prims[start() + i + 1]; - int4 bin0 = get_bin(prim0.bounds()); - int4 bin1 = get_bin(prim1.bounds()); + BoundBox bounds0 = get_prim_bounds(prim0); + BoundBox bounds1 = get_prim_bounds(prim1); + + int4 bin0 = get_bin(bounds0); + int4 bin1 = get_bin(bounds1); /* increase bounds for bins for even primitive */ - int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds()); - int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds()); - int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds()); + int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0); + int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0); + int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0); /* increase bounds of bins for odd primitive */ - int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(prim1.bounds()); - int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(prim1.bounds()); - int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(prim1.bounds()); + int b10 = (int)extract<0>(bin1); bin_count[b10][0]++; bin_bounds[b10][0].grow(bounds1); + int b11 = (int)extract<1>(bin1); bin_count[b11][1]++; bin_bounds[b11][1].grow(bounds1); + int b12 = (int)extract<2>(bin1); bin_count[b12][2]++; bin_bounds[b12][2].grow(bounds1); } /* for uneven number of primitives */ if(i < ssize_t(size())) { /* map primitive to bin */ const BVHReference& prim0 = prims[start() + i]; - int4 bin0 = get_bin(prim0.bounds()); + BoundBox bounds0 = get_prim_bounds(prim0); + int4 bin0 = get_bin(bounds0); /* increase bounds of bins */ - int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(prim0.bounds()); - int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(prim0.bounds()); - int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(prim0.bounds()); + int b00 = (int)extract<0>(bin0); bin_count[b00][0]++; bin_bounds[b00][0].grow(bounds0); + int b01 = (int)extract<1>(bin0); bin_count[b01][1]++; bin_bounds[b01][1].grow(bounds0); + int b02 = (int)extract<2>(bin0); bin_count[b02][2]++; bin_bounds[b02][2].grow(bounds0); } } @@ -151,17 +178,19 @@ BVHObjectBinning::BVHObjectBinning(const BVHRange& job, BVHReference *prims) bestSAH = min(sah,bestSAH); } - int4 mask = float3_to_float4(cent_bounds().size()) <= make_float4(0.0f); + int4 mask = float3_to_float4(cent_bounds_.size()) <= make_float4(0.0f); bestSAH = insert<3>(select(mask, make_float4(FLT_MAX), bestSAH), FLT_MAX); /* find best dimension */ dim = get_best_dimension(bestSAH); splitSAH = bestSAH[dim]; pos = bestSplit[dim]; - leafSAH = bounds().half_area() * blocks(size()); + leafSAH = bounds_.half_area() * blocks(size()); } -void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const +void BVHObjectBinning::split(BVHReference* prims, + BVHObjectBinning& left_o, + BVHObjectBinning& right_o) const { size_t N = size(); @@ -176,10 +205,12 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO prefetch_L2(&prims[start() + l + 8]); prefetch_L2(&prims[start() + r - 8]); - const BVHReference& prim = prims[start() + l]; + BVHReference prim = prims[start() + l]; + BoundBox unaligned_bounds = get_prim_bounds(prim); + float3 unaligned_center = unaligned_bounds.center2(); float3 center = prim.bounds().center2(); - if(get_bin(center)[dim] < pos) { + if(get_bin(unaligned_center)[dim] < pos) { lgeom_bounds.grow(prim.bounds()); lcent_bounds.grow(center); l++; @@ -191,7 +222,6 @@ void BVHObjectBinning::split(BVHReference* prims, BVHObjectBinning& left_o, BVHO r--; } } - /* finish */ if(l != 0 && N-1-r != 0) { right_o = BVHObjectBinning(BVHRange(rgeom_bounds, rcent_bounds, start() + l, N-1-r), prims); diff --git a/intern/cycles/bvh/bvh_binning.h b/intern/cycles/bvh/bvh_binning.h index 60742157055..52955f70151 100644 --- a/intern/cycles/bvh/bvh_binning.h +++ b/intern/cycles/bvh/bvh_binning.h @@ -19,11 +19,14 @@ #define __BVH_BINNING_H__ #include "bvh_params.h" +#include "bvh_unaligned.h" #include "util_types.h" CCL_NAMESPACE_BEGIN +class BVHBuild; + /* Single threaded object binner. Finds the split with the best SAH heuristic * by testing for each dimension multiple partitionings for regular spaced * partition locations. A partitioning for a partition location is computed, @@ -34,10 +37,18 @@ CCL_NAMESPACE_BEGIN class BVHObjectBinning : public BVHRange { public: - __forceinline BVHObjectBinning() {} - BVHObjectBinning(const BVHRange& job, BVHReference *prims); + __forceinline BVHObjectBinning() : leafSAH(FLT_MAX) {} + + BVHObjectBinning(const BVHRange& job, + BVHReference *prims, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); - void split(BVHReference *prims, BVHObjectBinning& left_o, BVHObjectBinning& right_o) const; + void split(BVHReference *prims, + BVHObjectBinning& left_o, + BVHObjectBinning& right_o) const; + + __forceinline const BoundBox& unaligned_bounds() { return bounds_; } float splitSAH; /* SAH cost of the best split */ float leafSAH; /* SAH cost of creating a leaf */ @@ -48,13 +59,20 @@ protected: size_t num_bins; /* actual number of bins to use */ float3 scale; /* scaling factor to compute bin */ + /* Effective bounds and centroid bounds. */ + BoundBox bounds_; + BoundBox cent_bounds_; + + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; + enum { MAX_BINS = 32 }; enum { LOG_BLOCK_SIZE = 2 }; /* computes the bin numbers for each dimension for a box. */ __forceinline int4 get_bin(const BoundBox& box) const { - int4 a = make_int4((box.center2() - cent_bounds().min)*scale - make_float3(0.5f)); + int4 a = make_int4((box.center2() - cent_bounds_.min)*scale - make_float3(0.5f)); int4 mn = make_int4(0); int4 mx = make_int4((int)num_bins-1); @@ -64,7 +82,7 @@ protected: /* computes the bin numbers for each dimension for a point. */ __forceinline int4 get_bin(const float3& c) const { - return make_int4((c - cent_bounds().min)*scale - make_float3(0.5f)); + return make_int4((c - cent_bounds_.min)*scale - make_float3(0.5f)); } /* compute the number of blocks occupied for each dimension. */ @@ -78,6 +96,17 @@ protected: { return (int)((a+((1LL << LOG_BLOCK_SIZE)-1)) >> LOG_BLOCK_SIZE); } + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } }; CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_build.cpp b/intern/cycles/bvh/bvh_build.cpp index 3f687224eee..67ffb6853d6 100644 --- a/intern/cycles/bvh/bvh_build.cpp +++ b/intern/cycles/bvh/bvh_build.cpp @@ -33,6 +33,7 @@ #include "util_stack_allocator.h" #include "util_simd.h" #include "util_time.h" +#include "util_queue.h" CCL_NAMESPACE_BEGIN @@ -99,7 +100,8 @@ BVHBuild::BVHBuild(const vector<Object*>& objects_, prim_object(prim_object_), params(params_), progress(progress_), - progress_start_time(0.0) + progress_start_time(0.0), + unaligned_heuristic(objects_) { spatial_min_overlap = 0.0f; } @@ -112,70 +114,74 @@ BVHBuild::~BVHBuild() void BVHBuild::add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i) { - Attribute *attr_mP = NULL; - - if(mesh->has_motion_blur()) - attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + Attribute *attr_mP = NULL; - size_t num_triangles = mesh->num_triangles(); - for(uint j = 0; j < num_triangles; j++) { - Mesh::Triangle t = mesh->get_triangle(j); - BoundBox bounds = BoundBox::empty; - PrimitiveType type = PRIMITIVE_TRIANGLE; + if(mesh->has_motion_blur()) + attr_mP = mesh->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + size_t num_triangles = mesh->num_triangles(); + for(uint j = 0; j < num_triangles; j++) { + Mesh::Triangle t = mesh->get_triangle(j); + BoundBox bounds = BoundBox::empty; + PrimitiveType type = PRIMITIVE_TRIANGLE; - t.bounds_grow(&mesh->verts[0], bounds); + t.bounds_grow(&mesh->verts[0], bounds); - /* motion triangles */ - if(attr_mP) { - size_t mesh_size = mesh->verts.size(); - size_t steps = mesh->motion_steps - 1; - float3 *vert_steps = attr_mP->data_float3(); + /* motion triangles */ + if(attr_mP) { + size_t mesh_size = mesh->verts.size(); + size_t steps = mesh->motion_steps - 1; + float3 *vert_steps = attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - t.bounds_grow(vert_steps + i*mesh_size, bounds); + for(size_t i = 0; i < steps; i++) + t.bounds_grow(vert_steps + i*mesh_size, bounds); - type = PRIMITIVE_MOTION_TRIANGLE; - } + type = PRIMITIVE_MOTION_TRIANGLE; + } - if(bounds.valid()) { - references.push_back(BVHReference(bounds, j, i, type)); - root.grow(bounds); - center.grow(bounds.center2()); + if(bounds.valid()) { + references.push_back(BVHReference(bounds, j, i, type)); + root.grow(bounds); + center.grow(bounds.center2()); + } } } - Attribute *curve_attr_mP = NULL; + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + Attribute *curve_attr_mP = NULL; - if(mesh->has_motion_blur()) - curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + if(mesh->has_motion_blur()) + curve_attr_mP = mesh->curve_attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); - size_t num_curves = mesh->num_curves(); - for(uint j = 0; j < num_curves; j++) { - Mesh::Curve curve = mesh->get_curve(j); - PrimitiveType type = PRIMITIVE_CURVE; + size_t num_curves = mesh->num_curves(); + for(uint j = 0; j < num_curves; j++) { + Mesh::Curve curve = mesh->get_curve(j); + PrimitiveType type = PRIMITIVE_CURVE; - for(int k = 0; k < curve.num_keys - 1; k++) { - BoundBox bounds = BoundBox::empty; - curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds); + for(int k = 0; k < curve.num_keys - 1; k++) { + BoundBox bounds = BoundBox::empty; + curve.bounds_grow(k, &mesh->curve_keys[0], &mesh->curve_radius[0], bounds); - /* motion curve */ - if(curve_attr_mP) { - size_t mesh_size = mesh->curve_keys.size(); - size_t steps = mesh->motion_steps - 1; - float3 *key_steps = curve_attr_mP->data_float3(); + /* motion curve */ + if(curve_attr_mP) { + size_t mesh_size = mesh->curve_keys.size(); + size_t steps = mesh->motion_steps - 1; + float3 *key_steps = curve_attr_mP->data_float3(); - for(size_t i = 0; i < steps; i++) - curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds); + for(size_t i = 0; i < steps; i++) + curve.bounds_grow(k, key_steps + i*mesh_size, &mesh->curve_radius[0], bounds); - type = PRIMITIVE_MOTION_CURVE; - } + type = PRIMITIVE_MOTION_CURVE; + } - if(bounds.valid()) { - int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); - - references.push_back(BVHReference(bounds, j, i, packed_type)); - root.grow(bounds); - center.grow(bounds.center2()); + if(bounds.valid()) { + int packed_type = PRIMITIVE_PACK_SEGMENT(type, k); + + references.push_back(BVHReference(bounds, j, i, packed_type)); + root.grow(bounds); + center.grow(bounds.center2()); + } } } } @@ -209,15 +215,23 @@ void BVHBuild::add_references(BVHRange& root) continue; } if(!ob->mesh->is_instanced()) { - num_alloc_references += ob->mesh->num_triangles(); - num_alloc_references += count_curve_segments(ob->mesh); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + num_alloc_references += ob->mesh->num_triangles(); + } + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + num_alloc_references += count_curve_segments(ob->mesh); + } } else num_alloc_references++; } else { - num_alloc_references += ob->mesh->num_triangles(); - num_alloc_references += count_curve_segments(ob->mesh); + if(params.primitive_mask & PRIMITIVE_ALL_TRIANGLE) { + num_alloc_references += ob->mesh->num_triangles(); + } + if(params.primitive_mask & PRIMITIVE_ALL_CURVE) { + num_alloc_references += count_curve_segments(ob->mesh); + } } } @@ -340,6 +354,8 @@ BVHNode* BVHBuild::run() << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_INNER_COUNT)) << "\n" << " Number of leaf nodes: " << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_LEAF_COUNT)) << "\n" + << " Number of unaligned nodes: " + << string_human_readable_number(rootnode->getSubtreeSize(BVH_STAT_UNALIGNED_COUNT)) << "\n" << " Allocation slop factor: " << ((prim_type.capacity() != 0) ? (float)prim_type.size() / prim_type.capacity() @@ -445,10 +461,11 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) float leafSAH = params.sah_primitive_cost * range.leafSAH; float splitSAH = params.sah_node_cost * range.bounds().half_area() + params.sah_primitive_cost * range.splitSAH; - /* have at least one inner node on top level, for performance and correct - * visibility tests, since object instances do not check visibility flag */ + /* Have at least one inner node on top level, for performance and correct + * visibility tests, since object instances do not check visibility flag. + */ if(!(range.size() > 0 && params.top_level && level == 0)) { - /* make leaf node when threshold reached or SAH tells us */ + /* Make leaf node when threshold reached or SAH tells us. */ if((params.small_enough_for_leaf(size, level)) || (range_within_max_leaf_size(range, references) && leafSAH < splitSAH)) { @@ -456,28 +473,70 @@ BVHNode* BVHBuild::build_node(const BVHObjectBinning& range, int level) } } - /* perform split */ + BVHObjectBinning unaligned_range; + float unalignedSplitSAH = FLT_MAX; + float unalignedLeafSAH = FLT_MAX; + Transform aligned_space; + if(params.use_unaligned_nodes && + splitSAH > params.unaligned_split_threshold*leafSAH) + { + aligned_space = unaligned_heuristic.compute_aligned_space( + range, &references[0]); + unaligned_range = BVHObjectBinning(range, + &references[0], + &unaligned_heuristic, + &aligned_space); + unalignedSplitSAH = params.sah_node_cost * unaligned_range.unaligned_bounds().half_area() + + params.sah_primitive_cost * unaligned_range.splitSAH; + unalignedLeafSAH = params.sah_primitive_cost * unaligned_range.leafSAH; + if(!(range.size() > 0 && params.top_level && level == 0)) { + if(unalignedLeafSAH < unalignedSplitSAH && unalignedSplitSAH < splitSAH && + range_within_max_leaf_size(range, references)) + { + return create_leaf_node(range, references); + } + } + } + + /* Perform split. */ BVHObjectBinning left, right; - range.split(&references[0], left, right); + if(unalignedSplitSAH < splitSAH) { + unaligned_range.split(&references[0], left, right); + } + else { + range.split(&references[0], left, right); + } - /* create inner node. */ - InnerNode *inner; + BoundBox bounds; + if(unalignedSplitSAH < splitSAH) { + bounds = unaligned_heuristic.compute_aligned_boundbox( + range, &references[0], aligned_space); + } + else { + bounds = range.bounds(); + } + /* Create inner node. */ + InnerNode *inner; if(range.size() < THREAD_TASK_SIZE) { /* local build */ BVHNode *leftnode = build_node(left, level + 1); BVHNode *rightnode = build_node(right, level + 1); - inner = new InnerNode(range.bounds(), leftnode, rightnode); + inner = new InnerNode(bounds, leftnode, rightnode); } else { - /* threaded build */ - inner = new InnerNode(range.bounds()); + /* Threaded build */ + inner = new InnerNode(bounds); task_pool.push(new BVHBuildTask(this, inner, 0, left, level + 1), true); task_pool.push(new BVHBuildTask(this, inner, 1, right, level + 1), true); } + if(unalignedSplitSAH < splitSAH) { + inner->set_aligned_space(aligned_space); + } + return inner; } @@ -516,16 +575,54 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, return create_leaf_node(range, *references); } } + float leafSAH = params.sah_primitive_cost * split.leafSAH; + float splitSAH = params.sah_node_cost * range.bounds().half_area() + + params.sah_primitive_cost * split.nodeSAH; + + BVHMixedSplit unaligned_split; + float unalignedSplitSAH = FLT_MAX; + /* float unalignedLeafSAH = FLT_MAX; */ + Transform aligned_space; + if(params.use_unaligned_nodes && + splitSAH > params.unaligned_split_threshold*leafSAH) + { + aligned_space = + unaligned_heuristic.compute_aligned_space(range, &references->at(0)); + unaligned_split = BVHMixedSplit(this, + storage, + range, + references, + level, + &unaligned_heuristic, + &aligned_space); + /* unalignedLeafSAH = params.sah_primitive_cost * split.leafSAH; */ + unalignedSplitSAH = params.sah_node_cost * unaligned_split.bounds.half_area() + + params.sah_primitive_cost * unaligned_split.nodeSAH; + /* TOOD(sergey): Check we can create leaf already. */ + } /* Do split. */ BVHRange left, right; - split.split(this, left, right, range); + if(unalignedSplitSAH < splitSAH) { + unaligned_split.split(this, left, right, range); + } + else { + split.split(this, left, right, range); + } progress_total += left.size() + right.size() - range.size(); + BoundBox bounds; + if(unalignedSplitSAH < splitSAH) { + bounds = unaligned_heuristic.compute_aligned_boundbox( + range, &references->at(0), aligned_space); + } + else { + bounds = range.bounds(); + } + /* Create inner node. */ InnerNode *inner; - if(range.size() < THREAD_TASK_SIZE) { /* Local build. */ @@ -539,11 +636,11 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, /* Build right node. */ BVHNode *rightnode = build_node(right, ©, level + 1, thread_id); - inner = new InnerNode(range.bounds(), leftnode, rightnode); + inner = new InnerNode(bounds, leftnode, rightnode); } else { /* Threaded build. */ - inner = new InnerNode(range.bounds()); + inner = new InnerNode(bounds); task_pool.push(new BVHSpatialSplitBuildTask(this, inner, 0, @@ -560,6 +657,10 @@ BVHNode* BVHBuild::build_node(const BVHRange& range, true); } + if(unalignedSplitSAH < splitSAH) { + inner->set_aligned_space(aligned_space); + } + return inner; } @@ -616,6 +717,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, vector<int, LeafStackAllocator> p_type[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_index[PRIMITIVE_NUM_TOTAL]; vector<int, LeafStackAllocator> p_object[PRIMITIVE_NUM_TOTAL]; + vector<BVHReference, LeafStackAllocator> p_ref[PRIMITIVE_NUM_TOTAL]; /* TODO(sergey): In theory we should be able to store references. */ typedef StackAllocator<256, BVHReference> LeafReferenceStackAllocator; @@ -634,6 +736,7 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, const BVHReference& ref = references[range.start() + i]; if(ref.prim_index() != -1) { int type_index = bitscan(ref.prim_type() & PRIMITIVE_ALL); + p_ref[type_index].push_back(ref); p_type[type_index].push_back(ref.prim_type()); p_index[type_index].push_back(ref.prim_index()); p_object[type_index].push_back(ref.prim_object()); @@ -674,16 +777,38 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, if(num != 0) { assert(p_type[i].size() == p_index[i].size()); assert(p_type[i].size() == p_object[i].size()); + Transform aligned_space; + bool alignment_found = false; for(int j = 0; j < num; ++j) { const int index = start_index + j; local_prim_type[index] = p_type[i][j]; local_prim_index[index] = p_index[i][j]; local_prim_object[index] = p_object[i][j]; + if(params.use_unaligned_nodes && !alignment_found) { + alignment_found = + unaligned_heuristic.compute_aligned_space(p_ref[i][j], + &aligned_space); + } + } + LeafNode *leaf_node = new LeafNode(bounds[i], + visibility[i], + start_index, + start_index + num); + if(alignment_found) { + /* Need to recalculate leaf bounds with new alignment. */ + leaf_node->m_bounds = BoundBox::empty; + for(int j = 0; j < num; ++j) { + const BVHReference &ref = p_ref[i][j]; + BoundBox ref_bounds = + unaligned_heuristic.compute_aligned_prim_boundbox( + ref, + aligned_space); + leaf_node->m_bounds.grow(ref_bounds); + } + /* Set alignment space. */ + leaf_node->set_aligned_space(aligned_space); } - leaves[num_leaves++] = new LeafNode(bounds[i], - visibility[i], - start_index, - start_index + num); + leaves[num_leaves++] = leaf_node; start_index += num; } } @@ -765,6 +890,9 @@ BVHNode* BVHBuild::create_leaf_node(const BVHRange& range, ++num_leaves; } + /* TODO(sergey): Need to take care of alignment when number of leaves + * is more than 1. + */ if(num_leaves == 1) { /* Simplest case: single leaf, just return it. * In all the rest cases we'll be creating intermediate inner node with diff --git a/intern/cycles/bvh/bvh_build.h b/intern/cycles/bvh/bvh_build.h index a015b89d72f..64180349935 100644 --- a/intern/cycles/bvh/bvh_build.h +++ b/intern/cycles/bvh/bvh_build.h @@ -22,6 +22,7 @@ #include "bvh.h" #include "bvh_binning.h" +#include "bvh_unaligned.h" #include "util_boundbox.h" #include "util_task.h" @@ -59,13 +60,14 @@ protected: friend class BVHSpatialSplit; friend class BVHBuildTask; friend class BVHSpatialSplitBuildTask; + friend class BVHObjectBinning; - /* adding references */ + /* Adding references. */ void add_reference_mesh(BoundBox& root, BoundBox& center, Mesh *mesh, int i); void add_reference_object(BoundBox& root, BoundBox& center, Object *ob, int i); void add_references(BVHRange& root); - /* building */ + /* Building. */ BVHNode *build_node(const BVHRange& range, vector<BVHReference> *references, int level, @@ -78,7 +80,7 @@ protected: bool range_within_max_leaf_size(const BVHRange& range, const vector<BVHReference>& references) const; - /* threads */ + /* Threads. */ enum { THREAD_TASK_SIZE = 4096 }; void thread_build_node(InnerNode *node, int child, @@ -92,41 +94,44 @@ protected: int thread_id); thread_mutex build_mutex; - /* progress */ + /* Progress. */ void progress_update(); - /* tree rotations */ + /* Tree rotations. */ void rotate(BVHNode *node, int max_depth); void rotate(BVHNode *node, int max_depth, int iterations); - /* objects and primitive references */ + /* Objects and primitive references. */ vector<Object*> objects; vector<BVHReference> references; int num_original_references; - /* output primitive indexes and objects */ + /* Output primitive indexes and objects. */ array<int>& prim_type; array<int>& prim_index; array<int>& prim_object; - /* build parameters */ + /* Build parameters. */ BVHParams params; - /* progress reporting */ + /* Progress reporting. */ Progress& progress; double progress_start_time; size_t progress_count; size_t progress_total; size_t progress_original_total; - /* spatial splitting */ + /* Spatial splitting. */ float spatial_min_overlap; vector<BVHSpatialStorage> spatial_storage; size_t spatial_free_index; thread_spin_lock spatial_spin_lock; - /* threads */ + /* Threads. */ TaskPool task_pool; + + /* Unaligned building. */ + BVHUnaligned unaligned_heuristic; }; CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_node.cpp b/intern/cycles/bvh/bvh_node.cpp index 8294690da7d..f5cd699bdf4 100644 --- a/intern/cycles/bvh/bvh_node.cpp +++ b/intern/cycles/bvh/bvh_node.cpp @@ -61,6 +61,76 @@ int BVHNode::getSubtreeSize(BVH_STAT stat) const } } return cnt; + case BVH_STAT_ALIGNED_COUNT: + if(!is_unaligned()) { + cnt = 1; + } + break; + case BVH_STAT_UNALIGNED_COUNT: + if(is_unaligned()) { + cnt = 1; + } + break; + case BVH_STAT_ALIGNED_INNER_COUNT: + if(!is_leaf()) { + bool has_unaligned = false; + for(int j = 0; j < num_children(); j++) { + has_unaligned |= get_child(j)->is_unaligned(); + } + cnt += has_unaligned? 0: 1; + } + break; + case BVH_STAT_UNALIGNED_INNER_COUNT: + if(!is_leaf()) { + bool has_unaligned = false; + for(int j = 0; j < num_children(); j++) { + has_unaligned |= get_child(j)->is_unaligned(); + } + cnt += has_unaligned? 1: 0; + } + break; + case BVH_STAT_ALIGNED_INNER_QNODE_COUNT: + { + bool has_unaligned = false; + for(int i = 0; i < num_children(); i++) { + BVHNode *node = get_child(i); + if(node->is_leaf()) { + has_unaligned |= node->is_unaligned(); + } + else { + for(int j = 0; j < node->num_children(); j++) { + cnt += node->get_child(j)->getSubtreeSize(stat); + has_unaligned |= node->get_child(j)->is_unaligned(); + } + } + } + cnt += has_unaligned? 0: 1; + } + return cnt; + case BVH_STAT_UNALIGNED_INNER_QNODE_COUNT: + { + bool has_unaligned = false; + for(int i = 0; i < num_children(); i++) { + BVHNode *node = get_child(i); + if(node->is_leaf()) { + has_unaligned |= node->is_unaligned(); + } + else { + for(int j = 0; j < node->num_children(); j++) { + cnt += node->get_child(j)->getSubtreeSize(stat); + has_unaligned |= node->get_child(j)->is_unaligned(); + } + } + } + cnt += has_unaligned? 1: 0; + } + return cnt; + case BVH_STAT_ALIGNED_LEAF_COUNT: + cnt = (is_leaf() && !is_unaligned()) ? 1 : 0; + break; + case BVH_STAT_UNALIGNED_LEAF_COUNT: + cnt = (is_leaf() && is_unaligned()) ? 1 : 0; + break; default: assert(0); /* unknown mode */ } diff --git a/intern/cycles/bvh/bvh_node.h b/intern/cycles/bvh/bvh_node.h index d476fb917ed..f2965a785e6 100644 --- a/intern/cycles/bvh/bvh_node.h +++ b/intern/cycles/bvh/bvh_node.h @@ -31,6 +31,14 @@ enum BVH_STAT { BVH_STAT_TRIANGLE_COUNT, BVH_STAT_CHILDNODE_COUNT, BVH_STAT_QNODE_COUNT, + BVH_STAT_ALIGNED_COUNT, + BVH_STAT_UNALIGNED_COUNT, + BVH_STAT_ALIGNED_INNER_COUNT, + BVH_STAT_UNALIGNED_INNER_COUNT, + BVH_STAT_ALIGNED_INNER_QNODE_COUNT, + BVH_STAT_UNALIGNED_INNER_QNODE_COUNT, + BVH_STAT_ALIGNED_LEAF_COUNT, + BVH_STAT_UNALIGNED_LEAF_COUNT, }; class BVHParams; @@ -38,16 +46,41 @@ class BVHParams; class BVHNode { public: - BVHNode() + BVHNode() : m_is_unaligned(false), + m_aligned_space(NULL) { } - virtual ~BVHNode() {} + virtual ~BVHNode() + { + delete m_aligned_space; + } + virtual bool is_leaf() const = 0; virtual int num_children() const = 0; virtual BVHNode *get_child(int i) const = 0; virtual int num_triangles() const { return 0; } virtual void print(int depth = 0) const = 0; + bool is_unaligned() const { return m_is_unaligned; } + + inline void set_aligned_space(const Transform& aligned_space) + { + m_is_unaligned = true; + if (m_aligned_space == NULL) { + m_aligned_space = new Transform(aligned_space); + } + else { + *m_aligned_space = aligned_space; + } + } + + inline Transform get_aligned_space() const + { + if(m_aligned_space == NULL) { + return transform_identity(); + } + return *m_aligned_space; + } BoundBox m_bounds; uint m_visibility; @@ -58,12 +91,20 @@ public: void deleteSubtree(); uint update_visibility(); + + bool m_is_unaligned; + + // TODO(sergey): Can be stored as 3x3 matrix, but better to have some + // utilities and type defines in util_transform first. + Transform *m_aligned_space; }; class InnerNode : public BVHNode { public: - InnerNode(const BoundBox& bounds, BVHNode* child0, BVHNode* child1) + InnerNode(const BoundBox& bounds, + BVHNode* child0, + BVHNode* child1) { m_bounds = bounds; children[0] = child0; diff --git a/intern/cycles/bvh/bvh_params.h b/intern/cycles/bvh/bvh_params.h index cf683df1b31..2e698a80742 100644 --- a/intern/cycles/bvh/bvh_params.h +++ b/intern/cycles/bvh/bvh_params.h @@ -20,6 +20,8 @@ #include "util_boundbox.h" +#include "kernel_types.h" + CCL_NAMESPACE_BEGIN /* BVH Parameters */ @@ -31,6 +33,9 @@ public: bool use_spatial_split; float spatial_split_alpha; + /* Unaligned nodes creation threshold */ + float unaligned_split_threshold; + /* SAH costs */ float sah_node_cost; float sah_primitive_cost; @@ -46,6 +51,14 @@ public: /* QBVH */ bool use_qbvh; + /* Mask of primitives to be included into the BVH. */ + int primitive_mask; + + /* Use unaligned bounding boxes. + * Only used for curves BVH. + */ + bool use_unaligned_nodes; + /* fixed parameters */ enum { MAX_DEPTH = 64, @@ -58,6 +71,8 @@ public: use_spatial_split = true; spatial_split_alpha = 1e-5f; + unaligned_split_threshold = 0.7f; + /* todo: see if splitting up primitive cost to be separate for triangles * and curves can help. so far in tests it doesn't help, but why? */ sah_node_cost = 1.0f; @@ -69,6 +84,9 @@ public: top_level = false; use_qbvh = false; + use_unaligned_nodes = false; + + primitive_mask = PRIMITIVE_ALL; } /* SAH costs */ diff --git a/intern/cycles/bvh/bvh_sort.cpp b/intern/cycles/bvh/bvh_sort.cpp index e9032c61c3b..e5bcf9995bf 100644 --- a/intern/cycles/bvh/bvh_sort.cpp +++ b/intern/cycles/bvh/bvh_sort.cpp @@ -26,23 +26,27 @@ CCL_NAMESPACE_BEGIN static const int BVH_SORT_THRESHOLD = 4096; -/* Silly workaround for float extended precision that happens when compiling - * on x86, due to one float staying in 80 bit precision register and the other - * not, which causes the strictly weak ordering to break. - */ -#if !defined(__i386__) -# define NO_EXTENDED_PRECISION -#else -# define NO_EXTENDED_PRECISION volatile -#endif - struct BVHReferenceCompare { public: int dim; + const BVHUnaligned *unaligned_heuristic; + const Transform *aligned_space; + + BVHReferenceCompare(int dim, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) + : dim(dim), + unaligned_heuristic(unaligned_heuristic), + aligned_space(aligned_space) + { + } - explicit BVHReferenceCompare(int dim_) + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const { - dim = dim_; + return (aligned_space != NULL) + ? unaligned_heuristic->compute_aligned_prim_boundbox( + prim, *aligned_space) + : prim.bounds(); } /* Compare two references. @@ -52,8 +56,10 @@ public: __forceinline int compare(const BVHReference& ra, const BVHReference& rb) const { - NO_EXTENDED_PRECISION float ca = ra.bounds().min[dim] + ra.bounds().max[dim]; - NO_EXTENDED_PRECISION float cb = rb.bounds().min[dim] + rb.bounds().max[dim]; + BoundBox ra_bounds = get_prim_bounds(ra), + rb_bounds = get_prim_bounds(rb); + float ca = ra_bounds.min[dim] + ra_bounds.max[dim]; + float cb = rb_bounds.min[dim] + rb_bounds.max[dim]; if(ca < cb) return -1; else if(ca > cb) return 1; @@ -171,10 +177,15 @@ static void bvh_reference_sort_threaded(TaskPool *task_pool, } } -void bvh_reference_sort(int start, int end, BVHReference *data, int dim) +void bvh_reference_sort(int start, + int end, + BVHReference *data, + int dim, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) { const int count = end - start; - BVHReferenceCompare compare(dim); + BVHReferenceCompare compare(dim, unaligned_heuristic, aligned_space); if(count < BVH_SORT_THRESHOLD) { /* It is important to not use any mutex if array is small enough, * otherwise we end up in situation when we're going to sleep far diff --git a/intern/cycles/bvh/bvh_sort.h b/intern/cycles/bvh/bvh_sort.h index 18aafb5f1ff..b49ca02eb60 100644 --- a/intern/cycles/bvh/bvh_sort.h +++ b/intern/cycles/bvh/bvh_sort.h @@ -20,7 +20,15 @@ CCL_NAMESPACE_BEGIN -void bvh_reference_sort(int start, int end, BVHReference *data, int dim); +class BVHUnaligned; +struct Transform; + +void bvh_reference_sort(int start, + int end, + BVHReference *data, + int dim, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_split.cpp b/intern/cycles/bvh/bvh_split.cpp index bf68b41021f..d0d5fbe5a7a 100644 --- a/intern/cycles/bvh/bvh_split.cpp +++ b/intern/cycles/bvh/bvh_split.cpp @@ -32,14 +32,18 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH) + float nodeSAH, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) : sah(FLT_MAX), dim(0), num_left(0), left_bounds(BoundBox::empty), right_bounds(BoundBox::empty), storage_(storage), - references_(references) + references_(references), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { const BVHReference *ref_ptr = &references_->at(range.start()); float min_sah = FLT_MAX; @@ -51,12 +55,15 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, bvh_reference_sort(range.start(), range.end(), &references_->at(0), - dim); + dim, + unaligned_heuristic_, + aligned_space_); /* sweep right to left and determine bounds. */ BoundBox right_bounds = BoundBox::empty; for(int i = range.size() - 1; i > 0; i--) { - right_bounds.grow(ref_ptr[i].bounds()); + BoundBox prim_bounds = get_prim_bounds(ref_ptr[i]); + right_bounds.grow(prim_bounds); storage_->right_bounds[i - 1] = right_bounds; } @@ -64,7 +71,8 @@ BVHObjectSplit::BVHObjectSplit(BVHBuild *builder, BoundBox left_bounds = BoundBox::empty; for(int i = 1; i < range.size(); i++) { - left_bounds.grow(ref_ptr[i - 1].bounds()); + BoundBox prim_bounds = get_prim_bounds(ref_ptr[i - 1]); + left_bounds.grow(prim_bounds); right_bounds = storage_->right_bounds[i - 1]; float sah = nodeSAH + @@ -88,16 +96,37 @@ void BVHObjectSplit::split(BVHRange& left, BVHRange& right, const BVHRange& range) { + assert(references_->size() > 0); /* sort references according to split */ bvh_reference_sort(range.start(), range.end(), &references_->at(0), - this->dim); + this->dim, + unaligned_heuristic_, + aligned_space_); + + BoundBox effective_left_bounds, effective_right_bounds; + const int num_right = range.size() - this->num_left; + if(aligned_space_ == NULL) { + effective_left_bounds = left_bounds; + effective_right_bounds = right_bounds; + } + else { + effective_left_bounds = BoundBox::empty; + effective_right_bounds = BoundBox::empty; + for(int i = 0; i < this->num_left; ++i) { + BoundBox prim_boundbox = references_->at(range.start() + i).bounds(); + effective_left_bounds.grow(prim_boundbox); + } + for(int i = 0; i < num_right; ++i) { + BoundBox prim_boundbox = references_->at(range.start() + this->num_left + i).bounds(); + effective_right_bounds.grow(prim_boundbox); + } + } /* split node ranges */ - left = BVHRange(this->left_bounds, range.start(), this->num_left); - right = BVHRange(this->right_bounds, left.end(), range.size() - this->num_left); - + left = BVHRange(effective_left_bounds, range.start(), this->num_left); + right = BVHRange(effective_right_bounds, left.end(), num_right); } /* Spatial Split */ @@ -106,16 +135,31 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH) + float nodeSAH, + const BVHUnaligned *unaligned_heuristic, + const Transform *aligned_space) : sah(FLT_MAX), dim(0), pos(0.0f), storage_(storage), - references_(references) + references_(references), + unaligned_heuristic_(unaligned_heuristic), + aligned_space_(aligned_space) { /* initialize bins. */ - float3 origin = range.bounds().min; - float3 binSize = (range.bounds().max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS); + BoundBox range_bounds; + if(aligned_space == NULL) { + range_bounds = range.bounds(); + } + else { + range_bounds = unaligned_heuristic->compute_aligned_boundbox( + range, + &references->at(0), + *aligned_space); + } + + float3 origin = range_bounds.min; + float3 binSize = (range_bounds.max - origin) * (1.0f / (float)BVHParams::NUM_SPATIAL_BINS); float3 invBinSize = 1.0f / binSize; for(int dim = 0; dim < 3; dim++) { @@ -131,8 +175,9 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, /* chop references into bins. */ for(unsigned int refIdx = range.start(); refIdx < range.end(); refIdx++) { const BVHReference& ref = references_->at(refIdx); - float3 firstBinf = (ref.bounds().min - origin) * invBinSize; - float3 lastBinf = (ref.bounds().max - origin) * invBinSize; + BoundBox prim_bounds = get_prim_bounds(ref); + float3 firstBinf = (prim_bounds.min - origin) * invBinSize; + float3 lastBinf = (prim_bounds.max - origin) * invBinSize; int3 firstBin = make_int3((int)firstBinf.x, (int)firstBinf.y, (int)firstBinf.z); int3 lastBin = make_int3((int)lastBinf.x, (int)lastBinf.y, (int)lastBinf.z); @@ -140,7 +185,10 @@ BVHSpatialSplit::BVHSpatialSplit(const BVHBuild& builder, lastBin = clamp(lastBin, firstBin, BVHParams::NUM_SPATIAL_BINS - 1); for(int dim = 0; dim < 3; dim++) { - BVHReference currRef = ref; + BVHReference currRef(get_prim_bounds(ref), + ref.prim_index(), + ref.prim_object(), + ref.prim_type()); for(int i = firstBin[dim]; i < lastBin[dim]; i++) { BVHReference leftRef, rightRef; @@ -209,14 +257,15 @@ void BVHSpatialSplit::split(BVHBuild *builder, BoundBox right_bounds = BoundBox::empty; for(int i = left_end; i < right_start; i++) { - if(refs[i].bounds().max[this->dim] <= this->pos) { + BoundBox prim_bounds = get_prim_bounds(refs[i]); + if(prim_bounds.max[this->dim] <= this->pos) { /* entirely on the left-hand side */ - left_bounds.grow(refs[i].bounds()); + left_bounds.grow(prim_bounds); swap(refs[i], refs[left_end++]); } - else if(refs[i].bounds().min[this->dim] >= this->pos) { + else if(prim_bounds.min[this->dim] >= this->pos) { /* entirely on the right-hand side */ - right_bounds.grow(refs[i].bounds()); + right_bounds.grow(prim_bounds); swap(refs[i--], refs[--right_start]); } } @@ -231,8 +280,12 @@ void BVHSpatialSplit::split(BVHBuild *builder, new_refs.reserve(right_start - left_end); while(left_end < right_start) { /* split reference. */ + BVHReference curr_ref(get_prim_bounds(refs[left_end]), + refs[left_end].prim_index(), + refs[left_end].prim_object(), + refs[left_end].prim_type()); BVHReference lref, rref; - split_reference(*builder, lref, rref, refs[left_end], this->dim, this->pos); + split_reference(*builder, lref, rref, curr_ref, this->dim, this->pos); /* compute SAH for duplicate/unsplit candidates. */ BoundBox lub = left_bounds; // Unsplit to left: new left-hand bounds. @@ -240,8 +293,8 @@ void BVHSpatialSplit::split(BVHBuild *builder, BoundBox ldb = left_bounds; // Duplicate: new left-hand bounds. BoundBox rdb = right_bounds; // Duplicate: new right-hand bounds. - lub.grow(refs[left_end].bounds()); - rub.grow(refs[left_end].bounds()); + lub.grow(curr_ref.bounds()); + rub.grow(curr_ref.bounds()); ldb.grow(lref.bounds()); rdb.grow(rref.bounds()); @@ -280,6 +333,17 @@ void BVHSpatialSplit::split(BVHBuild *builder, new_refs.begin(), new_refs.end()); } + if(aligned_space_ != NULL) { + left_bounds = right_bounds = BoundBox::empty; + for(int i = left_start; i < left_end - left_start; ++i) { + BoundBox prim_boundbox = references_->at(i).bounds(); + left_bounds.grow(prim_boundbox); + } + for(int i = right_start; i < right_end - right_start; ++i) { + BoundBox prim_boundbox = references_->at(i).bounds(); + right_bounds.grow(prim_boundbox); + } + } left = BVHRange(left_bounds, left_start, left_end - left_start); right = BVHRange(right_bounds, right_start, right_end - right_start); } @@ -295,11 +359,13 @@ void BVHSpatialSplit::split_triangle_primitive(const Mesh *mesh, Mesh::Triangle t = mesh->get_triangle(prim_index); const float3 *verts = &mesh->verts[0]; float3 v1 = tfm ? transform_point(tfm, verts[t.v[2]]) : verts[t.v[2]]; + v1 = get_unaligned_point(v1); for(int i = 0; i < 3; i++) { float3 v0 = v1; int vindex = t.v[i]; v1 = tfm ? transform_point(tfm, verts[vindex]) : verts[vindex]; + v1 = get_unaligned_point(v1); float v0p = v0[dim]; float v1p = v1[dim]; @@ -339,6 +405,8 @@ void BVHSpatialSplit::split_curve_primitive(const Mesh *mesh, v0 = transform_point(tfm, v0); v1 = transform_point(tfm, v1); } + v0 = get_unaligned_point(v0); + v1 = get_unaligned_point(v1); float v0p = v0[dim]; float v1p = v1[dim]; @@ -473,6 +541,7 @@ void BVHSpatialSplit::split_reference(const BVHBuild& builder, /* intersect with original bounds. */ left_bounds.max[dim] = pos; right_bounds.min[dim] = pos; + left_bounds.intersect(ref.bounds()); right_bounds.intersect(ref.bounds()); diff --git a/intern/cycles/bvh/bvh_split.h b/intern/cycles/bvh/bvh_split.h index aea8b2565e0..dbdb51f1a5b 100644 --- a/intern/cycles/bvh/bvh_split.h +++ b/intern/cycles/bvh/bvh_split.h @@ -24,6 +24,7 @@ CCL_NAMESPACE_BEGIN class BVHBuild; +struct Transform; /* Object Split */ @@ -41,7 +42,9 @@ public: BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH); + float nodeSAH, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); void split(BVHRange& left, BVHRange& right, @@ -50,6 +53,19 @@ public: protected: BVHSpatialStorage *storage_; vector<BVHReference> *references_; + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } }; /* Spatial Split */ @@ -70,7 +86,9 @@ public: BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - float nodeSAH); + float nodeSAH, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL); void split(BVHBuild *builder, BVHRange& left, @@ -87,6 +105,8 @@ public: protected: BVHSpatialStorage *storage_; vector<BVHReference> *references_; + const BVHUnaligned *unaligned_heuristic_; + const Transform *aligned_space_; /* Lower-level functions which calculates boundaries of left and right nodes * needed for spatial split. @@ -132,6 +152,27 @@ protected: float pos, BoundBox& left_bounds, BoundBox& right_bounds); + + __forceinline BoundBox get_prim_bounds(const BVHReference& prim) const + { + if(aligned_space_ == NULL) { + return prim.bounds(); + } + else { + return unaligned_heuristic_->compute_aligned_prim_boundbox( + prim, *aligned_space_); + } + } + + __forceinline float3 get_unaligned_point(const float3& point) const + { + if(aligned_space_ == NULL) { + return point; + } + else { + return transform_point(aligned_space_, point); + } + } }; /* Mixed Object-Spatial Split */ @@ -148,19 +189,40 @@ public: bool no_split; + BoundBox bounds; + + BVHMixedSplit() {} + __forceinline BVHMixedSplit(BVHBuild *builder, BVHSpatialStorage *storage, const BVHRange& range, vector<BVHReference> *references, - int level) + int level, + const BVHUnaligned *unaligned_heuristic = NULL, + const Transform *aligned_space = NULL) { + if(aligned_space == NULL) { + bounds = range.bounds(); + } + else { + bounds = unaligned_heuristic->compute_aligned_boundbox( + range, + &references->at(0), + *aligned_space); + } /* find split candidates. */ - float area = range.bounds().safe_area(); + float area = bounds.safe_area(); leafSAH = area * builder->params.primitive_cost(range.size()); nodeSAH = area * builder->params.node_cost(2); - object = BVHObjectSplit(builder, storage, range, references, nodeSAH); + object = BVHObjectSplit(builder, + storage, + range, + references, + nodeSAH, + unaligned_heuristic, + aligned_space); if(builder->params.use_spatial_split && level < BVHParams::MAX_SPATIAL_DEPTH) { BoundBox overlap = object.left_bounds; @@ -171,7 +233,9 @@ public: storage, range, references, - nodeSAH); + nodeSAH, + unaligned_heuristic, + aligned_space); } } @@ -181,7 +245,10 @@ public: builder->range_within_max_leaf_size(range, *references)); } - __forceinline void split(BVHBuild *builder, BVHRange& left, BVHRange& right, const BVHRange& range) + __forceinline void split(BVHBuild *builder, + BVHRange& left, + BVHRange& right, + const BVHRange& range) { if(builder->params.use_spatial_split && minSAH == spatial.sah) spatial.split(builder, left, right, range); @@ -193,4 +260,3 @@ public: CCL_NAMESPACE_END #endif /* __BVH_SPLIT_H__ */ - diff --git a/intern/cycles/bvh/bvh_unaligned.cpp b/intern/cycles/bvh/bvh_unaligned.cpp new file mode 100644 index 00000000000..a876c670914 --- /dev/null +++ b/intern/cycles/bvh/bvh_unaligned.cpp @@ -0,0 +1,178 @@ +/* + * Copyright 2011-2016 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. + */ + + +#include "bvh_unaligned.h" + +#include "mesh.h" +#include "object.h" + +#include "bvh_binning.h" +#include "bvh_params.h" + +#include "util_boundbox.h" +#include "util_debug.h" +#include "util_transform.h" + +CCL_NAMESPACE_BEGIN + + +BVHUnaligned::BVHUnaligned(const vector<Object*>& objects) + : objects_(objects) +{ +} + +Transform BVHUnaligned::compute_aligned_space( + const BVHObjectBinning& range, + const BVHReference *references) const +{ + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + Transform aligned_space; + /* Use first primitive which defines correct direction to define + * the orientation space. + */ + if(compute_aligned_space(ref, &aligned_space)) { + return aligned_space; + } + } + return transform_identity(); +} + +Transform BVHUnaligned::compute_aligned_space( + const BVHRange& range, + const BVHReference *references) const +{ + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + Transform aligned_space; + /* Use first primitive which defines correct direction to define + * the orientation space. + */ + if(compute_aligned_space(ref, &aligned_space)) { + return aligned_space; + } + } + return transform_identity(); +} + +bool BVHUnaligned::compute_aligned_space(const BVHReference& ref, + Transform *aligned_space) const +{ + const Object *object = objects_[ref.prim_object()]; + const int packed_type = ref.prim_type(); + const int type = (packed_type & PRIMITIVE_ALL); + if(type & PRIMITIVE_CURVE) { + const int curve_index = ref.prim_index(); + const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); + const Mesh *mesh = object->mesh; + const Mesh::Curve& curve = mesh->get_curve(curve_index); + const int key = curve.first_key + segment; + const float3 v1 = mesh->curve_keys[key], + v2 = mesh->curve_keys[key + 1]; + float length; + const float3 axis = normalize_len(v2 - v1, &length); + if(length > 1e-6f) { + *aligned_space = make_transform_frame(axis); + return true; + } + } + *aligned_space = transform_identity(); + return false; +} + +BoundBox BVHUnaligned::compute_aligned_prim_boundbox( + const BVHReference& prim, + const Transform& aligned_space) const +{ + BoundBox bounds = BoundBox::empty; + const Object *object = objects_[prim.prim_object()]; + const int packed_type = prim.prim_type(); + const int type = (packed_type & PRIMITIVE_ALL); + if(type & PRIMITIVE_CURVE) { + const int curve_index = prim.prim_index(); + const int segment = PRIMITIVE_UNPACK_SEGMENT(packed_type); + const Mesh *mesh = object->mesh; + const Mesh::Curve& curve = mesh->get_curve(curve_index); + curve.bounds_grow(segment, + &mesh->curve_keys[0], + &mesh->curve_radius[0], + aligned_space, + bounds); + } + else { + bounds = prim.bounds().transformed(&aligned_space); + } + return bounds; +} + +BoundBox BVHUnaligned::compute_aligned_boundbox( + const BVHObjectBinning& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds) const +{ + BoundBox bounds = BoundBox::empty; + if(cent_bounds != NULL) { + *cent_bounds = BoundBox::empty; + } + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space); + bounds.grow(ref_bounds); + if(cent_bounds != NULL) { + cent_bounds->grow(ref_bounds.center2()); + } + } + return bounds; +} + +BoundBox BVHUnaligned::compute_aligned_boundbox( + const BVHRange& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds) const +{ + BoundBox bounds = BoundBox::empty; + if(cent_bounds != NULL) { + *cent_bounds = BoundBox::empty; + } + for(int i = range.start(); i < range.end(); ++i) { + const BVHReference& ref = references[i]; + BoundBox ref_bounds = compute_aligned_prim_boundbox(ref, aligned_space); + bounds.grow(ref_bounds); + if(cent_bounds != NULL) { + cent_bounds->grow(ref_bounds.center2()); + } + } + return bounds; +} + +Transform BVHUnaligned::compute_node_transform( + const BoundBox& bounds, + const Transform& aligned_space) +{ + Transform space = aligned_space; + space.x.w -= bounds.min.x; + space.y.w -= bounds.min.y; + space.z.w -= bounds.min.z; + float3 dim = bounds.max - bounds.min; + return transform_scale(1.0f / max(1e-18f, dim.x), + 1.0f / max(1e-18f, dim.y), + 1.0f / max(1e-18f, dim.z)) * space; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/bvh/bvh_unaligned.h b/intern/cycles/bvh/bvh_unaligned.h new file mode 100644 index 00000000000..4d0872f4a39 --- /dev/null +++ b/intern/cycles/bvh/bvh_unaligned.h @@ -0,0 +1,81 @@ +/* + * Copyright 2011-2016 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. + */ + +#ifndef __BVH_UNALIGNED_H__ +#define __BVH_UNALIGNED_H__ + +#include "util_vector.h" + +CCL_NAMESPACE_BEGIN + +class BoundBox; +class BVHObjectBinning; +class BVHRange; +class BVHReference; +struct Transform; +class Object; + +/* Helper class to perform calculations needed for unaligned nodes. */ +class BVHUnaligned { +public: + BVHUnaligned(const vector<Object*>& objects); + + /* Calculate alignment for the oriented node for a given range. */ + Transform compute_aligned_space( + const BVHObjectBinning& range, + const BVHReference *references) const; + Transform compute_aligned_space( + const BVHRange& range, + const BVHReference *references) const; + + /* Calculate alignment for the oriented node for a given reference. + * + * Return true when space was calculated successfully. + */ + bool compute_aligned_space(const BVHReference& ref, + Transform *aligned_space) const; + + /* Calculate primitive's bounding box in given space. */ + BoundBox compute_aligned_prim_boundbox( + const BVHReference& prim, + const Transform& aligned_space) const; + + /* Calculate bounding box in given space. */ + BoundBox compute_aligned_boundbox( + const BVHObjectBinning& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds = NULL) const; + BoundBox compute_aligned_boundbox( + const BVHRange& range, + const BVHReference *references, + const Transform& aligned_space, + BoundBox *cent_bounds = NULL) const; + + /* Calculate affine transform for node packing. + * Bounds will be in the range of 0..1. + */ + static Transform compute_node_transform(const BoundBox& bounds, + const Transform& aligned_space); +protected: + /* List of objects BVH is being created for. */ + const vector<Object*>& objects_; +}; + +CCL_NAMESPACE_END + +#endif /* __BVH_UNALIGNED_H__ */ + diff --git a/intern/cycles/device/device_memory.h b/intern/cycles/device/device_memory.h index 8c32d03135e..5b5b4dc6802 100644 --- a/intern/cycles/device/device_memory.h +++ b/intern/cycles/device/device_memory.h @@ -150,6 +150,11 @@ template<> struct device_type_traits<float4> { static const int num_elements = 4; }; +template<> struct device_type_traits<half> { + static const DataType data_type = TYPE_HALF; + static const int num_elements = 1; +}; + template<> struct device_type_traits<half4> { static const DataType data_type = TYPE_HALF; static const int num_elements = 4; diff --git a/intern/cycles/device/device_opencl.cpp b/intern/cycles/device/device_opencl.cpp index afe21c49730..50490f3a20e 100644 --- a/intern/cycles/device/device_opencl.cpp +++ b/intern/cycles/device/device_opencl.cpp @@ -795,7 +795,7 @@ public: bool load_binary(const string& /*kernel_path*/, const string& clbin, - string custom_kernel_build_options, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { @@ -848,7 +848,7 @@ public: } bool build_kernel(cl_program *kernel_program, - string custom_kernel_build_options, + const string& custom_kernel_build_options, const string *debug_src = NULL) { string build_options; @@ -881,30 +881,39 @@ public: return true; } - bool compile_kernel(const string& kernel_path, - string source, - string custom_kernel_build_options, + bool compile_kernel(const string& kernel_name, + const string& kernel_path, + const string& source, + const string& custom_kernel_build_options, cl_program *kernel_program, const string *debug_src = NULL) { - /* we compile kernels consisting of many files. unfortunately opencl + /* We compile kernels consisting of many files. unfortunately OpenCL * kernel caches do not seem to recognize changes in included files. - * so we force recompile on changes by adding the md5 hash of all files */ - source = path_source_replace_includes(source, kernel_path); + * so we force recompile on changes by adding the md5 hash of all files. + */ + string inlined_source = path_source_replace_includes(source, + kernel_path); - if(debug_src) - path_write_text(*debug_src, source); + if(debug_src) { + path_write_text(*debug_src, inlined_source); + } - size_t source_len = source.size(); - const char *source_str = source.c_str(); + size_t source_len = inlined_source.size(); + const char *source_str = inlined_source.c_str(); - *kernel_program = clCreateProgramWithSource(cxContext, 1, &source_str, &source_len, &ciErr); + *kernel_program = clCreateProgramWithSource(cxContext, + 1, + &source_str, + &source_len, + &ciErr); - if(opencl_error(ciErr)) + if(opencl_error(ciErr)) { return false; + } double starttime = time_dt(); - printf("Compiling OpenCL kernel ...\n"); + printf("Compiling %s OpenCL kernel ...\n", kernel_name.c_str()); /* TODO(sergey): Report which kernel is being compiled * as well (megakernel or which of split kernels etc..). */ @@ -1004,7 +1013,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("base_kernel", + kernel_path, init_kernel_source, build_flags, &cpProgram, @@ -1694,7 +1704,8 @@ public: string init_kernel_source = "#include \"kernels/opencl/kernel.cl\" // " + kernel_md5 + "\n"; /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel("mega_kernel", + kernel_path, init_kernel_source, custom_kernel_build_options, &path_trace_program, @@ -2078,30 +2089,33 @@ public: /* TODO(sergey): Seems really close to load_kernel(), * could it be de-duplicated? */ - bool load_split_kernel(string kernel_path, - string kernel_init_source, - string clbin, - string custom_kernel_build_options, + bool load_split_kernel(const string& kernel_name, + const string& kernel_path, + const string& kernel_init_source, + const string& clbin, + const string& custom_kernel_build_options, cl_program *program, const string *debug_src = NULL) { - if(!opencl_version_check()) + if(!opencl_version_check()) { return false; + } - clbin = path_user_get(path_join("cache", clbin)); + string cache_clbin = path_user_get(path_join("cache", clbin)); /* If exists already, try use it. */ - if(path_exists(clbin) && load_binary(kernel_path, - clbin, - custom_kernel_build_options, - program, - debug_src)) + if(path_exists(cache_clbin) && load_binary(kernel_path, + cache_clbin, + custom_kernel_build_options, + program, + debug_src)) { /* Kernel loaded from binary. */ } else { /* If does not exist or loading binary failed, compile kernel. */ - if(!compile_kernel(kernel_path, + if(!compile_kernel(kernel_name, + kernel_path, kernel_init_source, custom_kernel_build_options, program, @@ -2110,7 +2124,7 @@ public: return false; } /* Save binary for reuse. */ - if(!save_binary(program, clbin)) { + if(!save_binary(program, cache_clbin)) { return false; } } @@ -2208,7 +2222,10 @@ public: clsrc = path_user_get(path_join("cache", clsrc)); \ debug_src = &clsrc; \ } \ - if(!load_split_kernel(kernel_path, kernel_init_source, clbin, \ + if(!load_split_kernel(#name, \ + kernel_path, \ + kernel_init_source, \ + clbin, \ build_options, \ &GLUE(name, _program), \ debug_src)) \ diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp index 6c6035fdb22..5b98de778ad 100644 --- a/intern/cycles/graph/node_type.cpp +++ b/intern/cycles/graph/node_type.cpp @@ -89,6 +89,7 @@ ustring SocketType::type_name(Type type) ustring("boolean"), ustring("float"), ustring("int"), + ustring("uint"), ustring("color"), ustring("vector"), ustring("point"), diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 61c484df094..bd3969b2889 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -28,6 +28,22 @@ set(SRC kernels/cuda/kernel.cu ) +set(SRC_BVH_HEADERS + bvh/bvh.h + bvh/bvh_nodes.h + bvh/bvh_shadow_all.h + bvh/bvh_subsurface.h + bvh/bvh_traversal.h + bvh/bvh_volume.h + bvh/bvh_volume_all.h + bvh/qbvh_nodes.h + bvh/qbvh_shadow_all.h + bvh/qbvh_subsurface.h + bvh/qbvh_traversal.h + bvh/qbvh_volume.h + bvh/qbvh_volume_all.h +) + set(SRC_HEADERS kernel_accumulate.h kernel_bake.h @@ -76,6 +92,8 @@ set(SRC_CLOSURE_HEADERS closure/bsdf_diffuse.h closure/bsdf_diffuse_ramp.h closure/bsdf_microfacet.h + closure/bsdf_microfacet_multi.h + closure/bsdf_microfacet_multi_impl.h closure/bsdf_oren_nayar.h closure/bsdf_phong_ramp.h closure/bsdf_reflection.h @@ -98,6 +116,7 @@ set(SRC_SVM_HEADERS svm/svm_closure.h svm/svm_convert.h svm/svm_checker.h + svm/svm_color_util.h svm/svm_brick.h svm/svm_displace.h svm/svm_fresnel.h @@ -137,23 +156,11 @@ set(SRC_SVM_HEADERS set(SRC_GEOM_HEADERS geom/geom.h geom/geom_attribute.h - geom/geom_bvh.h - geom/geom_bvh_shadow.h - geom/geom_bvh_subsurface.h - geom/geom_bvh_traversal.h - geom/geom_bvh_volume.h - geom/geom_bvh_volume_all.h geom/geom_curve.h geom/geom_motion_curve.h geom/geom_motion_triangle.h geom/geom_object.h geom/geom_primitive.h - geom/geom_qbvh.h - geom/geom_qbvh_shadow.h - geom/geom_qbvh_subsurface.h - geom/geom_qbvh_traversal.h - geom/geom_qbvh_volume.h - geom/geom_qbvh_volume_all.h geom/geom_triangle.h geom/geom_triangle_intersect.h geom/geom_volume.h @@ -209,7 +216,14 @@ if(WITH_CYCLES_CUDA_BINARIES) endif() # build for each arch - set(cuda_sources kernels/cuda/kernel.cu ${SRC_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_UTIL_HEADERS}) + set(cuda_sources kernels/cuda/kernel.cu + ${SRC_HEADERS} + ${SRC_BVH_HEADERS} + ${SRC_SVM_HEADERS} + ${SRC_GEOM_HEADERS} + ${SRC_CLOSURE_HEADERS} + ${SRC_UTIL_HEADERS} + ) set(cuda_cubins) macro(CYCLES_CUDA_KERNEL_ADD arch experimental) @@ -309,6 +323,7 @@ add_library(cycles_kernel ${SRC} ${SRC_HEADERS} ${SRC_KERNELS_CPU_HEADERS} + ${SRC_BVH_HEADERS} ${SRC_CLOSURE_HEADERS} ${SRC_SVM_HEADERS} ${SRC_GEOM_HEADERS} @@ -343,6 +358,7 @@ delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_next_iteratio delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/opencl/kernel_sum_all_radiance.cl" ${CYCLES_INSTALL_PATH}/kernel/kernels/opencl) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "kernels/cuda/kernel.cu" ${CYCLES_INSTALL_PATH}/kernel/kernels/cuda) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel) +delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_BVH_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/bvh) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_CLOSURE_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/closure) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_SVM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/svm) delayed_install(${CMAKE_CURRENT_SOURCE_DIR} "${SRC_GEOM_HEADERS}" ${CYCLES_INSTALL_PATH}/kernel/geom) diff --git a/intern/cycles/kernel/geom/geom_bvh.h b/intern/cycles/kernel/bvh/bvh.h index d0eedd3396a..59881738195 100644 --- a/intern/cycles/kernel/geom/geom_bvh.h +++ b/intern/cycles/kernel/bvh/bvh.h @@ -35,6 +35,13 @@ CCL_NAMESPACE_BEGIN # define ccl_device_intersect ccl_device_inline #endif +/* bottom-most stack entry, indicating the end of traversal */ +#define ENTRYPOINT_SENTINEL 0x76543210 + +/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ +#define BVH_STACK_SIZE 192 +#define BVH_QSTACK_SIZE 384 + /* BVH intersection function variations */ #define BVH_INSTANCING 1 @@ -72,71 +79,73 @@ CCL_NAMESPACE_BEGIN /* Common QBVH functions. */ #ifdef __QBVH__ -# include "geom_qbvh.h" +# include "qbvh_nodes.h" #endif /* Regular BVH traversal */ +#include "bvh_nodes.h" + #define BVH_FUNCTION_NAME bvh_intersect #define BVH_FUNCTION_FEATURES 0 -#include "geom_bvh_traversal.h" +#include "bvh_traversal.h" #if defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif #if defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_HAIR_MINIMUM_WIDTH|BVH_MOTION -# include "geom_bvh_traversal.h" +# include "bvh_traversal.h" #endif /* Subsurface scattering BVH traversal */ #if defined(__SUBSURFACE__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_subsurface.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_subsurface.h" #endif #if defined(__SUBSURFACE__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_subsurface_motion -# define BVH_FUNCTION_FEATURES BVH_MOTION -# include "geom_bvh_subsurface.h" +# define BVH_FUNCTION_FEATURES BVH_MOTION|BVH_HAIR +# include "bvh_subsurface.h" #endif /* Volume BVH traversal */ #if defined(__VOLUME__) # define BVH_FUNCTION_NAME bvh_intersect_volume -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_volume.h" #endif #if defined(__VOLUME__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_instancing -# define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR +# include "bvh_volume.h" #endif #if defined(__VOLUME__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_motion -# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_volume.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR +# include "bvh_volume.h" #endif /* Record all intersections - Shadow BVH traversal */ @@ -144,51 +153,51 @@ CCL_NAMESPACE_BEGIN #if defined(__SHADOW_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all # define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_instancing # define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif #if defined(__SHADOW_RECORD_ALL__) && defined(__HAIR__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_shadow_all_hair_motion # define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR|BVH_MOTION -# include "geom_bvh_shadow.h" +# include "bvh_shadow_all.h" #endif /* Record all intersections - Volume BVH traversal */ #if defined(__VOLUME_RECORD_ALL__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all -# define BVH_FUNCTION_FEATURES 0 -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_HAIR +# include "bvh_volume_all.h" #endif #if defined(__VOLUME_RECORD_ALL__) && defined(__INSTANCING__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_instancing -# define BVH_FUNCTION_FEATURES BVH_INSTANCING -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_HAIR +# include "bvh_volume_all.h" #endif #if defined(__VOLUME_RECORD_ALL__) && defined(__OBJECT_MOTION__) # define BVH_FUNCTION_NAME bvh_intersect_volume_all_motion -# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION -# include "geom_bvh_volume_all.h" +# define BVH_FUNCTION_FEATURES BVH_INSTANCING|BVH_MOTION|BVH_HAIR +# include "bvh_volume_all.h" #endif #undef BVH_FEATURE diff --git a/intern/cycles/kernel/bvh/bvh_nodes.h b/intern/cycles/kernel/bvh/bvh_nodes.h new file mode 100644 index 00000000000..db2275b0ff8 --- /dev/null +++ b/intern/cycles/kernel/bvh/bvh_nodes.h @@ -0,0 +1,656 @@ +/* + * Copyright 2011-2016, 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. + */ + +// TODO(sergey): Look into avoid use of full Transform and use 3x3 matrix and +// 3-vector which might be faster. +ccl_device_inline Transform bvh_unaligned_node_fetch_space(KernelGlobals *kg, + int node_addr, + int child) +{ + Transform space; + const int child_addr = node_addr + child * 3; + space.x = kernel_tex_fetch(__bvh_nodes, child_addr+1); + space.y = kernel_tex_fetch(__bvh_nodes, child_addr+2); + space.z = kernel_tex_fetch(__bvh_nodes, child_addr+3); + space.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f); + return space; +} + +#if !defined(__KERNEL_SSE2__) +ccl_device_inline int bvh_aligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + + /* fetch node data */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1); + float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2); + float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3); + + /* intersect ray against child nodes */ + float c0lox = (node0.x - P.x) * idir.x; + float c0hix = (node0.z - P.x) * idir.x; + float c0loy = (node1.x - P.y) * idir.y; + float c0hiy = (node1.z - P.y) * idir.y; + float c0loz = (node2.x - P.z) * idir.z; + float c0hiz = (node2.z - P.z) * idir.z; + float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); + float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + + float c1lox = (node0.y - P.x) * idir.x; + float c1hix = (node0.w - P.x) * idir.x; + float c1loy = (node1.y - P.y) * idir.y; + float c1hiy = (node1.w - P.y) * idir.y; + float c1loz = (node2.y - P.z) * idir.z; + float c1hiz = (node2.w - P.z) * idir.z; + float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); + float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + + dist[0] = c0min; + dist[1] = c1min; + +#ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); +#else + return ((c0max >= c0min)? 1: 0) | + ((c1max >= c1min)? 2: 0); +#endif +} + +ccl_device_inline int bvh_aligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + + /* fetch node data */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 node0 = kernel_tex_fetch(__bvh_nodes, node_addr+1); + float4 node1 = kernel_tex_fetch(__bvh_nodes, node_addr+2); + float4 node2 = kernel_tex_fetch(__bvh_nodes, node_addr+3); + + /* intersect ray against child nodes */ + float c0lox = (node0.x - P.x) * idir.x; + float c0hix = (node0.z - P.x) * idir.x; + float c0loy = (node1.x - P.y) * idir.y; + float c0hiy = (node1.z - P.y) * idir.y; + float c0loz = (node2.x - P.z) * idir.z; + float c0hiz = (node2.z - P.z) * idir.z; + float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); + float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); + + float c1lox = (node0.y - P.x) * idir.x; + float c1hix = (node0.w - P.x) * idir.x; + float c1loy = (node1.y - P.y) * idir.y; + float c1hiy = (node1.w - P.y) * idir.y; + float c1loz = (node2.y - P.z) * idir.z; + float c1hiz = (node2.w - P.z) * idir.z; + float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); + float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); + + if(difl != 0.0f) { + float hdiff = 1.0f + difl; + float ldiff = 1.0f - difl; + if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { + c0min = max(ldiff * c0min, c0min - extmax); + c0max = min(hdiff * c0max, c0max + extmax); + } + if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { + c1min = max(ldiff * c1min, c1min - extmax); + c1max = min(hdiff * c1max, c1max + extmax); + } + } + + dist[0] = c0min; + dist[1] = c1min; + +#ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + return (((c0max >= c0min) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((c1max >= c1min) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); +#else + return ((c0max >= c0min)? 1: 0) | + ((c1max >= c1min)? 2: 0); +#endif +} + +ccl_device_inline bool bvh_unaligned_node_intersect_child( + KernelGlobals *kg, + const float3 P, + const float3 dir, + const float t, + int node_addr, + int child, + float dist[2]) +{ + Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child); + float3 aligned_dir = transform_direction(&space, dir); + float3 aligned_P = transform_point(&space, P); + float3 nrdir = -bvh_inverse_direction(aligned_dir); + float3 lower_xyz = aligned_P * nrdir; + float3 upper_xyz = lower_xyz - nrdir; + const float near_x = min(lower_xyz.x, upper_xyz.x); + const float near_y = min(lower_xyz.y, upper_xyz.y); + const float near_z = min(lower_xyz.z, upper_xyz.z); + const float far_x = max(lower_xyz.x, upper_xyz.x); + const float far_y = max(lower_xyz.y, upper_xyz.y); + const float far_z = max(lower_xyz.z, upper_xyz.z); + const float tnear = max4(0.0f, near_x, near_y, near_z); + const float tfar = min4(t, far_x, far_y, far_z); + *dist = tnear; + return tnear <= tfar; +} + +ccl_device_inline bool bvh_unaligned_node_intersect_child_robust( + KernelGlobals *kg, + const float3 P, + const float3 dir, + const float t, + const float difl, + int node_addr, + int child, + float dist[2]) +{ + Transform space = bvh_unaligned_node_fetch_space(kg, node_addr, child); + float3 aligned_dir = transform_direction(&space, dir); + float3 aligned_P = transform_point(&space, P); + float3 nrdir = -bvh_inverse_direction(aligned_dir); + float3 tLowerXYZ = aligned_P * nrdir; + float3 tUpperXYZ = tLowerXYZ - nrdir; + const float near_x = min(tLowerXYZ.x, tUpperXYZ.x); + const float near_y = min(tLowerXYZ.y, tUpperXYZ.y); + const float near_z = min(tLowerXYZ.z, tUpperXYZ.z); + const float far_x = max(tLowerXYZ.x, tUpperXYZ.x); + const float far_y = max(tLowerXYZ.y, tUpperXYZ.y); + const float far_z = max(tLowerXYZ.z, tUpperXYZ.z); + const float tnear = max4(0.0f, near_x, near_y, near_z); + const float tfar = min4(t, far_x, far_y, far_z); + *dist = tnear; + if(difl != 0.0f) { + /* TODO(sergey): Same as for QBVH, needs a proper use. */ + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + return round_down*tnear <= round_up*tfar; + } + else { + return tnear <= tfar; + } +} + +ccl_device_inline int bvh_unaligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + int mask = 0; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 0, &dist[0])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.x) & visibility)) +#endif + { + mask |= 1; + } + } + if(bvh_unaligned_node_intersect_child(kg, P, dir, t, node_addr, 1, &dist[1])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.y) & visibility)) +#endif + { + mask |= 2; + } + } + return mask; +} + +ccl_device_inline int bvh_unaligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + int mask = 0; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 0, &dist[0])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.x) & visibility)) +#endif + { + mask |= 1; + } + } + if(bvh_unaligned_node_intersect_child_robust(kg, P, dir, t, difl, node_addr, 1, &dist[1])) { +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(cnodes.y) & visibility)) +#endif + { + mask |= 2; + } + } + return mask; +} + +ccl_device_inline int bvh_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect(kg, + P, + dir, + idir, + t, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect(kg, + P, + idir, + t, + node_addr, + visibility, + dist); + } +} + +ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const float3 idir, + const float t, + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect_robust(kg, + P, + dir, + idir, + t, + difl, + extmax, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect_robust(kg, + P, + idir, + t, + difl, + extmax, + node_addr, + visibility, + dist); + } +} +#else /* !defined(__KERNEL_SSE2__) */ + +int ccl_device_inline bvh_aligned_node_intersect( + KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const int node_addr, + const uint visibility, + float dist[2]) +{ + /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); + + /* fetch node data */ + const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + node_addr; + + /* intersect ray against child nodes */ + const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; + const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; + const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; + + /* calculate { c0min, c1min, -c0max, -c1max} */ + ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); + const ssef tminmax = minmax ^ pn; + const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); + + dist[0] = tminmax[0]; + dist[1] = tminmax[1]; + + int mask = movemask(lrhit); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_aligned_node_intersect_robust( + KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const float difl, + const float extmax, + const int nodeAddr, + const uint visibility, + float dist[2]) +{ + /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); + + /* fetch node data */ + const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr; + + /* intersect ray against child nodes */ + const ssef tminmaxx = (shuffle_swap(bvh_nodes[1], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; + const ssef tminmaxy = (shuffle_swap(bvh_nodes[2], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; + const ssef tminmaxz = (shuffle_swap(bvh_nodes[3], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; + + /* calculate { c0min, c1min, -c0max, -c1max} */ + ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); + const ssef tminmax = minmax ^ pn; + + if(difl != 0.0f) { + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0); + float4 *tminmaxview = (float4*)&tminmax; + float& c0min = tminmaxview->x, &c1min = tminmaxview->y; + float& c0max = tminmaxview->z, &c1max = tminmaxview->w; + float hdiff = 1.0f + difl; + float ldiff = 1.0f - difl; + if(__float_as_int(cnodes.x) & PATH_RAY_CURVE) { + c0min = max(ldiff * c0min, c0min - extmax); + c0max = min(hdiff * c0max, c0max + extmax); + } + if(__float_as_int(cnodes.y) & PATH_RAY_CURVE) { + c1min = max(ldiff * c1min, c1min - extmax); + c1max = min(hdiff * c1max, c1max + extmax); + } + } + + const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); + + dist[0] = tminmax[0]; + dist[1] = tminmax[1]; + + int mask = movemask(lrhit); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_unaligned_node_intersect(KernelGlobals *kg, + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const int node_addr, + const uint visibility, + float dist[2]) +{ + Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); + Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); + + float3 aligned_dir0 = transform_direction(&space0, dir), + aligned_dir1 = transform_direction(&space1, dir);; + float3 aligned_P0 = transform_point(&space0, P), + aligned_P1 = transform_point(&space1, P); + float3 nrdir0 = -bvh_inverse_direction(aligned_dir0), + nrdir1 = -bvh_inverse_direction(aligned_dir1); + + ssef lower_x = ssef(aligned_P0.x * nrdir0.x, + aligned_P1.x * nrdir1.x, + 0.0f, 0.0f), + lower_y = ssef(aligned_P0.y * nrdir0.y, + aligned_P1.y * nrdir1.y, + 0.0f, + 0.0f), + lower_z = ssef(aligned_P0.z * nrdir0.z, + aligned_P1.z * nrdir1.z, + 0.0f, + 0.0f); + + ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f), + upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f), + upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f); + + ssef tnear_x = min(lower_x, upper_x); + ssef tnear_y = min(lower_y, upper_y); + ssef tnear_z = min(lower_z, upper_z); + ssef tfar_x = max(lower_x, upper_x); + ssef tfar_y = max(lower_y, upper_y); + ssef tfar_z = max(lower_z, upper_z); + + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + sseb vmask = tnear <= tfar; + dist[0] = tnear.f[0]; + dist[1] = tnear.f[1]; + + int mask = (int)movemask(vmask); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +int ccl_device_inline bvh_unaligned_node_intersect_robust(KernelGlobals *kg, + const float3 P, + const float3 dir, + const ssef& isect_near, + const ssef& isect_far, + const float difl, + const int node_addr, + const uint visibility, + float dist[2]) +{ + Transform space0 = bvh_unaligned_node_fetch_space(kg, node_addr, 0); + Transform space1 = bvh_unaligned_node_fetch_space(kg, node_addr, 1); + + float3 aligned_dir0 = transform_direction(&space0, dir), + aligned_dir1 = transform_direction(&space1, dir);; + float3 aligned_P0 = transform_point(&space0, P), + aligned_P1 = transform_point(&space1, P); + float3 nrdir0 = -bvh_inverse_direction(aligned_dir0), + nrdir1 = -bvh_inverse_direction(aligned_dir1); + + ssef lower_x = ssef(aligned_P0.x * nrdir0.x, + aligned_P1.x * nrdir1.x, + 0.0f, 0.0f), + lower_y = ssef(aligned_P0.y * nrdir0.y, + aligned_P1.y * nrdir1.y, + 0.0f, + 0.0f), + lower_z = ssef(aligned_P0.z * nrdir0.z, + aligned_P1.z * nrdir1.z, + 0.0f, + 0.0f); + + ssef upper_x = lower_x - ssef(nrdir0.x, nrdir1.x, 0.0f, 0.0f), + upper_y = lower_y - ssef(nrdir0.y, nrdir1.y, 0.0f, 0.0f), + upper_z = lower_z - ssef(nrdir0.z, nrdir1.z, 0.0f, 0.0f); + + ssef tnear_x = min(lower_x, upper_x); + ssef tnear_y = min(lower_y, upper_y); + ssef tnear_z = min(lower_z, upper_z); + ssef tfar_x = max(lower_x, upper_x); + ssef tfar_y = max(lower_y, upper_y); + ssef tfar_z = max(lower_z, upper_z); + + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + sseb vmask; + if(difl != 0.0f) { + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + vmask = round_down*tnear <= round_up*tfar; + } + else { + vmask = tnear <= tfar; + } + + dist[0] = tnear.f[0]; + dist[1] = tnear.f[1]; + + int mask = (int)movemask(vmask); + +# ifdef __VISIBILITY_FLAG__ + /* this visibility test gives a 5% performance hit, how to solve? */ + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + int cmask = (((mask & 1) && (__float_as_uint(cnodes.x) & visibility))? 1: 0) | + (((mask & 2) && (__float_as_uint(cnodes.y) & visibility))? 2: 0); + return cmask; +# else + return mask & 3; +# endif +} + +ccl_device_inline int bvh_node_intersect(KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect(kg, + P, + dir, + isect_near, + isect_far, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect(kg, + P, + dir, + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); + } +} + +ccl_device_inline int bvh_node_intersect_robust(KernelGlobals *kg, + const float3& P, + const float3& dir, + const ssef& isect_near, + const ssef& isect_far, + const ssef& tsplat, + const ssef Psplat[3], + const ssef idirsplat[3], + const shuffle_swap_t shufflexyz[3], + const float difl, + const float extmax, + const int node_addr, + const uint visibility, + float dist[2]) +{ + float4 node = kernel_tex_fetch(__bvh_nodes, node_addr); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return bvh_unaligned_node_intersect_robust(kg, + P, + dir, + isect_near, + isect_far, + difl, + node_addr, + visibility, + dist); + } + else { + return bvh_aligned_node_intersect_robust(kg, + P, + dir, + tsplat, + Psplat, + idirsplat, + shufflexyz, + difl, + extmax, + node_addr, + visibility, + dist); + } +} +#endif /* !defined(__KERNEL_SSE2__) */ diff --git a/intern/cycles/kernel/geom/geom_bvh_shadow.h b/intern/cycles/kernel/bvh/bvh_shadow_all.h index 4005489f77d..b27afaa9869 100644 --- a/intern/cycles/kernel/geom/geom_bvh_shadow.h +++ b/intern/cycles/kernel/bvh/bvh_shadow_all.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_shadow.h" +# include "qbvh_shadow_all.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function, where various features can be @@ -41,14 +47,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, * - likely and unlikely for if() statements * - test restrict attribute for pointers */ - + /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ const float tmax = ray->t; @@ -72,9 +78,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -93,130 +102,87 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_ahild1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW); - traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW); -# else - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, # endif - + idir, + isect_t, + node_addr, + PATH_RAY_SHADOW, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & PATH_RAY_SHADOW); - traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & PATH_RAY_SHADOW); -# else - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, # endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + PATH_RAY_SHADOW, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); + node_addr = __float_as_int(cnodes.z); + node_addr_ahild1 = __float_as_int(cnodes.w); - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif - - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_ahild1; + node_addr_ahild1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_ahild1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_ahild1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ - while(primAddr < primAddr2) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + while(prim_addr < prim_addr2) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; @@ -226,22 +192,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #endif #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); - else - hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } + else { + hit = bvh_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } break; } #endif @@ -253,6 +254,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* shadow ray early termination */ if(hit) { + /* Update number of hits now, so we do proper check on max bounces. */ + (*num_hits)++; + /* detect if this surface has a shader with transparent shadows */ /* todo: optimize so primitive visibility flag indicates if @@ -279,27 +283,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } - /* move on to next entry in intersections array */ - isect_array++; - (*num_hits)++; #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - - isect_array->t = isect_t; + /* Move on to next entry in intersections array */ + isect_array++; } - primAddr++; + prim_addr++; } } #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); @@ -317,21 +318,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -369,15 +373,18 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return false; } @@ -410,3 +417,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_subsurface.h b/intern/cycles/kernel/bvh/bvh_subsurface.h index 915e9415c93..18978efcfa3 100644 --- a/intern/cycles/kernel/geom/geom_bvh_subsurface.h +++ b/intern/cycles/kernel/bvh/bvh_subsurface.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_subsurface.h" +# include "qbvh_subsurface.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for subsurface scattering, where @@ -44,12 +50,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object); + int stack_ptr = 0; + int node_addr = kernel_tex_fetch(__object_node, subsurface_object); /* ray parameters in registers */ float3 P = ray->P; @@ -84,6 +90,9 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -100,127 +109,94 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, /* traversal loop */ do { - do - { + do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) - { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect_t, + node_addr, + PATH_RAY_ALL_VISIBILITY, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - const ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + PATH_RAY_ALL_VISIBILITY, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, &isect_precalc, ss_isect, P, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -230,15 +206,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); motion_triangle_intersect_subsurface(kg, ss_isect, P, dir, ray->time, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -251,8 +227,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } } } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); } ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, @@ -286,3 +262,4 @@ ccl_device_inline void BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_traversal.h b/intern/cycles/kernel/bvh/bvh_traversal.h index ae919ef3f86..68a11b65ad7 100644 --- a/intern/cycles/kernel/geom/geom_bvh_traversal.h +++ b/intern/cycles/kernel/bvh/bvh_traversal.h @@ -18,7 +18,15 @@ */ #ifdef __QBVH__ -# include "geom_qbvh_traversal.h" +# include "qbvh_traversal.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +# define NODE_INTERSECT_ROBUST bvh_node_intersect_robust +#else +# define NODE_INTERSECT bvh_aligned_node_intersect +# define NODE_INTERSECT_ROBUST bvh_aligned_node_intersect_robust #endif /* This is a template BVH traversal function, where various features can be @@ -49,14 +57,14 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, * - likely and unlikely for if() statements * - test restrict attribute for pointers */ - + /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ float3 P = ray->P; @@ -79,9 +87,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect->t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -100,174 +111,148 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - # if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { - float hdiff = 1.0f + difl; - float ldiff = 1.0f - difl; - if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { - c0min = max(ldiff * c0min, c0min - extmax); - c0max = min(hdiff * c0max, c0max + extmax); - } - if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { - c1min = max(ldiff * c1min, c1min - extmax); - c1max = min(hdiff * c1max, c1max + extmax); - } + traverse_mask = NODE_INTERSECT_ROBUST(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + difl, + extmax, + node_addr, + visibility, + dist); } + else # endif - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (c0max >= c0min) && (__float_as_uint(cnodes.z) & visibility); - traverseChild1 = (c1max >= c1min) && (__float_as_uint(cnodes.w) & visibility); -# else - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); -# endif - + { + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + node_addr, + visibility, + dist); + } #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - # if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) if(difl != 0.0f) { - float4 *tminmaxview = (float4*)&tminmax; - float &c0min = tminmaxview->x, &c1min = tminmaxview->y; - float &c0max = tminmaxview->z, &c1max = tminmaxview->w; - - float hdiff = 1.0f + difl; - float ldiff = 1.0f - difl; - if(__float_as_int(cnodes.z) & PATH_RAY_CURVE) { - c0min = max(ldiff * c0min, c0min - extmax); - c0max = min(hdiff * c0max, c0max + extmax); - } - if(__float_as_int(cnodes.w) & PATH_RAY_CURVE) { - c1min = max(ldiff * c1min, c1min - extmax); - c1max = min(hdiff * c1max, c1max + extmax); - } + traverse_mask = NODE_INTERSECT_ROBUST(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + difl, + extmax, + node_addr, + visibility, + dist); } + else # endif - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ -# ifdef __VISIBILITY_FLAG__ - /* this visibility test gives a 5% performance hit, how to solve? */ - traverseChild0 = (movemask(lrhit) & 1) && (__float_as_uint(cnodes.z) & visibility); - traverseChild1 = (movemask(lrhit) & 2) && (__float_as_uint(cnodes.w) & visibility); -# else - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); -# endif + { + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); + } #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } BVH_DEBUG_NEXT_STEP(); } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { + for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr)) + { /* shadow ray early termination */ #if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif #else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -278,15 +263,26 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { + for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr)) + { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif # else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -299,20 +295,47 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - for(; primAddr < primAddr2; primAddr++) { + for(; prim_addr < prim_addr2; prim_addr++) { BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - else - hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + else { + hit = bvh_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } if(hit) { /* shadow ray early termination */ # if defined(__KERNEL_SSE2__) if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif # else if(visibility == PATH_RAY_SHADOW_OPAQUE) return true; @@ -327,7 +350,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); @@ -342,24 +365,27 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); BVH_DEBUG_NEXT_INSTANCE(); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* instance pop */ @@ -376,16 +402,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } @@ -433,3 +462,5 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT +#undef NODE_INTERSECT_ROBUST diff --git a/intern/cycles/kernel/geom/geom_bvh_volume.h b/intern/cycles/kernel/bvh/bvh_volume.h index f3edf85d723..03499e94347 100644 --- a/intern/cycles/kernel/geom/geom_bvh_volume.h +++ b/intern/cycles/kernel/bvh/bvh_volume.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -#include "geom_qbvh_volume.h" +# include "qbvh_volume.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for volumes, where @@ -43,12 +49,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ float3 P = ray->P; @@ -69,9 +75,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect->t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -90,143 +99,124 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect->t, + node_addr, + visibility, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); - - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr); + triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr); } break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr); + motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr); } break; } @@ -239,7 +229,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -258,29 +248,32 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* pop */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* instance pop */ @@ -298,16 +291,19 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect->t, -isect->t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect->t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_MOTION) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } @@ -337,3 +333,4 @@ ccl_device_inline bool BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_bvh_volume_all.h b/intern/cycles/kernel/bvh/bvh_volume_all.h index ec837212471..d7f6bf86c71 100644 --- a/intern/cycles/kernel/geom/geom_bvh_volume_all.h +++ b/intern/cycles/kernel/bvh/bvh_volume_all.h @@ -18,7 +18,13 @@ */ #ifdef __QBVH__ -#include "geom_qbvh_volume_all.h" +# include "qbvh_volume_all.h" +#endif + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT bvh_node_intersect +#else +# define NODE_INTERSECT bvh_aligned_node_intersect #endif /* This is a template BVH traversal function for volumes, where @@ -44,12 +50,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, */ /* traversal stack in CUDA thread-local memory */ - int traversalStack[BVH_STACK_SIZE]; - traversalStack[0] = ENTRYPOINT_SENTINEL; + int traversal_stack[BVH_STACK_SIZE]; + traversal_stack[0] = ENTRYPOINT_SENTINEL; /* traversal variables in registers */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* ray parameters in registers */ const float tmax = ray->t; @@ -73,9 +79,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if defined(__KERNEL_SSE2__) const shuffle_swap_t shuf_identity = shuffle_swap_identity(); const shuffle_swap_t shuf_swap = shuffle_swap_swap(); - + const ssef pn = cast(ssei(0, 0, 0x80000000, 0x80000000)); ssef Psplat[3], idirsplat[3]; +# if BVH_FEATURE(BVH_HAIR) + ssef tnear(0.0f), tfar(isect_t); +# endif shuffle_swap_t shufflexyz[3]; Psplat[0] = ssef(P.x); @@ -94,138 +103,110 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, do { do { /* traverse internal nodes */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - bool traverseChild0, traverseChild1; - int nodeAddrChild1; + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + int node_addr_child1, traverse_mask; + float dist[2]; + float4 cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); #if !defined(__KERNEL_SSE2__) - /* Intersect two child bounding boxes, non-SSE version */ - float t = isect_array->t; - - /* fetch node data */ - float4 node0 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0); - float4 node1 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1); - float4 node2 = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2); - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3); - - /* intersect ray against child nodes */ - NO_EXTENDED_PRECISION float c0lox = (node0.x - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0hix = (node0.z - P.x) * idir.x; - NO_EXTENDED_PRECISION float c0loy = (node1.x - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0hiy = (node1.z - P.y) * idir.y; - NO_EXTENDED_PRECISION float c0loz = (node2.x - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0hiz = (node2.z - P.z) * idir.z; - NO_EXTENDED_PRECISION float c0min = max4(min(c0lox, c0hix), min(c0loy, c0hiy), min(c0loz, c0hiz), 0.0f); - NO_EXTENDED_PRECISION float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t); - - NO_EXTENDED_PRECISION float c1lox = (node0.y - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1hix = (node0.w - P.x) * idir.x; - NO_EXTENDED_PRECISION float c1loy = (node1.y - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1hiy = (node1.w - P.y) * idir.y; - NO_EXTENDED_PRECISION float c1loz = (node2.y - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1hiz = (node2.w - P.z) * idir.z; - NO_EXTENDED_PRECISION float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f); - NO_EXTENDED_PRECISION float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t); - - /* decide which nodes to traverse next */ - traverseChild0 = (c0max >= c0min); - traverseChild1 = (c1max >= c1min); - + traverse_mask = NODE_INTERSECT(kg, + P, +# if BVH_FEATURE(BVH_HAIR) + dir, +# endif + idir, + isect_t, + node_addr, + visibility, + dist); #else // __KERNEL_SSE2__ - /* Intersect two child bounding boxes, SSE3 version adapted from Embree */ - - /* fetch node data */ - const ssef *bvh_nodes = (ssef*)kg->__bvh_nodes.data + nodeAddr*BVH_NODE_SIZE; - const float4 cnodes = ((float4*)bvh_nodes)[3]; - - /* intersect ray against child nodes */ - const ssef tminmaxx = (shuffle_swap(bvh_nodes[0], shufflexyz[0]) - Psplat[0]) * idirsplat[0]; - const ssef tminmaxy = (shuffle_swap(bvh_nodes[1], shufflexyz[1]) - Psplat[1]) * idirsplat[1]; - const ssef tminmaxz = (shuffle_swap(bvh_nodes[2], shufflexyz[2]) - Psplat[2]) * idirsplat[2]; - - /* calculate { c0min, c1min, -c0max, -c1max} */ - ssef minmax = max(max(tminmaxx, tminmaxy), max(tminmaxz, tsplat)); - const ssef tminmax = minmax ^ pn; - - const sseb lrhit = tminmax <= shuffle<2, 3, 0, 1>(tminmax); - - /* decide which nodes to traverse next */ - traverseChild0 = (movemask(lrhit) & 1); - traverseChild1 = (movemask(lrhit) & 2); + traverse_mask = NODE_INTERSECT(kg, + P, + dir, +# if BVH_FEATURE(BVH_HAIR) + tnear, + tfar, +# endif + tsplat, + Psplat, + idirsplat, + shufflexyz, + node_addr, + visibility, + dist); #endif // __KERNEL_SSE2__ - nodeAddr = __float_as_int(cnodes.x); - nodeAddrChild1 = __float_as_int(cnodes.y); + node_addr = __float_as_int(cnodes.z); + node_addr_child1 = __float_as_int(cnodes.w); - if(traverseChild0 && traverseChild1) { - /* both children were intersected, push the farther one */ -#if !defined(__KERNEL_SSE2__) - bool closestChild1 = (c1min < c0min); -#else - bool closestChild1 = tminmax[1] < tminmax[0]; -#endif - - if(closestChild1) { - int tmp = nodeAddr; - nodeAddr = nodeAddrChild1; - nodeAddrChild1 = tmp; + if(traverse_mask == 3) { + /* Both children were intersected, push the farther one. */ + bool is_closest_child1 = (dist[1] < dist[0]); + if(is_closest_child1) { + int tmp = node_addr; + node_addr = node_addr_child1; + node_addr_child1 = tmp; } - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = nodeAddrChild1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = node_addr_child1; } else { - /* one child was intersected */ - if(traverseChild1) { - nodeAddr = nodeAddrChild1; + /* One child was intersected. */ + if(traverse_mask == 2) { + node_addr = node_addr_child1; } - else if(!traverseChild0) { - /* neither child was intersected */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + else if(traverse_mask == 0) { + /* Neither child was intersected. */ + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } /* if node is leaf, fetch triangle list */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_NODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - const int primAddr2 = __float_as_int(leaf.y); + const int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); bool hit; /* pop */ - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; /* primitive intersection */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + visibility, + object, + prim_addr); if(hit) { - /* Move on to next entry in intersections array. */ - isect_array++; + /* Update number of hits now, so we do proper check on max bounces. */ num_hits++; #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - isect_array->t = isect_t; - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -239,6 +220,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; } + /* Move on to next entry in intersections array */ + isect_array++; + isect_array->t = isect_t; } } break; @@ -246,24 +230,29 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* intersect ray against primitive */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* only primitives from volume object */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + visibility, + object, + prim_addr); if(hit) { - /* Move on to next entry in intersections array. */ - isect_array++; + /* Update number of hits now, so we do proper check on max bounces. */ num_hits++; # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - isect_array->t = isect_t; - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -277,6 +266,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, # endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; } + /* Move on to next entry in intersections array */ + isect_array++; + isect_array->t = isect_t; } } break; @@ -290,7 +282,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* instance push */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -311,29 +303,32 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif - ++stackPtr; - kernel_assert(stackPtr < BVH_STACK_SIZE); - traversalStack[stackPtr] = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_STACK_SIZE); + traversal_stack[stack_ptr] = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* pop */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -368,16 +363,19 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(BVH)(KernelGlobals *kg, Psplat[2] = ssef(P.z); tsplat = ssef(0.0f, 0.0f, -isect_t, -isect_t); +# if BVH_FEATURE(BVH_HAIR) + tfar = ssef(isect_t); +# endif gen_idirsplat_swap(pn, shuf_identity, shuf_swap, idir, idirsplat, shufflexyz); # endif object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr]; - --stackPtr; + node_addr = traversal_stack[stack_ptr]; + --stack_ptr; } #endif /* FEATURE(BVH_MOTION) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return num_hits; } @@ -410,3 +408,4 @@ ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals *kg, #undef BVH_FUNCTION_NAME #undef BVH_FUNCTION_FEATURES +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/bvh/qbvh_nodes.h b/intern/cycles/kernel/bvh/qbvh_nodes.h new file mode 100644 index 00000000000..4d8695bedec --- /dev/null +++ b/intern/cycles/kernel/bvh/qbvh_nodes.h @@ -0,0 +1,433 @@ +/* + * Copyright 2011-2014, 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. + */ + +struct QBVHStackItem { + int addr; + float dist; +}; + +/* TOOD(sergey): Investigate if using intrinsics helps for both + * stack item swap and float comparison. + */ +ccl_device_inline void qbvh_item_swap(QBVHStackItem *ccl_restrict a, + QBVHStackItem *ccl_restrict b) +{ + QBVHStackItem tmp = *a; + *a = *b; + *b = tmp; +} + +ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1, + QBVHStackItem *ccl_restrict s2, + QBVHStackItem *ccl_restrict s3) +{ + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } + if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } +} + +ccl_device_inline void qbvh_stack_sort(QBVHStackItem *ccl_restrict s1, + QBVHStackItem *ccl_restrict s2, + QBVHStackItem *ccl_restrict s3, + QBVHStackItem *ccl_restrict s4) +{ + if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } + if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); } + if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); } + if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); } + if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } +} + +/* Axis-aligned nodes intersection */ + +ccl_device_inline int qbvh_aligned_node_intersect(KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#else + const sse3f& org, +#endif + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr + 1; +#ifdef __KERNEL_AVX2__ + const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x); + const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y); + const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z); + const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x); + const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y); + const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z); +#else + const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x; + const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y; + const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z; + const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x; + const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y; + const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z; +#endif + +#ifdef __KERNEL_SSE41__ + const ssef tnear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, isect_near)); + const ssef tfar = mini(mini(tfar_x, tfar_y), mini(tfar_z, isect_far)); + const sseb vmask = cast(tnear) > cast(tfar); + int mask = (int)movemask(vmask)^0xf; +#else + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const sseb vmask = tnear <= tfar; + int mask = (int)movemask(vmask); +#endif + *dist = tnear; + return mask; +} + +ccl_device_inline int qbvh_aligned_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#else + const sse3f& P, +#endif + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr + 1; +#ifdef __KERNEL_AVX2__ + const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x); + const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y); + const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z); + const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x); + const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y); + const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z); +#else + const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x; + const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y; + const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z; + const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x; + const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y; + const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z; +#endif + + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + const ssef tnear = max4(tnear_x, tnear_y, tnear_z, isect_near); + const ssef tfar = min4(tfar_x, tfar_y, tfar_z, isect_far); + const sseb vmask = round_down*tnear <= round_up*tfar; + *dist = tnear; + return (int)movemask(vmask); +} + +/* Unaligned nodes intersection */ + +ccl_device_inline int qbvh_unaligned_node_intersect( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#endif + const sse3f& org, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1); + const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2); + const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3); + + const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4); + const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5); + const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6); + + const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7); + const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8); + const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9); + + const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10); + const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11); + const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12); + + const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z, + aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z, + aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z; + + const ssef aligned_P_x = org.x*tfm_x_x + org.y*tfm_x_y + org.z*tfm_x_z + tfm_t_x, + aligned_P_y = org.x*tfm_y_x + org.y*tfm_y_y + org.z*tfm_y_z + tfm_t_y, + aligned_P_z = org.x*tfm_z_x + org.y*tfm_z_y + org.z*tfm_z_z + tfm_t_z; + + const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f); + const ssef nrdir_x = neg_one / aligned_dir_x, + nrdir_y = neg_one / aligned_dir_y, + nrdir_z = neg_one / aligned_dir_z; + + const ssef tlower_x = aligned_P_x * nrdir_x, + tlower_y = aligned_P_y * nrdir_y, + tlower_z = aligned_P_z * nrdir_z; + + const ssef tupper_x = tlower_x - nrdir_x, + tupper_y = tlower_y - nrdir_y, + tupper_z = tlower_z - nrdir_z; + +#ifdef __KERNEL_SSE41__ + const ssef tnear_x = mini(tlower_x, tupper_x); + const ssef tnear_y = mini(tlower_y, tupper_y); + const ssef tnear_z = mini(tlower_z, tupper_z); + const ssef tfar_x = maxi(tlower_x, tupper_x); + const ssef tfar_y = maxi(tlower_y, tupper_y); + const ssef tfar_z = maxi(tlower_z, tupper_z); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = tnear <= tfar; + *dist = tnear; + return movemask(vmask); +#else + const ssef tnear_x = min(tlower_x, tupper_x); + const ssef tnear_y = min(tlower_y, tupper_y); + const ssef tnear_z = min(tlower_z, tupper_z); + const ssef tfar_x = max(tlower_x, tupper_x); + const ssef tfar_y = max(tlower_y, tupper_y); + const ssef tfar_z = max(tlower_z, tupper_z); + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = tnear <= tfar; + *dist = tnear; + return movemask(vmask); +#endif +} + +ccl_device_inline int qbvh_unaligned_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#endif + const sse3f& P, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const ssef tfm_x_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+1); + const ssef tfm_x_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+2); + const ssef tfm_x_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+3); + + const ssef tfm_y_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+4); + const ssef tfm_y_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+5); + const ssef tfm_y_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+6); + + const ssef tfm_z_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+7); + const ssef tfm_z_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+8); + const ssef tfm_z_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+9); + + const ssef tfm_t_x = kernel_tex_fetch_ssef(__bvh_nodes, offset+10); + const ssef tfm_t_y = kernel_tex_fetch_ssef(__bvh_nodes, offset+11); + const ssef tfm_t_z = kernel_tex_fetch_ssef(__bvh_nodes, offset+12); + + const ssef aligned_dir_x = dir.x*tfm_x_x + dir.y*tfm_x_y + dir.z*tfm_x_z, + aligned_dir_y = dir.x*tfm_y_x + dir.y*tfm_y_y + dir.z*tfm_y_z, + aligned_dir_z = dir.x*tfm_z_x + dir.y*tfm_z_y + dir.z*tfm_z_z; + + const ssef aligned_P_x = P.x*tfm_x_x + P.y*tfm_x_y + P.z*tfm_x_z + tfm_t_x, + aligned_P_y = P.x*tfm_y_x + P.y*tfm_y_y + P.z*tfm_y_z + tfm_t_y, + aligned_P_z = P.x*tfm_z_x + P.y*tfm_z_y + P.z*tfm_z_z + tfm_t_z; + + const ssef neg_one(-1.0f, -1.0f, -1.0f, -1.0f); + const ssef nrdir_x = neg_one / aligned_dir_x, + nrdir_y = neg_one / aligned_dir_y, + nrdir_z = neg_one / aligned_dir_z; + + const ssef tlower_x = aligned_P_x * nrdir_x, + tlower_y = aligned_P_y * nrdir_y, + tlower_z = aligned_P_z * nrdir_z; + + const ssef tupper_x = tlower_x - nrdir_x, + tupper_y = tlower_y - nrdir_y, + tupper_z = tlower_z - nrdir_z; + + const float round_down = 1.0f - difl; + const float round_up = 1.0f + difl; + +#ifdef __KERNEL_SSE41__ + const ssef tnear_x = mini(tlower_x, tupper_x); + const ssef tnear_y = mini(tlower_y, tupper_y); + const ssef tnear_z = mini(tlower_z, tupper_z); + const ssef tfar_x = maxi(tlower_x, tupper_x); + const ssef tfar_y = maxi(tlower_y, tupper_y); + const ssef tfar_z = maxi(tlower_z, tupper_z); +#else + const ssef tnear_x = min(tlower_x, tupper_x); + const ssef tnear_y = min(tlower_y, tupper_y); + const ssef tnear_z = min(tlower_z, tupper_z); + const ssef tfar_x = max(tlower_x, tupper_x); + const ssef tfar_y = max(tlower_y, tupper_y); + const ssef tfar_z = max(tlower_z, tupper_z); +#endif + const ssef tnear = max4(isect_near, tnear_x, tnear_y, tnear_z); + const ssef tfar = min4(isect_far, tfar_x, tfar_y, tfar_z); + const sseb vmask = round_down*tnear <= round_up*tfar; + *dist = tnear; + return movemask(vmask); +} + +/* Intersectors wrappers. + * + * They'll check node type and call appropriate intersection code. + */ + +ccl_device_inline int qbvh_node_intersect( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& org_idir, +#endif + const sse3f& org, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const float4 node = kernel_tex_fetch(__bvh_nodes, offset); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return qbvh_unaligned_node_intersect(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + org_idir, +#endif + org, + dir, + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + dist); + } + else { + return qbvh_aligned_node_intersect(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + org_idir, +#else + org, +#endif + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + dist); + } +} + +ccl_device_inline int qbvh_node_intersect_robust( + KernelGlobals *ccl_restrict kg, + const ssef& isect_near, + const ssef& isect_far, +#ifdef __KERNEL_AVX2__ + const sse3f& P_idir, +#endif + const sse3f& P, + const sse3f& dir, + const sse3f& idir, + const int near_x, + const int near_y, + const int near_z, + const int far_x, + const int far_y, + const int far_z, + const int node_addr, + const float difl, + ssef *ccl_restrict dist) +{ + const int offset = node_addr; + const float4 node = kernel_tex_fetch(__bvh_nodes, offset); + if(__float_as_uint(node.x) & PATH_RAY_NODE_UNALIGNED) { + return qbvh_unaligned_node_intersect_robust(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + P_idir, +#endif + P, + dir, + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + dist); + } + else { + return qbvh_aligned_node_intersect_robust(kg, + isect_near, + isect_far, +#ifdef __KERNEL_AVX2__ + P_idir, +#else + P, +#endif + idir, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + dist); + } +} diff --git a/intern/cycles/kernel/geom/geom_qbvh_shadow.h b/intern/cycles/kernel/bvh/qbvh_shadow_all.h index edb5b5c78c3..eb98eaf7455 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_shadow.h +++ b/intern/cycles/kernel/bvh/qbvh_shadow_all.h @@ -27,6 +27,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, @@ -39,12 +45,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ const float tmax = ray->t; @@ -72,13 +78,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(tmax); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -96,29 +106,53 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + +#ifdef __VISIBILITY_FLAG__ + if((__float_as_uint(inodes.x) & PATH_RAY_SHADOW) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +# endif +# if BVH_FEATURE(BVH_HAIR) + dir4, +# endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -127,24 +161,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -152,86 +186,86 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); #ifdef __VISIBILITY_FLAG__ if((__float_as_uint(leaf.z) & PATH_RAY_SHADOW) == 0) { /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } #endif - int primAddr = __float_as_int(leaf.x); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ - while(primAddr < primAddr2) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + while(prim_addr < prim_addr2) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); bool hit; @@ -241,22 +275,57 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, switch(p_type) { case PRIMITIVE_TRIANGLE: { - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, PATH_RAY_SHADOW, object, primAddr); + hit = triangle_intersect(kg, + &isect_precalc, + isect_array, + P, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, PATH_RAY_SHADOW, object, primAddr); + hit = motion_triangle_intersect(kg, + isect_array, + P, + dir, + ray->time, + PATH_RAY_SHADOW, + object, + prim_addr); break; } #endif #if BVH_FEATURE(BVH_HAIR) case PRIMITIVE_CURVE: case PRIMITIVE_MOTION_CURVE: { - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); - else - hit = bvh_curve_intersect(kg, isect_array, P, dir, PATH_RAY_SHADOW, object, primAddr, ray->time, type, NULL, 0, 0); + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } + else { + hit = bvh_curve_intersect(kg, + isect_array, + P, + dir, + PATH_RAY_SHADOW, + object, + prim_addr, + ray->time, + type, + NULL, + 0, 0); + } break; } #endif @@ -268,6 +337,9 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Shadow ray early termination. */ if(hit) { + /* Update number of hits now, so we do proper check on max bounces. */ + (*num_hits)++; + /* detect if this surface has a shader with transparent shadows */ /* todo: optimize so primitive visibility flag indicates if @@ -294,27 +366,25 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, return true; } /* if maximum number of hits reached, block all light */ - else if(*num_hits == max_hits) { + else if(*num_hits >= max_hits) { return true; } - /* move on to next entry in intersections array */ - isect_array++; - (*num_hits)++; #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - + /* Move on to next entry in intersections array */ + isect_array++; isect_array->t = isect_t; } - primAddr++; + prim_addr++; } } #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); # if BVH_FEATURE(BVH_MOTION) bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect_t, &ob_itfm); @@ -329,28 +399,33 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); if(num_hits_in_instance) { @@ -383,21 +458,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(tmax); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return false; } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h b/intern/cycles/kernel/bvh/qbvh_subsurface.h index 84512a8783c..03794e3a882 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_subsurface.h +++ b/intern/cycles/kernel/bvh/qbvh_subsurface.h @@ -25,6 +25,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, SubsurfaceIntersection *ss_isect, @@ -41,12 +47,12 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_tex_fetch(__object_node, subsurface_object); + int stack_ptr = 0; + int node_addr = kernel_tex_fetch(__object_node, subsurface_object); /* Ray parameters in registers. */ float3 P = ray->P; @@ -82,13 +88,17 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(isect_t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -106,29 +116,43 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); + if(child_mask != 0) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -137,24 +161,24 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -162,82 +186,82 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(type & PRIMITIVE_ALL) { case PRIMITIVE_TRIANGLE: { /* Intersect ray against primitive, */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); triangle_intersect_subsurface(kg, &isect_precalc, ss_isect, P, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -247,15 +271,15 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { /* Intersect ray against primitive. */ - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); motion_triangle_intersect_subsurface(kg, ss_isect, P, dir, ray->time, object, - primAddr, + prim_addr, isect_t, lcg_state, max_hits); @@ -267,6 +291,8 @@ ccl_device void BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, break; } } - } while(nodeAddr != ENTRYPOINT_SENTINEL); - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/bvh/qbvh_traversal.h b/intern/cycles/kernel/bvh/qbvh_traversal.h new file mode 100644 index 00000000000..f82ff661495 --- /dev/null +++ b/intern/cycles/kernel/bvh/qbvh_traversal.h @@ -0,0 +1,505 @@ +/* + * Adapted from code Copyright 2009-2010 NVIDIA Corporation, + * and code copyright 2009-2012 Intel Corporation + * + * Modifications Copyright 2011-2014, 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. + */ + +/* This is a template BVH traversal function, where various features can be + * enabled/disabled. This way we can compile optimized versions for each case + * without new features slowing things down. + * + * BVH_INSTANCING: object instancing + * BVH_HAIR: hair curve rendering + * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width + * BVH_MOTION: motion blur rendering + * + */ + +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +# define NODE_INTERSECT_ROBUST qbvh_node_intersect_robust +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +# define NODE_INTERSECT_ROBUST qbvh_aligned_node_intersect_robust +#endif + +ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, + const Ray *ray, + Intersection *isect, + const uint visibility +#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) + ,uint *lcg_state, + float difl, + float extmax +#endif + ) +{ + /* TODO(sergey): + * - Test if pushing distance on the stack helps (for non shadow rays). + * - Separate version for shadow rays. + * - Likely and unlikely for if() statements. + * - Test restrict attribute for pointers. + */ + + /* Traversal stack in CUDA thread-local memory. */ + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; + traversal_stack[0].dist = -FLT_MAX; + + /* Traversal variables in registers. */ + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; + float node_dist = -FLT_MAX; + + /* Ray parameters in registers. */ + float3 P = ray->P; + float3 dir = bvh_clamp_direction(ray->D); + float3 idir = bvh_inverse_direction(dir); + int object = OBJECT_NONE; + +#if BVH_FEATURE(BVH_MOTION) + Transform ob_itfm; +#endif + +#ifndef __KERNEL_SSE41__ + if(!isfinite(P.x)) { + return false; + } +#endif + + isect->t = ray->t; + isect->u = 0.0f; + isect->v = 0.0f; + isect->prim = PRIM_NONE; + isect->object = OBJECT_NONE; + + BVH_DEBUG_INIT(); + + ssef tnear(0.0f), tfar(ray->t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif + sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); + +#ifdef __KERNEL_AVX2__ + float3 P_idir = P*idir; + sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +#endif + + /* Offsets to select the side that becomes the lower or upper bound. */ + int near_x, near_y, near_z; + int far_x, far_y, far_z; + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + + IsectPrecalc isect_precalc; + triangle_intersect_precalc(dir, &isect_precalc); + + /* Traversal loop. */ + do { + do { + /* Traverse internal nodes. */ + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + + if(UNLIKELY(node_dist > isect->t) +#ifdef __VISIBILITY_FLAG__ + || (__float_as_uint(inodes.x) & visibility) == 0) +#endif + { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + int child_mask; + ssef dist; + + BVH_DEBUG_NEXT_STEP(); + +#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) + if(difl != 0.0f) { + /* NOTE: We extend all the child BB instead of fetching + * and checking visibility flags for each of the, + * + * Need to test if doing opposite would be any faster. + */ + child_mask = NODE_INTERSECT_ROBUST(kg, + tnear, + tfar, +# ifdef __KERNEL_AVX2__ + P_idir4, +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +# endif +# if BVH_FEATURE(BVH_HAIR) + dir4, +# endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + difl, + &dist); + } + else +#endif /* BVH_HAIR_MINIMUM_WIDTH */ + { + child_mask = NODE_INTERSECT(kg, + tnear, + tfar, +#ifdef __KERNEL_AVX2__ + P_idir4, +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + } + + if(child_mask != 0) { + float4 cnodes; + /* TODO(sergey): Investigate whether moving cnodes upwards + * gives a speedup (will be different cache pattern but will + * avoid extra check here), + */ +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } + + /* One child is hit, continue with that child. */ + int r = __bscf(child_mask); + float d0 = ((float*)&dist)[r]; + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); + node_dist = d0; + continue; + } + + /* Two children are hit, push far child, and continue with + * closer child. + */ + int c0 = __float_as_int(cnodes[r]); + r = __bscf(child_mask); + int c1 = __float_as_int(cnodes[r]); + float d1 = ((float*)&dist)[r]; + if(child_mask == 0) { + if(d1 < d0) { + node_addr = c1; + node_dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; + continue; + } + else { + node_addr = c0; + node_dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + continue; + } + } + + /* Here starts the slow path for 3 or 4 hit children. We push + * all nodes onto the stack to sort them there. + */ + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; + + /* Three children are hit, push all onto stack and sort 3 + * stack items, continue with closest child. + */ + r = __bscf(child_mask); + int c2 = __float_as_int(cnodes[r]); + float d2 = ((float*)&dist)[r]; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + /* Four children are hit, push all onto stack and sort 4 + * stack items, continue with closest child. + */ + r = __bscf(child_mask); + int c3 = __float_as_int(cnodes[r]); + float d3 = ((float*)&dist)[r]; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); + } + + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + } + + /* If node is leaf, fetch triangle list. */ + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + +#ifdef __VISIBILITY_FLAG__ + if(UNLIKELY((node_dist > isect->t) || + ((__float_as_uint(leaf.z) & visibility) == 0))) +#else + if(UNLIKELY((node_dist > isect->t))) +#endif + { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + continue; + } + + int prim_addr = __float_as_int(leaf.x); + +#if BVH_FEATURE(BVH_INSTANCING) + if(prim_addr >= 0) { +#endif + int prim_addr2 = __float_as_int(leaf.y); + const uint type = __float_as_int(leaf.w); + + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + + /* Primitive intersection. */ + switch(type & PRIMITIVE_ALL) { + case PRIMITIVE_TRIANGLE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(triangle_intersect(kg, + &isect_precalc, + isect, + P, + visibility, + object, + prim_addr)) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#if BVH_FEATURE(BVH_MOTION) + case PRIMITIVE_MOTION_TRIANGLE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + if(motion_triangle_intersect(kg, + isect, + P, + dir, + ray->time, + visibility, + object, + prim_addr)) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#endif /* BVH_FEATURE(BVH_MOTION) */ +#if BVH_FEATURE(BVH_HAIR) + case PRIMITIVE_CURVE: + case PRIMITIVE_MOTION_CURVE: { + for(; prim_addr < prim_addr2; prim_addr++) { + BVH_DEBUG_NEXT_STEP(); + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); + bool hit; + if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) { + hit = bvh_cardinal_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + else { + hit = bvh_curve_intersect(kg, + isect, + P, + dir, + visibility, + object, + prim_addr, + ray->time, + type, + lcg_state, + difl, + extmax); + } + if(hit) { + tfar = ssef(isect->t); + /* Shadow ray early termination. */ + if(visibility == PATH_RAY_SHADOW_OPAQUE) { + return true; + } + } + } + break; + } +#endif /* BVH_FEATURE(BVH_HAIR) */ + } + } +#if BVH_FEATURE(BVH_INSTANCING) + else { + /* Instance push. */ + object = kernel_tex_fetch(__prim_object, -prim_addr-1); + +# if BVH_FEATURE(BVH_MOTION) + qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist, &ob_itfm); +# else + qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &node_dist); +# endif + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif + idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# ifdef __KERNEL_AVX2__ + P_idir = P*idir; + P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + + triangle_intersect_precalc(dir, &isect_precalc); + + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; + traversal_stack[stack_ptr].dist = -FLT_MAX; + + node_addr = kernel_tex_fetch(__object_node, object); + + BVH_DEBUG_NEXT_INSTANCE(); + } + } +#endif /* FEATURE(BVH_INSTANCING) */ + } while(node_addr != ENTRYPOINT_SENTINEL); + +#if BVH_FEATURE(BVH_INSTANCING) + if(stack_ptr >= 0) { + kernel_assert(object != OBJECT_NONE); + + /* Instance pop. */ +# if BVH_FEATURE(BVH_MOTION) + bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); +# else + bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); +# endif + + if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } + if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } + if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } + tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif + idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# ifdef __KERNEL_AVX2__ + P_idir = P*idir; + P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); +# endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + + triangle_intersect_precalc(dir, &isect_precalc); + + object = OBJECT_NONE; + node_addr = traversal_stack[stack_ptr].addr; + node_dist = traversal_stack[stack_ptr].dist; + --stack_ptr; + } +#endif /* FEATURE(BVH_INSTANCING) */ + } while(node_addr != ENTRYPOINT_SENTINEL); + + return (isect->prim != PRIM_NONE); +} + +#undef NODE_INTERSECT +#undef NODE_INTERSECT_ROBUST diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume.h b/intern/cycles/kernel/bvh/qbvh_volume.h index ab2e530dd20..b4f334eb842 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_volume.h +++ b/intern/cycles/kernel/bvh/qbvh_volume.h @@ -26,6 +26,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect, @@ -38,12 +44,12 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ float3 P = ray->P; @@ -68,13 +74,17 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, isect->object = OBJECT_NONE; ssef tnear(0.0f), tfar(ray->t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -92,29 +102,52 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { +#ifdef __VISIBILITY_FLAG__ + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if((__float_as_uint(inodes.x) & visibility) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -123,24 +156,24 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -148,102 +181,102 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(p_type) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr); + triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, prim_addr); } break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr); + motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, prim_addr); } break; } @@ -253,7 +286,7 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -268,34 +301,39 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* Pop. */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* Instance pop. */ @@ -309,21 +347,28 @@ ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect->t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return (isect->prim != PRIM_NONE); } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h b/intern/cycles/kernel/bvh/qbvh_volume_all.h index 5546471b0e3..90cad9d91c0 100644 --- a/intern/cycles/kernel/geom/geom_qbvh_volume_all.h +++ b/intern/cycles/kernel/bvh/qbvh_volume_all.h @@ -26,6 +26,12 @@ * */ +#if BVH_FEATURE(BVH_HAIR) +# define NODE_INTERSECT qbvh_node_intersect +#else +# define NODE_INTERSECT qbvh_aligned_node_intersect +#endif + ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, const Ray *ray, Intersection *isect_array, @@ -39,12 +45,12 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; + QBVHStackItem traversal_stack[BVH_QSTACK_SIZE]; + traversal_stack[0].addr = ENTRYPOINT_SENTINEL; /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; + int stack_ptr = 0; + int node_addr = kernel_data.bvh.root; /* Ray parameters in registers. */ const float tmax = ray->t; @@ -72,13 +78,17 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif ssef tnear(0.0f), tfar(isect_t); +#if BVH_FEATURE(BVH_HAIR) + sse3f dir4(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +#endif sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); #ifdef __KERNEL_AVX2__ float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); + sse3f P_idir4(P_idir.x, P_idir.y, P_idir.z); +#endif +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + sse3f org4(ssef(P.x), ssef(P.y), ssef(P.z)); #endif /* Offsets to select the side that becomes the lower or upper bound. */ @@ -96,29 +106,52 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, do { do { /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { + while(node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) { +#ifdef __VISIBILITY_FLAG__ + float4 inodes = kernel_tex_fetch(__bvh_nodes, node_addr+0); + if((__float_as_uint(inodes.x) & visibility) == 0) { + /* Pop. */ + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; + continue; + } +#endif + ssef dist; - int traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, + int child_mask = NODE_INTERSECT(kg, + tnear, + tfar, #ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, + P_idir4, #endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); +#if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4, +#endif +#if BVH_FEATURE(BVH_HAIR) + dir4, +#endif + idir4, + near_x, near_y, near_z, + far_x, far_y, far_z, + node_addr, + &dist); + + if(child_mask != 0) { + float4 cnodes; +#if BVH_FEATURE(BVH_HAIR) + if(__float_as_uint(inodes.x) & PATH_RAY_NODE_UNALIGNED) { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+13); + } + else +#endif + { + cnodes = kernel_tex_fetch(__bvh_nodes, node_addr+7); + } /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); + int r = __bscf(child_mask); + if(child_mask == 0) { + node_addr = __float_as_int(cnodes[r]); continue; } @@ -127,24 +160,24 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, */ int c0 = __float_as_int(cnodes[r]); float d0 = ((float*)&dist)[r]; - r = __bscf(traverseChild); + r = __bscf(child_mask); int c1 = __float_as_int(cnodes[r]); float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { + if(child_mask == 0) { if(d1 < d0) { - nodeAddr = c1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + node_addr = c1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; continue; } else { - nodeAddr = c0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; + node_addr = c0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; continue; } } @@ -152,97 +185,95 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, /* Here starts the slow path for 3 or 4 hit children. We push * all nodes onto the stack to sort them there. */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c1; + traversal_stack[stack_ptr].dist = d1; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c0; + traversal_stack[stack_ptr].dist = d0; /* Three children are hit, push all onto stack and sort 3 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c2 = __float_as_int(cnodes[r]); float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + if(child_mask == 0) { + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2]); + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; continue; } /* Four children are hit, push all onto stack and sort 4 * stack items, continue with closest child. */ - r = __bscf(traverseChild); + r = __bscf(child_mask); int c3 = __float_as_int(cnodes[r]); float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c3; + traversal_stack[stack_ptr].dist = d3; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = c2; + traversal_stack[stack_ptr].dist = d2; + qbvh_stack_sort(&traversal_stack[stack_ptr], + &traversal_stack[stack_ptr - 1], + &traversal_stack[stack_ptr - 2], + &traversal_stack[stack_ptr - 3]); } - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - int primAddr = __float_as_int(leaf.x); + if(node_addr < 0) { + float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-node_addr-1)); + int prim_addr = __float_as_int(leaf.x); #if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { + if(prim_addr >= 0) { #endif - int primAddr2 = __float_as_int(leaf.y); + int prim_addr2 = __float_as_int(leaf.y); const uint type = __float_as_int(leaf.w); const uint p_type = type & PRIMITIVE_ALL; bool hit; /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; /* Primitive intersection. */ switch(p_type) { case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, primAddr); + hit = triangle_intersect(kg, &isect_precalc, isect_array, P, visibility, object, prim_addr); if(hit) { - /* Move on to next entry in intersections array. */ - isect_array++; + /* Update number of hits now, so we do proper check on max bounces. */ num_hits++; #if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; #endif - isect_array->t = isect_t; - if(num_hits == max_hits) { + if(num_hits >= max_hits) { #if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -256,31 +287,32 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; } + /* Move on to next entry in intersections array */ + isect_array++; + isect_array->t = isect_t; } } break; } #if BVH_FEATURE(BVH_MOTION) case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); + for(; prim_addr < prim_addr2; prim_addr++) { + kernel_assert(kernel_tex_fetch(__prim_type, prim_addr) == type); /* Only primitives from volume object. */ - uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, primAddr): object; + uint tri_object = (object == OBJECT_NONE)? kernel_tex_fetch(__prim_object, prim_addr): object; int object_flag = kernel_tex_fetch(__object_flag, tri_object); if((object_flag & SD_OBJECT_HAS_VOLUME) == 0) { continue; } /* Intersect ray against primitive. */ - hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, primAddr); + hit = motion_triangle_intersect(kg, isect_array, P, dir, ray->time, visibility, object, prim_addr); if(hit) { - /* Move on to next entry in intersections array. */ - isect_array++; + /* Update number of hits now, so we do proper check on max bounces. */ num_hits++; # if BVH_FEATURE(BVH_INSTANCING) num_hits_in_instance++; # endif - isect_array->t = isect_t; - if(num_hits == max_hits) { + if(num_hits >= max_hits) { # if BVH_FEATURE(BVH_INSTANCING) # if BVH_FEATURE(BVH_MOTION) float t_fac = 1.0f / len(transform_direction(&ob_itfm, dir)); @@ -294,6 +326,9 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, # endif /* BVH_FEATURE(BVH_INSTANCING) */ return num_hits; } + /* Move on to next entry in intersections array */ + isect_array++; + isect_array->t = isect_t; } } break; @@ -304,7 +339,7 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, #if BVH_FEATURE(BVH_INSTANCING) else { /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); + object = kernel_tex_fetch(__prim_object, -prim_addr-1); int object_flag = kernel_tex_fetch(__object_flag, object); if(object_flag & SD_OBJECT_HAS_VOLUME) { @@ -320,35 +355,40 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); num_hits_in_instance = 0; isect_array->t = isect_t; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; + ++stack_ptr; + kernel_assert(stack_ptr < BVH_QSTACK_SIZE); + traversal_stack[stack_ptr].addr = ENTRYPOINT_SENTINEL; - nodeAddr = kernel_tex_fetch(__object_node, object); + node_addr = kernel_tex_fetch(__object_node, object); } else { /* Pop. */ object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } } } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); #if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { + if(stack_ptr >= 0) { kernel_assert(object != OBJECT_NONE); /* Instance pop. */ @@ -379,23 +419,30 @@ ccl_device uint BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } tfar = ssef(isect_t); +# if BVH_FEATURE(BVH_HAIR) + dir4 = sse3f(ssef(dir.x), ssef(dir.y), ssef(dir.z)); +# endif idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); # ifdef __KERNEL_AVX2__ P_idir = P*idir; P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); # endif +# if BVH_FEATURE(BVH_HAIR) || !defined(__KERNEL_AVX2__) + org4 = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); +# endif + triangle_intersect_precalc(dir, &isect_precalc); isect_t = tmax; isect_array->t = isect_t; object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - --stackPtr; + node_addr = traversal_stack[stack_ptr].addr; + --stack_ptr; } #endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); + } while(node_addr != ENTRYPOINT_SENTINEL); return num_hits; } + +#undef NODE_INTERSECT diff --git a/intern/cycles/kernel/closure/bsdf.h b/intern/cycles/kernel/closure/bsdf.h index f0add804c32..f318a61f3a3 100644 --- a/intern/cycles/kernel/closure/bsdf.h +++ b/intern/cycles/kernel/closure/bsdf.h @@ -20,6 +20,7 @@ #include "../closure/bsdf_phong_ramp.h" #include "../closure/bsdf_diffuse_ramp.h" #include "../closure/bsdf_microfacet.h" +#include "../closure/bsdf_microfacet_multi.h" #include "../closure/bsdf_reflection.h" #include "../closure/bsdf_refraction.h" #include "../closure/bsdf_transparent.h" @@ -35,7 +36,7 @@ CCL_NAMESPACE_BEGIN -ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) +ccl_device int bsdf_sample(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf) { int label; @@ -85,6 +86,14 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader label = bsdf_microfacet_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + label = bsdf_microfacet_multi_ggx_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + label = bsdf_microfacet_multi_ggx_glass_sample(kg, sc, ccl_fetch(sd, Ng), ccl_fetch(sd, I), ccl_fetch(sd, dI).dx, ccl_fetch(sd, dI).dy, randu, randv, + eval, omega_in, &domega_in->dx, &domega_in->dy, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -130,7 +139,7 @@ ccl_device int bsdf_sample(KernelGlobals *kg, const ShaderData *sd, const Shader return label; } -ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) +ccl_device float3 bsdf_eval(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, const float3 omega_in, float *pdf) { float3 eval; @@ -172,6 +181,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_reflect(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -234,6 +249,12 @@ ccl_device float3 bsdf_eval(KernelGlobals *kg, const ShaderData *sd, const Shade case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: eval = bsdf_microfacet_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf); break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + eval = bsdf_microfacet_multi_ggx_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + eval = bsdf_microfacet_multi_ggx_glass_eval_transmit(sc, ccl_fetch(sd, I), omega_in, pdf, &ccl_fetch(sd, lcg_state)); + break; case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: @@ -286,6 +307,10 @@ ccl_device void bsdf_blur(KernelGlobals *kg, ShaderClosure *sc, float roughness) #ifdef __SVM__ switch(sc->type) { + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: + bsdf_microfacet_multi_ggx_blur(sc, roughness); + break; case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID: diff --git a/intern/cycles/kernel/closure/bsdf_microfacet.h b/intern/cycles/kernel/closure/bsdf_microfacet.h index 2a0e8f62e7c..7bf7c2806d4 100644 --- a/intern/cycles/kernel/closure/bsdf_microfacet.h +++ b/intern/cycles/kernel/closure/bsdf_microfacet.h @@ -276,7 +276,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderClosure *sc, cons bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -367,7 +367,7 @@ ccl_device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderClosure *sc, con bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID; float3 N = sc->N; - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -450,7 +450,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -539,7 +539,7 @@ ccl_device int bsdf_microfacet_ggx_sample(KernelGlobals *kg, const ShaderClosure *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -615,6 +615,36 @@ ccl_device void bsdf_microfacet_beckmann_blur(ShaderClosure *sc, float roughness sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ } +ccl_device_inline float bsdf_beckmann_G1(float alpha, float cos_n) +{ + cos_n *= cos_n; + float invA = alpha * safe_sqrtf((1.0f - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); +} + +ccl_device_inline float bsdf_beckmann_aniso_G1(float alpha_x, float alpha_y, float cos_n, float cos_phi, float sin_phi) +{ + cos_n *= cos_n; + sin_phi *= sin_phi; + cos_phi *= cos_phi; + alpha_x *= alpha_x; + alpha_y *= alpha_y; + + float alphaO2 = (cos_phi*alpha_x + sin_phi*alpha_y) / (cos_phi + sin_phi); + float invA = safe_sqrtf(alphaO2 * (1 - cos_n) / cos_n); + if(invA < 0.625f) { + return 1.0f; + } + + float a = 1.0f / invA; + return ((2.181f*a + 3.535f)*a) / ((2.577f*a + 2.276f)*a + 1.0f); +} + ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf) { float alpha_x = sc->data0; @@ -622,7 +652,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; - if(m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -646,10 +676,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_G1(alpha_x, cosNO); + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic */ @@ -668,24 +696,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderClosure *sc, D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) and G1(o,m) */ - float tanThetaO2 = (1 - cosNO * cosNO) / (cosNO * cosNO); - float cosPhiO = dot(I, X); - float sinPhiO = dot(I, Y); - - float alphaO2 = (cosPhiO*cosPhiO)*(alpha_x*alpha_x) + (sinPhiO*sinPhiO)*(alpha_y*alpha_y); - alphaO2 /= cosPhiO*cosPhiO + sinPhiO*sinPhiO; - - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(omega_in, X); - float sinPhiI = dot(omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ao = 1 / (safe_sqrtf(alphaO2 * tanThetaO2)); - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1o = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNO, dot(I, X), dot(I, Y)); + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, cosNI, dot(omega_in, X), dot(omega_in, Y)); } float G = G1o * G1i; @@ -716,7 +728,7 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc bool m_refractive = sc->type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID; float3 N = sc->N; - if(!m_refractive || fmaxf(alpha_x, alpha_y) <= 1e-4f) + if(!m_refractive || alpha_x*alpha_y <= 1e-7f) return make_float3(0.0f, 0.0f, 0.0f); float cosNO = dot(N, I); @@ -740,10 +752,8 @@ ccl_device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderClosure *sc float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4); /* eq. 26, 27: now calculate G1(i,m) and G1(o,m) */ - float ao = 1 / (alpha_x * safe_sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO))); - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f; - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1o = bsdf_beckmann_G1(alpha_x, cosNO); + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* probability */ @@ -798,7 +808,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *omega_in = 2 * cosMO * m - I; if(dot(Ng, *omega_in) > 0) { - if(fmaxf(alpha_x, alpha_y) <= 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -820,8 +830,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_G1(alpha_x, cosNI); } else { /* anisotropic distribution */ @@ -836,16 +845,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl D = expf(-slope_x*slope_x - slope_y*slope_y) / (M_PI_F * alpha2 * cosThetaM4); /* G1(i,m) */ - float cosNI = dot(N, *omega_in); - float tanThetaI2 = (1 - cosNI * cosNI) / (cosNI * cosNI); - float cosPhiI = dot(*omega_in, X); - float sinPhiI = dot(*omega_in, Y); - - float alphaI2 = (cosPhiI*cosPhiI)*(alpha_x*alpha_x) + (sinPhiI*sinPhiI)*(alpha_y*alpha_y); - alphaI2 /= cosPhiI*cosPhiI + sinPhiI*sinPhiI; - - float ai = 1 / (safe_sqrtf(alphaI2 * tanThetaI2)); - G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + G1i = bsdf_beckmann_aniso_G1(alpha_x, alpha_y, dot(*omega_in, N), dot(*omega_in, X), dot(*omega_in, Y)); } float G = G1o * G1i; @@ -889,7 +889,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl *domega_in_dy = dTdy; #endif - if(fmaxf(alpha_x, alpha_y) <= 1e-4f || fabsf(m_eta - 1.0f) < 1e-4f) { + if(alpha_x*alpha_y <= 1e-7f || fabsf(m_eta - 1.0f) < 1e-4f) { /* some high number for MIS */ *pdf = 1e6f; *eval = make_float3(1e6f, 1e6f, 1e6f); @@ -906,8 +906,7 @@ ccl_device int bsdf_microfacet_beckmann_sample(KernelGlobals *kg, const ShaderCl float cosNI = dot(N, *omega_in); /* eq. 26, 27: now calculate G1(i,m) */ - float ai = 1 / (alpha_x * safe_sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI))); - float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f; + float G1i = bsdf_beckmann_G1(alpha_x, cosNI); float G = G1o * G1i; /* eq. 21 */ diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h new file mode 100644 index 00000000000..51b12fe4e45 --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi.h @@ -0,0 +1,472 @@ +/* + * Copyright 2011-2016 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. + */ + +CCL_NAMESPACE_BEGIN + +/* Most of the code is based on the supplemental implementations from https://eheitzresearch.wordpress.com/240-2/. */ + +/* === GGX Microfacet distribution functions === */ + +/* Isotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx(float3 wm, float alpha) +{ + wm.z *= wm.z; + alpha *= alpha; + float tmp = (1.0f - wm.z) + alpha * wm.z; + return alpha / max(M_PI_F * tmp*tmp, 1e-7f); +} + +/* Anisotropic GGX microfacet distribution */ +ccl_device_inline float D_ggx_aniso(const float3 wm, const float2 alpha) +{ + float slope_x = -wm.x/alpha.x; + float slope_y = -wm.y/alpha.y; + float tmp = wm.z*wm.z + slope_x*slope_x + slope_y*slope_y; + + return 1.0f / max(M_PI_F * tmp*tmp * alpha.x*alpha.y, 1e-7f); +} + +/* Sample slope distribution (based on page 14 of the supplemental implementation). */ +ccl_device_inline float2 mf_sampleP22_11(const float cosI, const float2 randU) +{ + if(cosI > 0.9999f) { + const float r = sqrtf(randU.x / (1.0f - randU.x)); + const float phi = M_2PI_F * randU.y; + return make_float2(r*cosf(phi), r*sinf(phi)); + } + + const float sinI = sqrtf(1.0f - cosI*cosI); + const float tanI = sinI/cosI; + const float projA = 0.5f * (cosI + 1.0f); + if(projA < 0.0001f) + return make_float2(0.0f, 0.0f); + const float A = 2.0f*randU.x*projA / cosI - 1.0f; + float tmp = A*A-1.0f; + if(fabsf(tmp) < 1e-7f) + return make_float2(0.0f, 0.0f); + tmp = 1.0f / tmp; + const float D = safe_sqrtf(tanI*tanI*tmp*tmp - (A*A-tanI*tanI)*tmp); + + const float slopeX2 = tanI*tmp + D; + const float slopeX = (A < 0.0f || slopeX2 > 1.0f/tanI)? (tanI*tmp - D) : slopeX2; + + float U2; + if(randU.y >= 0.5f) + U2 = 2.0f*(randU.y - 0.5f); + else + U2 = 2.0f*(0.5f - randU.y); + const float z = (U2*(U2*(U2*0.27385f-0.73369f)+0.46341f)) / (U2*(U2*(U2*0.093073f+0.309420f)-1.0f)+0.597999f); + const float slopeY = z * sqrtf(1.0f + slopeX*slopeX); + + if(randU.y >= 0.5f) + return make_float2(slopeX, slopeY); + else + return make_float2(slopeX, -slopeY); +} + +/* Visible normal sampling for the GGX distribution (based on page 7 of the supplemental implementation). */ +ccl_device_inline float3 mf_sample_vndf(const float3 wi, const float2 alpha, const float2 randU) +{ + const float3 wi_11 = normalize(make_float3(alpha.x*wi.x, alpha.y*wi.y, wi.z)); + const float2 slope_11 = mf_sampleP22_11(wi_11.z, randU); + + const float2 cossin_phi = normalize(make_float2(wi_11.x, wi_11.y)); + const float slope_x = alpha.x*(cossin_phi.x * slope_11.x - cossin_phi.y * slope_11.y); + const float slope_y = alpha.y*(cossin_phi.y * slope_11.x + cossin_phi.x * slope_11.y); + + kernel_assert(isfinite(slope_x)); + return normalize(make_float3(-slope_x, -slope_y, 1.0f)); +} + +/* === Phase functions: Glossy, Diffuse and Glass === */ + +/* Phase function for reflective materials, either without a fresnel term (for compatibility) or with the conductive fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glossy(const float3 wi, float3 *n, float3 *k, float3 *weight, const float3 wm) +{ + if(n && k) + *weight *= fresnel_conductor(dot(wi, wm), *n, *k); + + return -wi + 2.0f * wm * dot(wi, wm); +} + +ccl_device_inline float3 mf_eval_phase_glossy(const float3 w, const float lambda, const float3 wo, const float2 alpha, float3 *n, float3 *k) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + + const float dotW_WH = dot(-w, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float phase = max(0.0f, dotW_WH) * 0.25f / (pArea * dotW_WH); + if(alpha.x == alpha.y) + phase *= D_ggx(wh, alpha.x); + else + phase *= D_ggx_aniso(wh, alpha); + + if(n && k) { + /* Apply conductive fresnel term. */ + return phase * fresnel_conductor(dotW_WH, *n, *k); + } + + return make_float3(phase, phase, phase); +} + +/* Phase function for rough lambertian diffuse surfaces. */ +ccl_device_inline float3 mf_sample_phase_diffuse(const float3 wm, const float randu, const float randv) +{ + float3 tm, bm; + make_orthonormals(wm, &tm, &bm); + + float2 disk = concentric_sample_disk(randu, randv); + return disk.x*tm + disk.y*bm + safe_sqrtf(1.0f - disk.x*disk.x - disk.y*disk.y)*wm; +} + +ccl_device_inline float3 mf_eval_phase_diffuse(const float3 w, const float3 wm) +{ + const float v = max(0.0f, dot(w, wm)) * M_1_PI_F; + return make_float3(v, v, v); +} + +/* Phase function for dielectric transmissive materials, including both reflection and refraction according to the dielectric fresnel term. */ +ccl_device_inline float3 mf_sample_phase_glass(const float3 wi, const float eta, const float3 wm, const float randV, bool *outside) +{ + float cosI = dot(wi, wm); + float f = fresnel_dielectric_cos(cosI, eta); + if(randV < f) { + *outside = true; + return -wi + 2.0f * wm * cosI; + } + *outside = false; + float inv_eta = 1.0f/eta; + float cosT = -safe_sqrtf(1.0f - (1.0f - cosI*cosI) * inv_eta*inv_eta); + return normalize(wm*(cosI*inv_eta + cosT) - wi*inv_eta); +} + +ccl_device_inline float3 mf_eval_phase_glass(const float3 w, const float lambda, const float3 wo, const bool wo_outside, const float2 alpha, const float eta) +{ + if(w.z > 0.9999f) + return make_float3(0.0f, 0.0f, 0.0f); + + float pArea = (w.z < -0.9999f)? 1.0f: lambda*w.z; + float v; + if(wo_outside) { + const float3 wh = normalize(wo - w); + if(wh.z < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + const float dotW_WH = dot(-w, wh); + v = fresnel_dielectric_cos(dotW_WH, eta) * max(0.0f, dotW_WH) * D_ggx(wh, alpha.x) * 0.25f / (pArea * dotW_WH); + } + else { + float3 wh = normalize(wo*eta - w); + if(wh.z < 0.0f) + wh = -wh; + const float dotW_WH = dot(-w, wh), dotWO_WH = dot(wo, wh); + if(dotW_WH < 0.0f) + return make_float3(0.0f, 0.0f, 0.0f); + + float temp = dotW_WH + eta*dotWO_WH; + v = (1.0f - fresnel_dielectric_cos(dotW_WH, eta)) * max(0.0f, dotW_WH) * max(0.0f, -dotWO_WH) * D_ggx(wh, alpha.x) / (pArea * temp * temp); + } + + return make_float3(v, v, v); +} + +/* === Utility functions for the random walks === */ + +/* Smith Lambda function for GGX (based on page 12 of the supplemental implementation). */ +ccl_device_inline float mf_lambda(const float3 w, const float2 alpha) +{ + if(w.z > 0.9999f) + return 0.0f; + else if(w.z < -0.9999f) + return -1.0f; + + const float inv_wz2 = 1.0f / (w.z*w.z); + const float2 wa = make_float2(w.x, w.y)*alpha; + float v = sqrtf(1.0f + dot(wa, wa) * inv_wz2); + if(w.z <= 0.0f) + v = -v; + + return 0.5f*(v - 1.0f); +} + +/* Height distribution CDF (based on page 4 of the supplemental implementation). */ +ccl_device_inline float mf_invC1(const float h) +{ + return 2.0f * saturate(h) - 1.0f; +} + +ccl_device_inline float mf_C1(const float h) +{ + return saturate(0.5f * (h + 1.0f)); +} + +/* Masking function (based on page 16 of the supplemental implementation). */ +ccl_device_inline float mf_G1(const float3 w, const float C1, const float lambda) +{ + if(w.z > 0.9999f) + return 1.0f; + if(w.z < 1e-5f) + return 0.0f; + return powf(C1, lambda); +} + +/* Sampling from the visible height distribution (based on page 17 of the supplemental implementation). */ +ccl_device_inline bool mf_sample_height(const float3 w, float *h, float *C1, float *G1, float *lambda, const float U) +{ + if(w.z > 0.9999f) + return false; + if(w.z < -0.9999f) { + *C1 *= U; + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + else if(fabsf(w.z) >= 0.0001f) { + if(U > 1.0f - *G1) + return false; + if(*lambda >= 0.0f) { + *C1 = 1.0f; + } + else { + *C1 *= powf(1.0f-U, -1.0f / *lambda); + } + *h = mf_invC1(*C1); + *G1 = mf_G1(w, *C1, *lambda); + } + return true; +} + +/* === PDF approximations for the different phase functions. === + * As explained in bsdf_microfacet_multi_impl.h, using approximations with MIS still produces an unbiased result. */ + +/* Approximation for the albedo of the single-scattering GGX distribution, + * the missing energy is then approximated as a diffuse reflection for the PDF. */ +ccl_device_inline float mf_ggx_albedo(float r) +{ + float albedo = 0.806495f*expf(-1.98712f*r*r) + 0.199531f; + albedo -= ((((((1.76741f*r - 8.43891f)*r + 15.784f)*r - 14.398f)*r + 6.45221f)*r - 1.19722f)*r + 0.027803f)*r + 0.00568739f; + return saturate(albedo); +} + +ccl_device_inline float mf_ggx_pdf(const float3 wi, const float3 wo, const float alpha) +{ + return 0.25f * D_ggx(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, make_float2(alpha, alpha))) * wi.z) + (1.0f - mf_ggx_albedo(alpha)) * wo.z; +} + +ccl_device_inline float mf_ggx_aniso_pdf(const float3 wi, const float3 wo, const float2 alpha) +{ + return 0.25f * D_ggx_aniso(normalize(wi+wo), alpha) / ((1.0f + mf_lambda(wi, alpha)) * wi.z) + (1.0f - mf_ggx_albedo(sqrtf(alpha.x*alpha.y))) * wo.z; +} + +ccl_device_inline float mf_diffuse_pdf(const float3 wo) +{ + return M_1_PI_F * wo.z; +} + +ccl_device_inline float mf_glass_pdf(const float3 wi, const float3 wo, const float alpha, const float eta) +{ + float3 wh; + float fresnel; + if(wi.z*wo.z > 0.0f) { + wh = normalize(wi + wo); + fresnel = fresnel_dielectric_cos(dot(wi, wh), eta); + } + else { + wh = normalize(wi + wo*eta); + fresnel = 1.0f - fresnel_dielectric_cos(dot(wi, wh), eta); + } + if(wh.z < 0.0f) + wh = -wh; + float3 r_wi = (wi.z < 0.0f)? -wi: wi; + return fresnel * max(0.0f, dot(r_wi, wh)) * D_ggx(wh, alpha) / ((1.0f + mf_lambda(r_wi, make_float2(alpha, alpha))) * r_wi.z) + fabsf(wo.z); +} + +/* === Actual random walk implementations, one version of mf_eval and mf_sample per phase function. === */ + +#define MF_NAME_JOIN(x,y) x ## _ ## y +#define MF_NAME_EVAL(x,y) MF_NAME_JOIN(x,y) +#define MF_FUNCTION_FULL_NAME(prefix) MF_NAME_EVAL(prefix, MF_PHASE_FUNCTION) + +#define MF_PHASE_FUNCTION glass +#define MF_MULTI_GLASS +#include "bsdf_microfacet_multi_impl.h" + +/* The diffuse phase function is not implemented as a node yet. */ +#if 0 +#define MF_PHASE_FUNCTION diffuse +#define MF_MULTI_DIFFUSE +#include "bsdf_microfacet_multi_impl.h" +#endif + +#define MF_PHASE_FUNCTION glossy +#define MF_MULTI_GLOSSY +#include "bsdf_microfacet_multi_impl.h" + +ccl_device void bsdf_microfacet_multi_ggx_blur(ShaderClosure *sc, float roughness) +{ + sc->data0 = fmaxf(roughness, sc->data0); /* alpha_x */ + sc->data1 = fmaxf(roughness, sc->data1); /* alpha_y */ +} + +/* === Closure implementations === */ + +/* Multiscattering GGX Glossy closure */ + +ccl_device int bsdf_microfacet_multi_ggx_common_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = clamp(sc->data1, 1e-4f, 1.0f); + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device int bsdf_microfacet_multi_ggx_aniso_setup(ShaderClosure *sc) +{ + if(is_zero(sc->T)) + sc->T = make_float3(1.0f, 0.0f, 0.0f); + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device int bsdf_microfacet_multi_ggx_setup(ShaderClosure *sc) +{ + sc->data1 = sc->data0; + + return bsdf_microfacet_multi_ggx_common_setup(sc); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + *pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + return mf_eval_glossy(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); +} + +ccl_device int bsdf_microfacet_multi_ggx_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + bool is_aniso = (sc->data0 != sc->data1); + float3 X, Y, Z; + Z = sc->N; + if(is_aniso) + make_orthonormals_tangent(Z, sc->T, &X, &Y); + else + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glossy(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, NULL, NULL); + if(is_aniso) + *pdf = mf_ggx_aniso_pdf(localI, localO, make_float2(sc->data0, sc->data1)); + else + *pdf = mf_ggx_pdf(localI, localO, sc->data0); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + return LABEL_REFLECT|LABEL_GLOSSY; +} + +/* Multiscattering GGX Glass closure */ + +ccl_device int bsdf_microfacet_multi_ggx_glass_setup(ShaderClosure *sc) +{ + sc->data0 = clamp(sc->data0, 1e-4f, 1.0f); /* alpha */ + sc->data1 = sc->data0; + sc->data2 = max(0.0f, sc->data2); /* ior */ + sc->custom1 = saturate(sc->custom1); /* color */ + sc->custom2 = saturate(sc->custom2); + sc->custom3 = saturate(sc->custom3); + + sc->type = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID; + + return SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM; +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_transmit(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, false, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device float3 bsdf_microfacet_multi_ggx_glass_eval_reflect(const ShaderClosure *sc, const float3 I, const float3 omega_in, float *pdf, ccl_addr_space uint *lcg_state) { + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO = make_float3(dot(omega_in, X), dot(omega_in, Y), dot(omega_in, Z)); + + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + return mf_eval_glass(localI, localO, true, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); +} + +ccl_device int bsdf_microfacet_multi_ggx_glass_sample(KernelGlobals *kg, const ShaderClosure *sc, float3 Ng, float3 I, float3 dIdx, float3 dIdy, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf, ccl_addr_space uint *lcg_state) +{ + float3 X, Y, Z; + Z = sc->N; + make_orthonormals(Z, &X, &Y); + + float3 localI = make_float3(dot(I, X), dot(I, Y), dot(I, Z)); + float3 localO; + + *eval = mf_sample_glass(localI, &localO, make_float3(sc->custom1, sc->custom2, sc->custom3), sc->data0, sc->data1, lcg_state, sc->data2); + *pdf = mf_glass_pdf(localI, localO, sc->data0, sc->data2); + *eval *= *pdf; + + *omega_in = X*localO.x + Y*localO.y + Z*localO.z; + if(localO.z*localI.z > 0.0f) + return LABEL_REFLECT|LABEL_GLOSSY; + else + return LABEL_TRANSMIT|LABEL_GLOSSY; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h new file mode 100644 index 00000000000..afd4a8da62a --- /dev/null +++ b/intern/cycles/kernel/closure/bsdf_microfacet_multi_impl.h @@ -0,0 +1,226 @@ +/* + * Copyright 2011-2016 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. + */ + +/* Evaluate the BSDF from wi to wo. + * Evaluation is split into the analytical single-scattering BSDF and the multi-scattering BSDF, + * which is evaluated stochastically through a random walk. At each bounce (except for the first one), + * the amount of reflection from here towards wo is evaluated before bouncing again. + * + * Because of the random walk, the evaluation is not deterministic, but its expected value is equal to + * the correct BSDF, which is enough for Monte-Carlo rendering. The PDF also can't be determined + * analytically, so the single-scattering PDF plus a diffuse term to account for the multi-scattered + * energy is used. In combination with MIS, that is enough to produce an unbiased result, although + * the balance heuristic isn't necessarily optimal anymore. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_eval)(float3 wi, float3 wo, const bool wo_outside, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint* lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + /* Evaluating for a shallower incoming direction produces less noise, and the properties of the BSDF guarantee reciprocity. */ + bool swapped = false; +#ifdef MF_MULTI_GLASS + if(wi.z*wo.z < 0.0f) { + /* Glass transmission is a special case and requires the directions to change hemisphere. */ + if(-wo.z < wi.z) { + swapped = true; + float3 tmp = -wo; + wo = -wi; + wi = tmp; + } + } + else +#endif + if(wo.z < wi.z) { + swapped = true; + float3 tmp = wo; + wo = wi; + wi = tmp; + } + + if(wi.z < 1e-5f || (wo.z < 1e-5f && wo_outside) || (wo.z > -1e-5f && !wo_outside)) + return make_float3(0.0f, 0.0f, 0.0f); + + const float2 alpha = make_float2(alpha_x, alpha_y); + + float lambda_r = mf_lambda(-wi, alpha); + float shadowing_lambda = mf_lambda(wo_outside? wo: -wo, alpha); + + /* Analytically compute single scattering for lower noise. */ + float3 eval; +#ifdef MF_MULTI_GLASS + eval = mf_eval_phase_glass(-wi, lambda_r, wo, wo_outside, alpha, eta); + if(wo_outside) + eval *= -lambda_r / (shadowing_lambda - lambda_r); + else + eval *= -lambda_r * beta(-lambda_r, shadowing_lambda+1.0f); +#elif defined(MF_MULTI_DIFFUSE) + /* Diffuse has no special closed form for the single scattering bounce */ + eval = make_float3(0.0f, 0.0f, 0.0f); +#else /* MF_MULTI_GLOSSY */ + const float3 wh = normalize(wi+wo); + const float G2 = 1.0f / (1.0f - (lambda_r + 1.0f) + shadowing_lambda); + float val = G2 * 0.25f / wi.z; + if(alpha.x == alpha.y) + val *= D_ggx(wh, alpha.x); + else + val *= D_ggx_aniso(wh, alpha); + if(n && k) { + eval = fresnel_conductor(dot(wh, wi), *n, *k) * val; + } + else { + eval = make_float3(val, val, val); + } +#endif + + float3 wr = -wi; + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + + for(int order = 0; order < 10; order++) { + /* Sample microfacet height and normal */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) + break; + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + +#ifdef MF_MULTI_DIFFUSE + if(order == 0) { + /* Compute single-scattering for diffuse. */ + const float G2_G1 = -lambda_r / (shadowing_lambda - lambda_r); + eval += throughput * G2_G1 * mf_eval_phase_diffuse(wo, wm); + } +#endif + if(order > 0) { + /* Evaluate amount of scattering towards wo on this microfacet. */ + float3 phase; +#ifdef MF_MULTI_GLASS + if(outside) + phase = mf_eval_phase_glass(wr, lambda_r, wo, wo_outside, alpha, eta); + else + phase = mf_eval_phase_glass(wr, lambda_r, -wo, !wo_outside, alpha, 1.0f/eta); +#elif defined(MF_MULTI_DIFFUSE) + phase = mf_eval_phase_diffuse(wo, wm); +#else /* MF_MULTI_GLOSSY */ + phase = mf_eval_phase_glossy(wr, lambda_r, wo, alpha, n, k) * throughput; +#endif + eval += throughput * phase * mf_G1(wo_outside? wo: -wo, mf_C1((outside == wo_outside)? hr: -hr), shadowing_lambda); + } + if(order+1 < 10) { + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + outside = !outside; + wr = -wr; + hr = -hr; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + lambda_r = mf_lambda(wr, alpha); + + throughput *= color; + + C1_r = mf_C1(hr); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + } + + if(swapped) + eval *= fabsf(wi.z / wo.z); + return eval; +} + +/* Perform a random walk on the microsurface starting from wi, returning the direction in which the walk + * escaped the surface in wo. The function returns the throughput between wi and wo. + * Without reflection losses due to coloring or fresnel absorption in conductors, the sampling is optimal. + */ +ccl_device float3 MF_FUNCTION_FULL_NAME(mf_sample)(float3 wi, float3 *wo, const float3 color, const float alpha_x, const float alpha_y, ccl_addr_space uint *lcg_state +#ifdef MF_MULTI_GLASS + , const float eta +#elif defined(MF_MULTI_GLOSSY) + , float3 *n, float3 *k +#endif +) +{ + const float2 alpha = make_float2(alpha_x, alpha_y); + + float3 throughput = make_float3(1.0f, 1.0f, 1.0f); + float3 wr = -wi; + float lambda_r = mf_lambda(wr, alpha); + float hr = 1.0f; + float C1_r = 1.0f; + float G1_r = 0.0f; + bool outside = true; + + int order; + for(order = 0; order < 10; order++) { + /* Sample microfacet height. */ + if(!mf_sample_height(wr, &hr, &C1_r, &G1_r, &lambda_r, lcg_step_float_addrspace(lcg_state))) { + /* The random walk has left the surface. */ + *wo = outside? wr: -wr; + return throughput; + } + /* Sample microfacet normal. */ + float3 wm = mf_sample_vndf(-wr, alpha, make_float2(lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state))); + + /* First-bounce color is already accounted for in mix weight. */ + if(order > 0) + throughput *= color; + + /* Bounce from the microfacet. */ +#ifdef MF_MULTI_GLASS + bool next_outside; + wr = mf_sample_phase_glass(-wr, outside? eta: 1.0f/eta, wm, lcg_step_float_addrspace(lcg_state), &next_outside); + if(!next_outside) { + hr = -hr; + wr = -wr; + outside = !outside; + } +#elif defined(MF_MULTI_DIFFUSE) + wr = mf_sample_phase_diffuse(wm, + lcg_step_float_addrspace(lcg_state), + lcg_step_float_addrspace(lcg_state)); +#else /* MF_MULTI_GLOSSY */ + wr = mf_sample_phase_glossy(-wr, n, k, &throughput, wm); +#endif + + /* Update random walk parameters. */ + lambda_r = mf_lambda(wr, alpha); + G1_r = mf_G1(wr, C1_r, lambda_r); + } + *wo = make_float3(0.0f, 0.0f, 1.0f); + return make_float3(0.0f, 0.0f, 0.0f); +} + +#undef MF_MULTI_GLASS +#undef MF_MULTI_DIFFUSE +#undef MF_MULTI_GLOSSY +#undef MF_PHASE_FUNCTION diff --git a/intern/cycles/kernel/closure/bsdf_util.h b/intern/cycles/kernel/closure/bsdf_util.h index 05816bac2c1..b0c5280b6cb 100644 --- a/intern/cycles/kernel/closure/bsdf_util.h +++ b/intern/cycles/kernel/closure/bsdf_util.h @@ -80,7 +80,7 @@ ccl_device float fresnel_dielectric( return 1; // total internal reflection } else { - float dnp = sqrtf(arg); + float dnp = max(sqrtf(arg), 1e-7f); float nK = (neta * cos)- dnp; *T = -(neta * I)+(nK * Nn); #ifdef __RAY_DIFFERENTIALS__ @@ -111,10 +111,9 @@ ccl_device float fresnel_dielectric_cos(float cosi, float eta) return 1.0f; // TIR(no refracted component) } -#if 0 ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k) { - float3 cosi2 = make_float3(cosi*cosi); + float3 cosi2 = make_float3(cosi*cosi, cosi*cosi, cosi*cosi); float3 one = make_float3(1.0f, 1.0f, 1.0f); float3 tmp_f = eta * eta + k * k; float3 tmp = tmp_f * cosi2; @@ -124,7 +123,6 @@ ccl_device float3 fresnel_conductor(float cosi, const float3 eta, const float3 k (tmp_f + (2.0f * eta * cosi) + cosi2); return(Rparl2 + Rperp2) * 0.5f; } -#endif ccl_device float smooth_step(float edge0, float edge1, float x) { diff --git a/intern/cycles/kernel/geom/geom.h b/intern/cycles/kernel/geom/geom.h index c94a5384d1f..d2c7edb11ea 100644 --- a/intern/cycles/kernel/geom/geom.h +++ b/intern/cycles/kernel/geom/geom.h @@ -15,27 +15,6 @@ * limitations under the License. */ -/* bottom-most stack entry, indicating the end of traversal */ -#define ENTRYPOINT_SENTINEL 0x76543210 - -/* 64 object BVH + 64 mesh BVH + 64 object node splitting */ -#define BVH_STACK_SIZE 192 -#define BVH_QSTACK_SIZE 384 -#define BVH_NODE_SIZE 4 -#define BVH_NODE_LEAF_SIZE 1 -#define BVH_QNODE_SIZE 7 -#define BVH_QNODE_LEAF_SIZE 1 -#define TRI_NODE_SIZE 3 - -/* silly workaround for float extended precision that happens when compiling - * without sse support on x86, it results in different results for float ops - * that you would otherwise expect to compare correctly */ -#if !defined(__i386__) || defined(__SSE__) -# define NO_EXTENDED_PRECISION -#else -# define NO_EXTENDED_PRECISION volatile -#endif - #include "geom_attribute.h" #include "geom_object.h" #include "geom_triangle.h" @@ -45,5 +24,4 @@ #include "geom_curve.h" #include "geom_volume.h" #include "geom_primitive.h" -#include "geom_bvh.h" diff --git a/intern/cycles/kernel/geom/geom_curve.h b/intern/cycles/kernel/geom/geom_curve.h index 8894843997c..292e1bfca0e 100644 --- a/intern/cycles/kernel/geom/geom_curve.h +++ b/intern/cycles/kernel/geom/geom_curve.h @@ -450,8 +450,8 @@ ccl_device_inline bool bvh_cardinal_curve_intersect(KernelGlobals *kg, Intersect else if(level == 1) { /* the maximum recursion depth is reached. - * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. - * dP* is reversed if necessary.*/ + * check if dP0.(Q-P0)>=0 and dPn.(Pn-Q)>=0. + * dP* is reversed if necessary.*/ float t = isect->t; float u = 0.0f; float gd = 0.0f; diff --git a/intern/cycles/kernel/geom/geom_motion_triangle.h b/intern/cycles/kernel/geom/geom_motion_triangle.h index ffe55529110..2fb8e219884 100644 --- a/intern/cycles/kernel/geom/geom_motion_triangle.h +++ b/intern/cycles/kernel/geom/geom_motion_triangle.h @@ -47,13 +47,13 @@ ccl_device_inline int find_attribute_motion(KernelGlobals *kg, int object, uint return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z; } -ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3]) +ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 verts[3]) { if(step == numsteps) { /* center step: regular vertex location */ - verts[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - verts[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - verts[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + verts[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + verts[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + verts[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); } else { /* center step not store in this array */ @@ -62,19 +62,19 @@ ccl_device_inline void motion_triangle_verts_for_step(KernelGlobals *kg, float3 offset += step*numverts; - verts[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - verts[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - verts[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + 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)); } } -ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float3 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3]) +ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, uint4 tri_vindex, int offset, int numverts, int numsteps, int step, float3 normals[3]) { if(step == numsteps) { /* center step: regular vertex location */ - normals[0] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); - normals[1] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); - normals[2] = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + 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)); } else { /* center step not stored in this array */ @@ -83,9 +83,9 @@ ccl_device_inline void motion_triangle_normals_for_step(KernelGlobals *kg, float offset += step*numverts; - normals[0] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - normals[1] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - normals[2] = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + 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)); } } @@ -107,7 +107,7 @@ ccl_device_inline void motion_triangle_vertices(KernelGlobals *kg, int object, i /* fetch vertex coordinates */ float3 next_verts[3]; - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); @@ -259,7 +259,7 @@ ccl_device_noinline void motion_triangle_shader_setup(KernelGlobals *kg, ShaderD /* fetch vertex coordinates */ float3 verts[3], next_verts[3]; - float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim))); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step, verts); motion_triangle_verts_for_step(kg, tri_vindex, offset, numverts, numsteps, step+1, next_verts); diff --git a/intern/cycles/kernel/geom/geom_qbvh.h b/intern/cycles/kernel/geom/geom_qbvh.h deleted file mode 100644 index 2a2d7822eee..00000000000 --- a/intern/cycles/kernel/geom/geom_qbvh.h +++ /dev/null @@ -1,147 +0,0 @@ -/* - * Copyright 2011-2014, 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. - */ - -struct QBVHStackItem { - int addr; - float dist; -}; - -/* TOOD(sergey): Investigate if using intrinsics helps for both - * stack item swap and float comparison. - */ -ccl_device_inline void qbvh_item_swap(QBVHStackItem *__restrict a, - QBVHStackItem *__restrict b) -{ - QBVHStackItem tmp = *a; - *a = *b; - *b = tmp; -} - -ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1, - QBVHStackItem *__restrict s2, - QBVHStackItem *__restrict s3) -{ - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } - if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } -} - -ccl_device_inline void qbvh_stack_sort(QBVHStackItem *__restrict s1, - QBVHStackItem *__restrict s2, - QBVHStackItem *__restrict s3, - QBVHStackItem *__restrict s4) -{ - if(s2->dist < s1->dist) { qbvh_item_swap(s2, s1); } - if(s4->dist < s3->dist) { qbvh_item_swap(s4, s3); } - if(s3->dist < s1->dist) { qbvh_item_swap(s3, s1); } - if(s4->dist < s2->dist) { qbvh_item_swap(s4, s2); } - if(s3->dist < s2->dist) { qbvh_item_swap(s3, s2); } -} - -ccl_device_inline int qbvh_node_intersect(KernelGlobals *__restrict kg, - const ssef& tnear, - const ssef& tfar, -#ifdef __KERNEL_AVX2__ - const sse3f& org_idir, -#else - const sse3f& org, -#endif - const sse3f& idir, - const int near_x, - const int near_y, - const int near_z, - const int far_x, - const int far_y, - const int far_z, - const int nodeAddr, - ssef *__restrict dist) -{ - const int offset = nodeAddr*BVH_QNODE_SIZE; -#ifdef __KERNEL_AVX2__ - const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, org_idir.x); - const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, org_idir.y); - const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, org_idir.z); - const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, org_idir.x); - const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, org_idir.y); - const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, org_idir.z); -#else - const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - org.x) * idir.x; - const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - org.y) * idir.y; - const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - org.z) * idir.z; - const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - org.x) * idir.x; - const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - org.y) * idir.y; - const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - org.z) * idir.z; -#endif - -#ifdef __KERNEL_SSE41__ - const ssef tNear = maxi(maxi(tnear_x, tnear_y), maxi(tnear_z, tnear)); - const ssef tFar = mini(mini(tfar_x, tfar_y), mini(tfar_z, tfar)); - const sseb vmask = cast(tNear) > cast(tFar); - int mask = (int)movemask(vmask)^0xf; -#else - const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear); - const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar); - const sseb vmask = tNear <= tFar; - int mask = (int)movemask(vmask); -#endif - *dist = tNear; - return mask; -} - -ccl_device_inline int qbvh_node_intersect_robust(KernelGlobals *__restrict kg, - const ssef& tnear, - const ssef& tfar, -#ifdef __KERNEL_AVX2__ - const sse3f& P_idir, -#else - const sse3f& P, -#endif - const sse3f& idir, - const int near_x, - const int near_y, - const int near_z, - const int far_x, - const int far_y, - const int far_z, - const int nodeAddr, - const float difl, - ssef *__restrict dist) -{ - const int offset = nodeAddr*BVH_QNODE_SIZE; -#ifdef __KERNEL_AVX2__ - const ssef tnear_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x), idir.x, P_idir.x); - const ssef tnear_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y), idir.y, P_idir.y); - const ssef tnear_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z), idir.z, P_idir.z); - const ssef tfar_x = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x), idir.x, P_idir.x); - const ssef tfar_y = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y), idir.y, P_idir.y); - const ssef tfar_z = msub(kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z), idir.z, P_idir.z); -#else - const ssef tnear_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_x) - P.x) * idir.x; - const ssef tnear_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_y) - P.y) * idir.y; - const ssef tnear_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+near_z) - P.z) * idir.z; - const ssef tfar_x = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_x) - P.x) * idir.x; - const ssef tfar_y = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_y) - P.y) * idir.y; - const ssef tfar_z = (kernel_tex_fetch_ssef(__bvh_nodes, offset+far_z) - P.z) * idir.z; -#endif - - const float round_down = 1.0f - difl; - const float round_up = 1.0f + difl; - const ssef tNear = max4(tnear_x, tnear_y, tnear_z, tnear); - const ssef tFar = min4(tfar_x, tfar_y, tfar_z, tfar); - const sseb vmask = round_down*tNear <= round_up*tFar; - *dist = tNear; - return (int)movemask(vmask); -} diff --git a/intern/cycles/kernel/geom/geom_qbvh_traversal.h b/intern/cycles/kernel/geom/geom_qbvh_traversal.h deleted file mode 100644 index 738d08ac6fc..00000000000 --- a/intern/cycles/kernel/geom/geom_qbvh_traversal.h +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Adapted from code Copyright 2009-2010 NVIDIA Corporation, - * and code copyright 2009-2012 Intel Corporation - * - * Modifications Copyright 2011-2014, 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. - */ - -/* This is a template BVH traversal function, where various features can be - * enabled/disabled. This way we can compile optimized versions for each case - * without new features slowing things down. - * - * BVH_INSTANCING: object instancing - * BVH_HAIR: hair curve rendering - * BVH_HAIR_MINIMUM_WIDTH: hair curve rendering with minimum width - * BVH_MOTION: motion blur rendering - * - */ - -ccl_device bool BVH_FUNCTION_FULL_NAME(QBVH)(KernelGlobals *kg, - const Ray *ray, - Intersection *isect, - const uint visibility -#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) - ,uint *lcg_state, - float difl, - float extmax -#endif - ) -{ - /* TODO(sergey): - * - Test if pushing distance on the stack helps (for non shadow rays). - * - Separate version for shadow rays. - * - Likely and unlikely for if() statements. - * - Test restrict attribute for pointers. - */ - - /* Traversal stack in CUDA thread-local memory. */ - QBVHStackItem traversalStack[BVH_QSTACK_SIZE]; - traversalStack[0].addr = ENTRYPOINT_SENTINEL; - traversalStack[0].dist = -FLT_MAX; - - /* Traversal variables in registers. */ - int stackPtr = 0; - int nodeAddr = kernel_data.bvh.root; - float nodeDist = -FLT_MAX; - - /* Ray parameters in registers. */ - float3 P = ray->P; - float3 dir = bvh_clamp_direction(ray->D); - float3 idir = bvh_inverse_direction(dir); - int object = OBJECT_NONE; - -#if BVH_FEATURE(BVH_MOTION) - Transform ob_itfm; -#endif - -#ifndef __KERNEL_SSE41__ - if(!isfinite(P.x)) { - return false; - } -#endif - - isect->t = ray->t; - isect->u = 0.0f; - isect->v = 0.0f; - isect->prim = PRIM_NONE; - isect->object = OBJECT_NONE; - - BVH_DEBUG_INIT(); - - ssef tnear(0.0f), tfar(ray->t); - sse3f idir4(ssef(idir.x), ssef(idir.y), ssef(idir.z)); - -#ifdef __KERNEL_AVX2__ - float3 P_idir = P*idir; - sse3f P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -#else - sse3f org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -#endif - - /* Offsets to select the side that becomes the lower or upper bound. */ - int near_x, near_y, near_z; - int far_x, far_y, far_z; - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - - IsectPrecalc isect_precalc; - triangle_intersect_precalc(dir, &isect_precalc); - - /* Traversal loop. */ - do { - do { - /* Traverse internal nodes. */ - while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL) { - if(UNLIKELY(nodeDist > isect->t)) { - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - int traverseChild; - ssef dist; - - BVH_DEBUG_NEXT_STEP(); - -#if BVH_FEATURE(BVH_HAIR_MINIMUM_WIDTH) - if(difl != 0.0f) { - /* NOTE: We extend all the child BB instead of fetching - * and checking visibility flags for each of the, - * - * Need to test if doing opposite would be any faster. - */ - traverseChild = qbvh_node_intersect_robust(kg, - tnear, - tfar, -# ifdef __KERNEL_AVX2__ - P_idir4, -# else - org, -# endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - difl, - &dist); - } - else -#endif /* BVH_HAIR_MINIMUM_WIDTH */ - { - traverseChild = qbvh_node_intersect(kg, - tnear, - tfar, -#ifdef __KERNEL_AVX2__ - P_idir4, -#else - org, -#endif - idir4, - near_x, near_y, near_z, - far_x, far_y, far_z, - nodeAddr, - &dist); - } - - if(traverseChild != 0) { - float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_QNODE_SIZE+6); - - /* One child is hit, continue with that child. */ - int r = __bscf(traverseChild); - float d0 = ((float*)&dist)[r]; - if(traverseChild == 0) { - nodeAddr = __float_as_int(cnodes[r]); - nodeDist = d0; - continue; - } - - /* Two children are hit, push far child, and continue with - * closer child. - */ - int c0 = __float_as_int(cnodes[r]); - r = __bscf(traverseChild); - int c1 = __float_as_int(cnodes[r]); - float d1 = ((float*)&dist)[r]; - if(traverseChild == 0) { - if(d1 < d0) { - nodeAddr = c1; - nodeDist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; - continue; - } - else { - nodeAddr = c0; - nodeDist = d0; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - continue; - } - } - - /* Here starts the slow path for 3 or 4 hit children. We push - * all nodes onto the stack to sort them there. - */ - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c1; - traversalStack[stackPtr].dist = d1; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c0; - traversalStack[stackPtr].dist = d0; - - /* Three children are hit, push all onto stack and sort 3 - * stack items, continue with closest child. - */ - r = __bscf(traverseChild); - int c2 = __float_as_int(cnodes[r]); - float d2 = ((float*)&dist)[r]; - if(traverseChild == 0) { - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2]); - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - /* Four children are hit, push all onto stack and sort 4 - * stack items, continue with closest child. - */ - r = __bscf(traverseChild); - int c3 = __float_as_int(cnodes[r]); - float d3 = ((float*)&dist)[r]; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c3; - traversalStack[stackPtr].dist = d3; - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = c2; - traversalStack[stackPtr].dist = d2; - qbvh_stack_sort(&traversalStack[stackPtr], - &traversalStack[stackPtr - 1], - &traversalStack[stackPtr - 2], - &traversalStack[stackPtr - 3]); - } - - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - } - - /* If node is leaf, fetch triangle list. */ - if(nodeAddr < 0) { - float4 leaf = kernel_tex_fetch(__bvh_leaf_nodes, (-nodeAddr-1)*BVH_QNODE_LEAF_SIZE); - -#ifdef __VISIBILITY_FLAG__ - if(UNLIKELY((nodeDist > isect->t) || ((__float_as_uint(leaf.z) & visibility) == 0))) -#else - if(UNLIKELY((nodeDist > isect->t))) -#endif - { - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - continue; - } - - int primAddr = __float_as_int(leaf.x); - -#if BVH_FEATURE(BVH_INSTANCING) - if(primAddr >= 0) { -#endif - int primAddr2 = __float_as_int(leaf.y); - const uint type = __float_as_int(leaf.w); - - /* Pop. */ - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - - /* Primitive intersection. */ - switch(type & PRIMITIVE_ALL) { - case PRIMITIVE_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(triangle_intersect(kg, &isect_precalc, isect, P, visibility, object, primAddr)) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#if BVH_FEATURE(BVH_MOTION) - case PRIMITIVE_MOTION_TRIANGLE: { - for(; primAddr < primAddr2; primAddr++) { - BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - if(motion_triangle_intersect(kg, isect, P, dir, ray->time, visibility, object, primAddr)) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#endif /* BVH_FEATURE(BVH_MOTION) */ -#if BVH_FEATURE(BVH_HAIR) - case PRIMITIVE_CURVE: - case PRIMITIVE_MOTION_CURVE: { - for(; primAddr < primAddr2; primAddr++) { - BVH_DEBUG_NEXT_STEP(); - kernel_assert(kernel_tex_fetch(__prim_type, primAddr) == type); - bool hit; - if(kernel_data.curve.curveflags & CURVE_KN_INTERPOLATE) - hit = bvh_cardinal_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - else - hit = bvh_curve_intersect(kg, isect, P, dir, visibility, object, primAddr, ray->time, type, lcg_state, difl, extmax); - if(hit) { - tfar = ssef(isect->t); - /* Shadow ray early termination. */ - if(visibility == PATH_RAY_SHADOW_OPAQUE) - return true; - } - } - break; - } -#endif /* BVH_FEATURE(BVH_HAIR) */ - } - } -#if BVH_FEATURE(BVH_INSTANCING) - else { - /* Instance push. */ - object = kernel_tex_fetch(__prim_object, -primAddr-1); - -# if BVH_FEATURE(BVH_MOTION) - qbvh_instance_motion_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist, &ob_itfm); -# else - qbvh_instance_push(kg, object, ray, &P, &dir, &idir, &isect->t, &nodeDist); -# endif - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - tfar = ssef(isect->t); - idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); -# ifdef __KERNEL_AVX2__ - P_idir = P*idir; - P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -# endif - triangle_intersect_precalc(dir, &isect_precalc); - - ++stackPtr; - kernel_assert(stackPtr < BVH_QSTACK_SIZE); - traversalStack[stackPtr].addr = ENTRYPOINT_SENTINEL; - traversalStack[stackPtr].dist = -FLT_MAX; - - nodeAddr = kernel_tex_fetch(__object_node, object); - - BVH_DEBUG_NEXT_INSTANCE(); - } - } -#endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); - -#if BVH_FEATURE(BVH_INSTANCING) - if(stackPtr >= 0) { - kernel_assert(object != OBJECT_NONE); - - /* Instance pop. */ -# if BVH_FEATURE(BVH_MOTION) - bvh_instance_motion_pop(kg, object, ray, &P, &dir, &idir, &isect->t, &ob_itfm); -# else - bvh_instance_pop(kg, object, ray, &P, &dir, &idir, &isect->t); -# endif - - if(idir.x >= 0.0f) { near_x = 0; far_x = 1; } else { near_x = 1; far_x = 0; } - if(idir.y >= 0.0f) { near_y = 2; far_y = 3; } else { near_y = 3; far_y = 2; } - if(idir.z >= 0.0f) { near_z = 4; far_z = 5; } else { near_z = 5; far_z = 4; } - tfar = ssef(isect->t); - idir4 = sse3f(ssef(idir.x), ssef(idir.y), ssef(idir.z)); -# ifdef __KERNEL_AVX2__ - P_idir = P*idir; - P_idir4 = sse3f(P_idir.x, P_idir.y, P_idir.z); -# else - org = sse3f(ssef(P.x), ssef(P.y), ssef(P.z)); -# endif - triangle_intersect_precalc(dir, &isect_precalc); - - object = OBJECT_NONE; - nodeAddr = traversalStack[stackPtr].addr; - nodeDist = traversalStack[stackPtr].dist; - --stackPtr; - } -#endif /* FEATURE(BVH_INSTANCING) */ - } while(nodeAddr != ENTRYPOINT_SENTINEL); - - return (isect->prim != PRIM_NONE); -} diff --git a/intern/cycles/kernel/geom/geom_triangle.h b/intern/cycles/kernel/geom/geom_triangle.h index 995dfac5b09..0c2351e1d1b 100644 --- a/intern/cycles/kernel/geom/geom_triangle.h +++ b/intern/cycles/kernel/geom/geom_triangle.h @@ -27,12 +27,11 @@ CCL_NAMESPACE_BEGIN ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + const float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + const float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + const float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); - float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); - /* return normal */ if(ccl_fetch(sd, flag) & SD_NEGATIVE_SCALE_APPLIED) return normalize(cross(v2 - v0, v1 - v0)); @@ -44,11 +43,10 @@ ccl_device_inline float3 triangle_normal(KernelGlobals *kg, ShaderData *sd) ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int prim, float u, float v, float3 *P, float3 *Ng, int *shader) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + float3 v0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + float3 v1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + float3 v2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* compute point */ float t = 1.0f - u - v; @@ -71,11 +69,10 @@ ccl_device_inline void triangle_point_normal(KernelGlobals *kg, int object, int ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3]) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - P[0] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - P[1] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - P[2] = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + P[0] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + P[1] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + P[2] = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); } /* Interpolate smooth vertex normal from vertices */ @@ -83,11 +80,10 @@ ccl_device_inline void triangle_vertices(KernelGlobals *kg, int prim, float3 P[3 ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, float u, float v) { /* load triangle vertices */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x))); - float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y))); - float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z))); + 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)); return normalize((1.0f - u - v)*n2 + u*n0 + v*n1); } @@ -97,11 +93,10 @@ ccl_device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int prim, flo ccl_device_inline void triangle_dPdudv(KernelGlobals *kg, int prim, ccl_addr_space float3 *dPdu, ccl_addr_space float3 *dPdv) { /* fetch triangle vertex coordinates */ - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); - - float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x))); - float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y))); - float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z))); + const uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, prim); + const float3 p0 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+0)); + const float3 p1 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+1)); + const float3 p2 = float4_to_float3(kernel_tex_fetch(__prim_tri_verts, tri_vindex.w+2)); /* compute derivatives of P w.r.t. uv */ *dPdu = (p0 - p2); @@ -119,11 +114,11 @@ ccl_device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *s return kernel_tex_fetch(__attributes_float, offset + ccl_fetch(sd, prim)); } else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); - float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x)); - float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y)); - float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z)); + float f0 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.x); + float f1 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.y); + float f2 = kernel_tex_fetch(__attributes_float, offset + tri_vindex.z); #ifdef __RAY_DIFFERENTIALS__ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2; @@ -162,11 +157,11 @@ ccl_device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + ccl_fetch(sd, prim))); } else if(elem == ATTR_ELEMENT_VERTEX || elem == ATTR_ELEMENT_VERTEX_MOTION) { - float4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); + uint4 tri_vindex = kernel_tex_fetch(__tri_vindex, ccl_fetch(sd, prim)); - float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x))); - float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y))); - float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z))); + float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.x)); + float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.y)); + float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + tri_vindex.z)); #ifdef __RAY_DIFFERENTIALS__ if(dx) *dx = ccl_fetch(sd, du).dx*f0 + ccl_fetch(sd, dv).dx*f1 - (ccl_fetch(sd, du).dx + ccl_fetch(sd, dv).dx)*f2; diff --git a/intern/cycles/kernel/geom/geom_triangle_intersect.h b/intern/cycles/kernel/geom/geom_triangle_intersect.h index b6dfc769012..720ee6a1f5c 100644 --- a/intern/cycles/kernel/geom/geom_triangle_intersect.h +++ b/intern/cycles/kernel/geom/geom_triangle_intersect.h @@ -106,9 +106,10 @@ ccl_device_inline bool triangle_intersect(KernelGlobals *kg, const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); @@ -202,9 +203,10 @@ ccl_device_inline void triangle_intersect_subsurface( const float Sz = isect_precalc->Sz; /* Calculate vertices relative to ray origin. */ - const float4 tri_a = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, triAddr*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, triAddr); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_tri_verts, tri_vindex+2); const float3 A = make_float3(tri_a.x - P.x, tri_a.y - P.y, tri_a.z - P.z); const float3 B = make_float3(tri_b.x - P.x, tri_b.y - P.y, tri_b.z - P.z); const float3 C = make_float3(tri_c.x - P.x, tri_c.y - P.y, tri_c.z - P.z); @@ -253,6 +255,13 @@ ccl_device_inline void triangle_intersect_subsurface( /* Normalize U, V, W, and T. */ const float inv_det = 1.0f / det; + const float t = T * inv_det; + for(int i = min(max_hits, ss_isect->num_hits); i >= 0; --i) { + if(ss_isect->hits[i].t == t) { + return; + } + } + ss_isect->num_hits++; int hit; @@ -275,7 +284,7 @@ ccl_device_inline void triangle_intersect_subsurface( isect->type = PRIMITIVE_TRIANGLE; isect->u = U * inv_det; isect->v = V * inv_det; - isect->t = T * inv_det; + isect->t = t; /* Record geometric normal. */ /* TODO(sergey): Use float4_to_float3() on just an edges. */ @@ -324,9 +333,10 @@ ccl_device_inline float3 triangle_refine(KernelGlobals *kg, P = P + D*t; - const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_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); @@ -381,9 +391,10 @@ ccl_device_inline float3 triangle_refine_subsurface(KernelGlobals *kg, P = P + D*t; #ifdef __INTERSECTION_REFINE__ - const float4 tri_a = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+0), - tri_b = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+1), - tri_c = kernel_tex_fetch(__tri_storage, isect->prim*TRI_NODE_SIZE+2); + const uint tri_vindex = kernel_tex_fetch(__prim_tri_index, isect->prim); + const float4 tri_a = kernel_tex_fetch(__prim_tri_verts, tri_vindex+0), + tri_b = kernel_tex_fetch(__prim_tri_verts, tri_vindex+1), + tri_c = kernel_tex_fetch(__prim_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/kernel_accumulate.h b/intern/cycles/kernel/kernel_accumulate.h index 5f5a3609ded..0e13b22bd2c 100644 --- a/intern/cycles/kernel/kernel_accumulate.h +++ b/intern/cycles/kernel/kernel_accumulate.h @@ -50,7 +50,7 @@ ccl_device_inline void bsdf_eval_init(BsdfEval *eval, ClosureType type, float3 v else eval->diffuse = value; #else - *eval = value; + eval->diffuse = value; #endif } @@ -80,7 +80,7 @@ void bsdf_eval_accum(BsdfEval *eval, ClosureType type, float3 value) else eval->diffuse += value; #else - *eval += value; + eval->diffuse += value; #endif } @@ -98,7 +98,7 @@ ccl_device_inline bool bsdf_eval_is_zero(BsdfEval *eval) else return is_zero(eval->diffuse); #else - return is_zero(*eval); + return is_zero(eval->diffuse); #endif } @@ -117,7 +117,7 @@ ccl_device_inline void bsdf_eval_mul(BsdfEval *eval, float3 value) else eval->diffuse *= value; #else - *eval *= value; + eval->diffuse *= value; #endif } @@ -172,7 +172,7 @@ ccl_device_inline void path_radiance_init(PathRadiance *L, int use_light_pass) else L->emission = make_float3(0.0f, 0.0f, 0.0f); #else - *L = make_float3(0.0f, 0.0f, 0.0f); + L->emission = make_float3(0.0f, 0.0f, 0.0f); #endif } @@ -207,7 +207,7 @@ ccl_device_inline void path_radiance_bsdf_bounce(PathRadiance *L, ccl_addr_space else *throughput *= bsdf_eval->diffuse*inverse_pdf; #else - *throughput *= *bsdf_eval*inverse_pdf; + *throughput *= bsdf_eval->diffuse*inverse_pdf; #endif } @@ -225,7 +225,7 @@ ccl_device_inline void path_radiance_accum_emission(PathRadiance *L, float3 thro else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -246,7 +246,7 @@ ccl_device_inline void path_radiance_accum_ao(PathRadiance *L, float3 throughput else L->emission += throughput*bsdf*ao; #else - *L += throughput*bsdf*ao; + L->emission += throughput*bsdf*ao; #endif } @@ -277,7 +277,7 @@ ccl_device_inline void path_radiance_accum_light(PathRadiance *L, float3 through else L->emission += throughput*bsdf_eval->diffuse*shadow; #else - *L += throughput*(*bsdf_eval)*shadow; + L->emission += throughput*bsdf_eval->diffuse*shadow; #endif } @@ -295,7 +295,7 @@ ccl_device_inline void path_radiance_accum_background(PathRadiance *L, float3 th else L->emission += throughput*value; #else - *L += throughput*value; + L->emission += throughput*value; #endif } @@ -441,7 +441,7 @@ ccl_device_inline float3 path_radiance_clamp_and_sum(KernelGlobals *kg, PathRadi else L_sum = L->emission; #else - L_sum = *L; + L_sum = L->emission; #endif /* Reject invalid value */ @@ -477,7 +477,7 @@ ccl_device_inline void path_radiance_accum_sample(PathRadiance *L, PathRadiance L->shadow += L_sample->shadow*fac; L->mist += L_sample->mist*fac; #else - *L += *L_sample * fac; + L->emission += L_sample->emission * fac; #endif } diff --git a/intern/cycles/kernel/kernel_bake.h b/intern/cycles/kernel/kernel_bake.h index 8d05befe1d4..9ee0b09529e 100644 --- a/intern/cycles/kernel/kernel_bake.h +++ b/intern/cycles/kernel/kernel_bake.h @@ -48,7 +48,7 @@ ccl_device void compute_light_pass(KernelGlobals *kg, ShaderData *sd, PathRadian /* evaluate surface shader */ float rbsdf = path_state_rng_1D(kg, &rng, &state, PRNG_BSDF); - shader_eval_surface(kg, sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, &rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* TODO, disable the closures we won't need */ @@ -220,6 +220,7 @@ ccl_device_inline float3 kernel_bake_shader_bsdf(KernelGlobals *kg, ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, ShaderData *sd, + RNG *rng, PathState *state, float3 direct, float3 indirect, @@ -239,12 +240,12 @@ ccl_device float3 kernel_bake_evaluate_direct_indirect(KernelGlobals *kg, } else { /* surface color of the pass only */ - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); return kernel_bake_shader_bsdf(kg, sd, type); } } else { - shader_eval_surface(kg, sd, state, 0.0f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, 0.0f, 0, SHADER_CONTEXT_MAIN); color = kernel_bake_shader_bsdf(kg, sd, type); } @@ -336,7 +337,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, case SHADER_EVAL_NORMAL: { if((sd.flag & SD_HAS_BUMP)) { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_MAIN); } /* compression: normal = (2 * color) - 1 */ @@ -350,7 +351,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, } case SHADER_EVAL_EMISSION: { - shader_eval_surface(kg, &sd, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, &sd, &rng, &state, 0.f, 0, SHADER_CONTEXT_EMISSION); out = shader_emissive_eval(kg, &sd); break; } @@ -403,6 +404,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_diffuse, L.indirect_diffuse, @@ -414,6 +416,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_glossy, L.indirect_glossy, @@ -425,6 +428,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, { out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_transmission, L.indirect_transmission, @@ -437,6 +441,7 @@ ccl_device void kernel_bake_evaluate(KernelGlobals *kg, ccl_global uint4 *input, #ifdef __SUBSURFACE__ out = kernel_bake_evaluate_direct_indirect(kg, &sd, + &rng, &state, L.direct_subsurface, L.indirect_subsurface, diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h index bb303b32705..c882b477c35 100644 --- a/intern/cycles/kernel/kernel_compat_cpu.h +++ b/intern/cycles/kernel/kernel_compat_cpu.h @@ -122,6 +122,17 @@ template<typename T> struct texture_image { return make_float4(r, r, r, 1.0f); } + ccl_always_inline float4 read(half4 r) + { + return half4_to_float4(r); + } + + ccl_always_inline float4 read(half r) + { + float f = half_to_float(r); + return make_float4(f, f, f, 1.0f); + } + ccl_always_inline int wrap_periodic(int x, int width) { x %= width; @@ -486,8 +497,10 @@ typedef texture<uint4> texture_uint4; typedef texture<uchar4> texture_uchar4; typedef texture_image<float> texture_image_float; typedef texture_image<uchar> texture_image_uchar; +typedef texture_image<half> texture_image_half; typedef texture_image<float4> texture_image_float4; typedef texture_image<uchar4> texture_image_uchar4; +typedef texture_image<half4> texture_image_half4; /* Macros to handle different memory storage on different devices */ diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h index 42314756f02..08f6f457805 100644 --- a/intern/cycles/kernel/kernel_compat_cuda.h +++ b/intern/cycles/kernel/kernel_compat_cuda.h @@ -42,6 +42,7 @@ #define ccl_constant #define ccl_may_alias #define ccl_addr_space +#define ccl_restrict __restrict__ /* No assert supported for CUDA */ diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h index a5708448e23..8505cb85576 100644 --- a/intern/cycles/kernel/kernel_compat_opencl.h +++ b/intern/cycles/kernel/kernel_compat_opencl.h @@ -39,6 +39,7 @@ #define ccl_global __global #define ccl_local __local #define ccl_private __private +#define ccl_restrict restrict #ifdef __SPLIT_KERNEL__ # define ccl_addr_space __global diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h index 4de8e0f698a..149ac3ed4f9 100644 --- a/intern/cycles/kernel/kernel_emission.h +++ b/intern/cycles/kernel/kernel_emission.h @@ -57,7 +57,7 @@ ccl_device_noinline float3 direct_emissive_eval(KernelGlobals *kg, /* no path flag, we're evaluating this for all closures. that's weak but * we'd have to do multiple evaluations otherwise */ path_state_modify_bounce(state, true); - shader_eval_surface(kg, emission_sd, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); + shader_eval_surface(kg, emission_sd, NULL, state, 0.0f, 0, SHADER_CONTEXT_EMISSION); path_state_modify_bounce(state, false); /* evaluate emissive closure */ @@ -124,8 +124,10 @@ ccl_device_noinline bool direct_emission(KernelGlobals *kg, #ifdef __PASSES__ /* use visibility flag to skip lights */ if(ls->shader & SHADER_EXCLUDE_ANY) { - if(ls->shader & SHADER_EXCLUDE_DIFFUSE) + if(ls->shader & SHADER_EXCLUDE_DIFFUSE) { eval->diffuse = make_float3(0.0f, 0.0f, 0.0f); + eval->subsurface = make_float3(0.0f, 0.0f, 0.0f); + } if(ls->shader & SHADER_EXCLUDE_GLOSSY) eval->glossy = make_float3(0.0f, 0.0f, 0.0f); if(ls->shader & SHADER_EXCLUDE_TRANSMIT) diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h index e06c68f2fc9..8e66a3a0340 100644 --- a/intern/cycles/kernel/kernel_globals.h +++ b/intern/cycles/kernel/kernel_globals.h @@ -37,8 +37,10 @@ struct VolumeStep; typedef struct KernelGlobals { texture_image_uchar4 texture_byte4_images[TEX_NUM_BYTE4_CPU]; texture_image_float4 texture_float4_images[TEX_NUM_FLOAT4_CPU]; + texture_image_half4 texture_half4_images[TEX_NUM_HALF4_CPU]; texture_image_float texture_float_images[TEX_NUM_FLOAT_CPU]; texture_image_uchar texture_byte_images[TEX_NUM_BYTE_CPU]; + texture_image_half texture_half_images[TEX_NUM_HALF_CPU]; # define KERNEL_TEX(type, ttype, name) ttype name; # define KERNEL_IMAGE_TEX(type, ttype, name) diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h index 736a884f819..93c4bd3f7d5 100644 --- a/intern/cycles/kernel/kernel_light.h +++ b/intern/cycles/kernel/kernel_light.h @@ -51,8 +51,8 @@ ccl_device float area_light_sample(float3 P, bool sample_coord) { /* In our name system we're using P for the center, - * which is o in the paper. - */ + * which is o in the paper. + */ float3 corner = *light_p - axisu * 0.5f - axisv * 0.5f; float axisu_len, axisv_len; diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h index 0dded397ffa..d5b31037723 100644 --- a/intern/cycles/kernel/kernel_path.h +++ b/intern/cycles/kernel/kernel_path.h @@ -25,6 +25,7 @@ #include "kernel_camera.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_accumulate.h" #include "kernel_shader.h" @@ -253,7 +254,7 @@ ccl_device void kernel_path_indirect(KernelGlobals *kg, &isect, ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_INDIRECT); #ifdef __BRANCHED_PATH__ shader_merge_closures(sd); #endif @@ -791,7 +792,7 @@ ccl_device_inline float4 kernel_path_integrate(KernelGlobals *kg, /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, &state, PRNG_BSDF); - shader_eval_surface(kg, &sd, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, rbsdf, state.flag, SHADER_CONTEXT_MAIN); /* holdout */ #ifdef __HOLDOUT__ diff --git a/intern/cycles/kernel/kernel_path_branched.h b/intern/cycles/kernel/kernel_path_branched.h index fdba1a7b025..56516967d8f 100644 --- a/intern/cycles/kernel/kernel_path_branched.h +++ b/intern/cycles/kernel/kernel_path_branched.h @@ -463,7 +463,7 @@ ccl_device float4 kernel_branched_path_integrate(KernelGlobals *kg, RNG *rng, in /* setup shading */ shader_setup_from_ray(kg, &sd, &isect, &ray); - shader_eval_surface(kg, &sd, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, &sd, rng, &state, 0.0f, state.flag, SHADER_CONTEXT_MAIN); shader_merge_closures(&sd); /* holdout */ diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h index 631a2cb75de..731dc0407c5 100644 --- a/intern/cycles/kernel/kernel_random.h +++ b/intern/cycles/kernel/kernel_random.h @@ -314,5 +314,21 @@ ccl_device_inline uint lcg_state_init(RNG *rng, const PathState *state, uint scr return lcg_init(*rng + state->rng_offset + state->sample*scramble); } +/* TODO(sergey): For until we can use generic address space from OpenCL 2.0. */ + +ccl_device_inline uint lcg_state_init_addrspace(ccl_addr_space RNG *rng, + const ccl_addr_space PathState *state, + uint scramble) +{ + return lcg_init(*rng + state->rng_offset + state->sample*scramble); +} + +ccl_device float lcg_step_float_addrspace(ccl_addr_space uint *rng) +{ + /* implicit mod 2^32 */ + *rng = (1103515245*(*rng) + 12345); + return (float)*rng * (1.0f/(float)0xFFFFFFFF); +} + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h index a0b56118ab7..765baa2a5ba 100644 --- a/intern/cycles/kernel/kernel_shader.h +++ b/intern/cycles/kernel/kernel_shader.h @@ -468,6 +468,9 @@ ccl_device void shader_merge_closures(ShaderData *sd) continue; } + if((sd->flag & SD_BSDF_HAS_CUSTOM) && !(sci->custom1 == scj->custom1 && sci->custom2 == scj->custom2 && sci->custom3 == scj->custom3)) + continue; + sci->weight += scj->weight; sci->sample_weight += scj->sample_weight; @@ -488,7 +491,7 @@ ccl_device void shader_merge_closures(ShaderData *sd) /* BSDF */ -ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderData *sd, const float3 omega_in, float *pdf, +ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, ShaderData *sd, const float3 omega_in, float *pdf, int skip_bsdf, BsdfEval *result_eval, float sum_pdf, float sum_sample_weight) { /* this is the veach one-sample model with balance heuristic, some pdf @@ -517,7 +520,7 @@ ccl_device_inline void _shader_bsdf_multi_eval(KernelGlobals *kg, const ShaderDa #ifdef __BRANCHED_PATH__ ccl_device_inline void _shader_bsdf_multi_eval_branched(KernelGlobals *kg, - const ShaderData *sd, + ShaderData *sd, const float3 omega_in, BsdfEval *result_eval, float light_pdf, @@ -563,7 +566,7 @@ ccl_device void shader_bsdf_eval(KernelGlobals *kg, } } -ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample(KernelGlobals *kg, ShaderData *sd, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -620,7 +623,7 @@ ccl_device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd, return label; } -ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, const ShaderData *sd, +ccl_device int shader_bsdf_sample_closure(KernelGlobals *kg, ShaderData *sd, const ShaderClosure *sc, float randu, float randv, BsdfEval *bsdf_eval, float3 *omega_in, differential3 *domega_in, float *pdf) { @@ -824,7 +827,7 @@ ccl_device float3 shader_holdout_eval(KernelGlobals *kg, ShaderData *sd) /* Surface Evaluation */ -ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, +ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_addr_space RNG *rng, ccl_addr_space PathState *state, float randb, int path_flag, ShaderContext ctx) { ccl_fetch(sd, num_closure) = 0; @@ -846,6 +849,10 @@ ccl_device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd, ccl_fetch(sd, flag) |= bsdf_diffuse_setup(ccl_fetch_array(sd, closure, 0)); #endif } + + if(rng && (ccl_fetch(sd, flag) & SD_BSDF_NEEDS_LCG)) { + ccl_fetch(sd, lcg_state) = lcg_state_init_addrspace(rng, state, 0xb4bc3953); + } } /* Background Evaluation */ diff --git a/intern/cycles/kernel/kernel_shadow.h b/intern/cycles/kernel/kernel_shadow.h index 1abbbb2ddad..d1576754d2e 100644 --- a/intern/cycles/kernel/kernel_shadow.h +++ b/intern/cycles/kernel/kernel_shadow.h @@ -75,7 +75,12 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, } uint num_hits; - blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + if(max_hits == 0) { + blocked = true; + num_hits = 0; + } else { + blocked = scene_intersect_shadow_all(kg, ray, hits, max_hits, &num_hits); + } /* if no opaque surface found but we did find transparent hits, shade them */ if(!blocked && num_hits > 0) { @@ -117,7 +122,7 @@ ccl_device_inline bool shadow_blocked(KernelGlobals *kg, ShaderData *shadow_sd, /* attenuation from transparent surface */ if(!(shadow_sd->flag & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); @@ -252,7 +257,7 @@ ccl_device_noinline bool shadow_blocked(KernelGlobals *kg, /* attenuation from transparent surface */ if(!(ccl_fetch(shadow_sd, flag) & SD_HAS_ONLY_VOLUME)) { path_state_modify_bounce(state, true); - shader_eval_surface(kg, shadow_sd, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); + shader_eval_surface(kg, shadow_sd, NULL, state, 0.0f, PATH_RAY_SHADOW, SHADER_CONTEXT_SHADOW); path_state_modify_bounce(state, false); throughput *= shader_bsdf_transparency(kg, shadow_sd); diff --git a/intern/cycles/kernel/kernel_subsurface.h b/intern/cycles/kernel/kernel_subsurface.h index 705b57ba6ff..b048bd38fc9 100644 --- a/intern/cycles/kernel/kernel_subsurface.h +++ b/intern/cycles/kernel/kernel_subsurface.h @@ -198,7 +198,7 @@ ccl_device void subsurface_color_bump_blur(KernelGlobals *kg, if(bump || texture_blur > 0.0f) { /* average color and normal at incoming point */ - shader_eval_surface(kg, sd, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); + shader_eval_surface(kg, sd, NULL, state, 0.0f, state_flag, SHADER_CONTEXT_SSS); float3 in_color = shader_bssrdf_sum(sd, (bump)? N: NULL, NULL); /* we simply divide out the average color and multiply with the average diff --git a/intern/cycles/kernel/kernel_textures.h b/intern/cycles/kernel/kernel_textures.h index 245d236ff97..5ba262c1044 100644 --- a/intern/cycles/kernel/kernel_textures.h +++ b/intern/cycles/kernel/kernel_textures.h @@ -25,7 +25,8 @@ /* bvh */ KERNEL_TEX(float4, texture_float4, __bvh_nodes) KERNEL_TEX(float4, texture_float4, __bvh_leaf_nodes) -KERNEL_TEX(float4, texture_float4, __tri_storage) +KERNEL_TEX(float4, texture_float4, __prim_tri_verts) +KERNEL_TEX(uint, texture_uint, __prim_tri_index) KERNEL_TEX(uint, texture_uint, __prim_type) KERNEL_TEX(uint, texture_uint, __prim_visibility) KERNEL_TEX(uint, texture_uint, __prim_index) @@ -39,8 +40,7 @@ KERNEL_TEX(float4, texture_float4, __objects_vector) /* triangles */ KERNEL_TEX(uint, texture_uint, __tri_shader) KERNEL_TEX(float4, texture_float4, __tri_vnormal) -KERNEL_TEX(float4, texture_float4, __tri_vindex) -KERNEL_TEX(float4, texture_float4, __tri_verts) +KERNEL_TEX(uint4, texture_uint4, __tri_vindex) /* curves */ KERNEL_TEX(float4, texture_float4, __curves) diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h index aa5eeebda7b..a9be2ae717a 100644 --- a/intern/cycles/kernel/kernel_types.h +++ b/intern/cycles/kernel/kernel_types.h @@ -292,11 +292,14 @@ enum PathRayFlag { PATH_RAY_CURVE = 512, /* visibility flag to define curve segments */ PATH_RAY_VOLUME_SCATTER = 1024, /* volume scattering */ - PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024), + /* Special flag to tag unaligned BVH nodes. */ + PATH_RAY_NODE_UNALIGNED = 2048, - PATH_RAY_MIS_SKIP = 2048, - PATH_RAY_DIFFUSE_ANCESTOR = 4096, - PATH_RAY_SINGLE_PASS_DONE = 8192, + PATH_RAY_ALL_VISIBILITY = (1|2|4|8|16|32|64|128|256|512|1024|2048), + + PATH_RAY_MIS_SKIP = 4096, + PATH_RAY_DIFFUSE_ANCESTOR = 8192, + PATH_RAY_SINGLE_PASS_DONE = 16384, }; /* Closure Label */ @@ -384,12 +387,13 @@ typedef enum BakePassFilterCombos { BAKE_FILTER_SUBSURFACE_INDIRECT = (BAKE_FILTER_INDIRECT | BAKE_FILTER_SUBSURFACE), } BakePassFilterCombos; -#ifdef __PASSES__ - typedef ccl_addr_space struct PathRadiance { +#ifdef __PASSES__ int use_light_pass; +#endif float3 emission; +#ifdef __PASSES__ float3 background; float3 ao; @@ -423,25 +427,23 @@ typedef ccl_addr_space struct PathRadiance { float4 shadow; float mist; +#endif } PathRadiance; typedef struct BsdfEval { +#ifdef __PASSES__ int use_light_pass; +#endif float3 diffuse; +#ifdef __PASSES__ float3 glossy; float3 transmission; float3 transparent; float3 subsurface; float3 scatter; -} BsdfEval; - -#else - -typedef ccl_addr_space float3 PathRadiance; -typedef float3 BsdfEval; - #endif +} BsdfEval; /* Shader Flag */ @@ -679,31 +681,34 @@ typedef enum ShaderContext { enum ShaderDataFlag { /* runtime flags */ - SD_BACKFACING = (1 << 0), /* backside of surface? */ - SD_EMISSION = (1 << 1), /* have emissive closure? */ - SD_BSDF = (1 << 2), /* have bsdf closure? */ - SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ - SD_BSSRDF = (1 << 4), /* have bssrdf */ - SD_HOLDOUT = (1 << 5), /* have holdout closure? */ - SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ - SD_SCATTER = (1 << 7), /* have volume phase closure? */ - SD_AO = (1 << 8), /* have ao closure? */ - SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BACKFACING = (1 << 0), /* backside of surface? */ + SD_EMISSION = (1 << 1), /* have emissive closure? */ + SD_BSDF = (1 << 2), /* have bsdf closure? */ + SD_BSDF_HAS_EVAL = (1 << 3), /* have non-singular bsdf closure? */ + SD_BSSRDF = (1 << 4), /* have bssrdf */ + SD_HOLDOUT = (1 << 5), /* have holdout closure? */ + SD_ABSORPTION = (1 << 6), /* have volume absorption closure? */ + SD_SCATTER = (1 << 7), /* have volume phase closure? */ + SD_AO = (1 << 8), /* have ao closure? */ + SD_TRANSPARENT = (1 << 9), /* have transparent closure? */ + SD_BSDF_NEEDS_LCG = (1 << 10), + SD_BSDF_HAS_CUSTOM = (1 << 11), /* are the custom variables relevant? */ SD_CLOSURE_FLAGS = (SD_EMISSION|SD_BSDF|SD_BSDF_HAS_EVAL|SD_BSSRDF| - SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO), + SD_HOLDOUT|SD_ABSORPTION|SD_SCATTER|SD_AO| + SD_BSDF_NEEDS_LCG|SD_BSDF_HAS_CUSTOM), /* shader flags */ - SD_USE_MIS = (1 << 10), /* direct light sample */ - SD_HAS_TRANSPARENT_SHADOW = (1 << 11), /* has transparent shadow */ - SD_HAS_VOLUME = (1 << 12), /* has volume shader */ - SD_HAS_ONLY_VOLUME = (1 << 13), /* has only volume shader, no surface */ - SD_HETEROGENEOUS_VOLUME = (1 << 14), /* has heterogeneous volume */ - SD_HAS_BSSRDF_BUMP = (1 << 15), /* bssrdf normal uses bump */ - SD_VOLUME_EQUIANGULAR = (1 << 16), /* use equiangular sampling */ - SD_VOLUME_MIS = (1 << 17), /* use multiple importance sampling */ - SD_VOLUME_CUBIC = (1 << 18), /* use cubic interpolation for voxels */ - SD_HAS_BUMP = (1 << 19), /* has data connected to the displacement input */ + SD_USE_MIS = (1 << 12), /* direct light sample */ + SD_HAS_TRANSPARENT_SHADOW = (1 << 13), /* has transparent shadow */ + SD_HAS_VOLUME = (1 << 14), /* has volume shader */ + SD_HAS_ONLY_VOLUME = (1 << 15), /* has only volume shader, no surface */ + SD_HETEROGENEOUS_VOLUME = (1 << 16), /* has heterogeneous volume */ + SD_HAS_BSSRDF_BUMP = (1 << 17), /* bssrdf normal uses bump */ + SD_VOLUME_EQUIANGULAR = (1 << 18), /* use equiangular sampling */ + SD_VOLUME_MIS = (1 << 19), /* use multiple importance sampling */ + SD_VOLUME_CUBIC = (1 << 20), /* use cubic interpolation for voxels */ + SD_HAS_BUMP = (1 << 21), /* has data connected to the displacement input */ SD_SHADER_FLAGS = (SD_USE_MIS|SD_HAS_TRANSPARENT_SHADOW|SD_HAS_VOLUME| SD_HAS_ONLY_VOLUME|SD_HETEROGENEOUS_VOLUME| @@ -711,13 +716,13 @@ enum ShaderDataFlag { SD_VOLUME_CUBIC|SD_HAS_BUMP), /* object flags */ - SD_HOLDOUT_MASK = (1 << 20), /* holdout for camera rays */ - SD_OBJECT_MOTION = (1 << 21), /* has object motion blur */ - SD_TRANSFORM_APPLIED = (1 << 22), /* vertices have transform applied */ - SD_NEGATIVE_SCALE_APPLIED = (1 << 23), /* vertices have negative scale applied */ - SD_OBJECT_HAS_VOLUME = (1 << 24), /* object has a volume shader */ - SD_OBJECT_INTERSECTS_VOLUME = (1 << 25), /* object intersects AABB of an object with volume shader */ - SD_OBJECT_HAS_VERTEX_MOTION = (1 << 26), /* has position for motion vertices */ + SD_HOLDOUT_MASK = (1 << 22), /* holdout for camera rays */ + SD_OBJECT_MOTION = (1 << 23), /* has object motion blur */ + SD_TRANSFORM_APPLIED = (1 << 24), /* vertices have transform applied */ + SD_NEGATIVE_SCALE_APPLIED = (1 << 25), /* vertices have negative scale applied */ + SD_OBJECT_HAS_VOLUME = (1 << 26), /* object has a volume shader */ + SD_OBJECT_INTERSECTS_VOLUME = (1 << 27), /* object intersects AABB of an object with volume shader */ + SD_OBJECT_HAS_VERTEX_MOTION = (1 << 28), /* has position for motion vertices */ SD_OBJECT_FLAGS = (SD_HOLDOUT_MASK|SD_OBJECT_MOTION|SD_TRANSFORM_APPLIED| SD_NEGATIVE_SCALE_APPLIED|SD_OBJECT_HAS_VOLUME| @@ -766,7 +771,7 @@ typedef ccl_addr_space struct ShaderData { int type; /* parametric coordinates - * - barycentric weights for triangles */ + * - barycentric weights for triangles */ float u; float v; /* object id if there is one, ~0 otherwise */ @@ -789,14 +794,14 @@ typedef ccl_addr_space struct ShaderData { #endif #ifdef __DPDU__ /* differential of P w.r.t. parametric coordinates. note that dPdu is - * not readily suitable as a tangent for shading on triangles. */ + * not readily suitable as a tangent for shading on triangles. */ float3 dPdu; float3 dPdv; #endif #ifdef __OBJECT_MOTION__ /* object <-> world space transformations, cached to avoid - * re-interpolating them constantly for shading */ + * re-interpolating them constantly for shading */ Transform ob_tfm; Transform ob_itfm; #endif @@ -806,6 +811,9 @@ typedef ccl_addr_space struct ShaderData { int num_closure; float randb_closure; + /* LCG state for closures that require additional random numbers. */ + uint lcg_state; + /* ray start position, only set for backgrounds */ float3 ray_P; differential3 ray_dP; @@ -1165,11 +1173,11 @@ typedef ccl_addr_space struct DebugData { #define QUEUE_EMPTY_SLOT -1 /* -* Queue 1 - Active rays -* Queue 2 - Background queue -* Queue 3 - Shadow ray cast kernel - AO -* Queeu 4 - Shadow ray cast kernel - direct lighting -*/ + * Queue 1 - Active rays + * Queue 2 - Background queue + * Queue 3 - Shadow ray cast kernel - AO + * Queeu 4 - Shadow ray cast kernel - direct lighting + */ #define NUM_QUEUES 4 /* Queue names */ diff --git a/intern/cycles/kernel/kernels/cpu/kernel.cpp b/intern/cycles/kernel/kernels/cpu/kernel.cpp index d8a83f69685..f11c85d5f6a 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel.cpp +++ b/intern/cycles/kernel/kernels/cpu/kernel.cpp @@ -154,6 +154,38 @@ void kernel_tex_copy(KernelGlobals *kg, tex->extension = extension; } } + else if(strstr(name, "__tex_image_half4")) { + texture_image_half4 *tex = NULL; + int id = atoi(name + strlen("__tex_image_half4_")); + int array_index = id - TEX_START_HALF4_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF4_CPU) { + tex = &kg->texture_half4_images[array_index]; + } + + if(tex) { + tex->data = (half4*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } + else if(strstr(name, "__tex_image_half")) { + texture_image_half *tex = NULL; + int id = atoi(name + strlen("__tex_image_half_")); + int array_index = id - TEX_START_HALF_CPU; + + if(array_index >= 0 && array_index < TEX_NUM_HALF_CPU) { + tex = &kg->texture_half_images[array_index]; + } + + if(tex) { + tex->data = (half*)mem; + tex->dimensions_set(width, height, depth); + tex->interpolation = interpolation; + tex->extension = extension; + } + } else assert(0); } diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h index b10861ab857..47383140170 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_image.h @@ -23,7 +23,11 @@ CCL_NAMESPACE_BEGIN ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float x, float y) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp(x, y); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp(x, y); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp(x, y); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp(x, y); @@ -35,7 +39,11 @@ ccl_device float4 kernel_tex_image_interp_impl(KernelGlobals *kg, int tex, float ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, float x, float y, float z) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half_images[tex - TEX_START_HALF_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF4_CPU].interp_3d(x, y, z); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d(x, y, z); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d(x, y, z); @@ -48,7 +56,11 @@ ccl_device float4 kernel_tex_image_interp_3d_impl(KernelGlobals *kg, int tex, fl ccl_device float4 kernel_tex_image_interp_3d_ex_impl(KernelGlobals *kg, int tex, float x, float y, float z, int interpolation) { - if(tex >= TEX_START_BYTE_CPU) + if(tex >= TEX_START_HALF_CPU) + return kg->texture_half4_images[tex - TEX_START_HALF_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_HALF4_CPU) + return kg->texture_half_images[tex - TEX_START_HALF4_CPU].interp_3d_ex(x, y, z, interpolation); + else if(tex >= TEX_START_BYTE_CPU) return kg->texture_byte_images[tex - TEX_START_BYTE_CPU].interp_3d_ex(x, y, z, interpolation); else if(tex >= TEX_START_FLOAT_CPU) return kg->texture_float_images[tex - TEX_START_FLOAT_CPU].interp_3d_ex(x, y, z, interpolation); diff --git a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h index 962196ccbdd..ec82d4b4c22 100644 --- a/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h +++ b/intern/cycles/kernel/kernels/cpu/kernel_cpu_impl.h @@ -109,6 +109,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, { if(type >= SHADER_EVAL_BAKE) { kernel_assert(output_luma == NULL); +#ifdef __BAKING__ kernel_bake_evaluate(kg, input, output, @@ -117,6 +118,7 @@ void KERNEL_FUNCTION_FULL_NAME(shader)(KernelGlobals *kg, i, offset, sample); +#endif } else { kernel_shader_evaluate(kg, diff --git a/intern/cycles/kernel/kernels/cuda/kernel.cu b/intern/cycles/kernel/kernels/cuda/kernel.cu index 37fae54faf0..eb2b6ea5414 100644 --- a/intern/cycles/kernel/kernels/cuda/kernel.cu +++ b/intern/cycles/kernel/kernels/cuda/kernel.cu @@ -77,8 +77,8 @@ # define CUDA_KERNEL_MAX_REGISTERS 63 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 -/* 5.0, 5.2 and 5.3 */ -#elif __CUDA_ARCH__ == 500 || __CUDA_ARCH__ == 520 || __CUDA_ARCH__ == 530 +/* 5.0, 5.2, 5.3, 6.0, 6.1 */ +#elif __CUDA_ARCH__ >= 500 # define CUDA_MULTIPRESSOR_MAX_REGISTERS 65536 # define CUDA_MULTIPROCESSOR_MAX_BLOCKS 32 # define CUDA_BLOCK_MAX_THREADS 1024 @@ -86,7 +86,7 @@ /* tunable parameters */ # define CUDA_THREADS_BLOCK_WIDTH 16 -# define CUDA_KERNEL_MAX_REGISTERS 40 +# define CUDA_KERNEL_MAX_REGISTERS 48 # define CUDA_KERNEL_BRANCHED_MAX_REGISTERS 63 /* unknown architecture */ diff --git a/intern/cycles/kernel/kernels/opencl/kernel.cl b/intern/cycles/kernel/kernels/opencl/kernel.cl index aad06ed5c76..37907cd8fdc 100644 --- a/intern/cycles/kernel/kernels/opencl/kernel.cl +++ b/intern/cycles/kernel/kernels/opencl/kernel.cl @@ -35,6 +35,7 @@ # include "../../kernel_montecarlo.h" # include "../../kernel_projection.h" # include "../../geom/geom.h" +# include "../../bvh/bvh.h" # include "../../kernel_accumulate.h" # include "../../kernel_camera.h" diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp index 95b8cea0922..02b1491489c 100644 --- a/intern/cycles/kernel/osl/osl_closures.cpp +++ b/intern/cycles/kernel/osl/osl_closures.cpp @@ -44,11 +44,13 @@ #include "kernel_compat_cpu.h" #include "kernel_globals.h" #include "kernel_montecarlo.h" +#include "kernel_random.h" #include "closure/bsdf_util.h" #include "closure/bsdf_ashikhmin_velvet.h" #include "closure/bsdf_diffuse.h" #include "closure/bsdf_microfacet.h" +#include "closure/bsdf_microfacet_multi.h" #include "closure/bsdf_oren_nayar.h" #include "closure/bsdf_reflection.h" #include "closure/bsdf_refraction.h" @@ -205,6 +207,12 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) bsdf_microfacet_ggx_aniso_params(), bsdf_microfacet_ggx_aniso_prepare); register_closure(ss, "microfacet_ggx_refraction", id++, bsdf_microfacet_ggx_refraction_params(), bsdf_microfacet_ggx_refraction_prepare); + register_closure(ss, "microfacet_multi_ggx", id++, + closure_bsdf_microfacet_multi_ggx_params(), closure_bsdf_microfacet_multi_ggx_prepare); + register_closure(ss, "microfacet_multi_ggx_glass", id++, + closure_bsdf_microfacet_multi_ggx_glass_params(), closure_bsdf_microfacet_multi_ggx_glass_prepare); + register_closure(ss, "microfacet_multi_ggx_aniso", id++, + closure_bsdf_microfacet_multi_ggx_aniso_params(), closure_bsdf_microfacet_multi_ggx_aniso_prepare); register_closure(ss, "microfacet_beckmann", id++, bsdf_microfacet_beckmann_params(), bsdf_microfacet_beckmann_prepare); register_closure(ss, "microfacet_beckmann_aniso", id++, @@ -250,5 +258,127 @@ void OSLShader::register_closures(OSLShadingSystem *ss_) volume_absorption_params(), volume_absorption_prepare); } +/* Multiscattering GGX closures */ + +class MicrofacetMultiClosure : public CBSDFClosure { +public: + float3 color; + + /* Technically, the MultiGGX Glass closure may also transmit. + * However, since this is set statically and only used for caustic flags, this is probably as good as it gets. */ + MicrofacetMultiClosure() : CBSDFClosure(LABEL_GLOSSY|LABEL_REFLECT) + { + } + + void setup() + { + sc.prim = NULL; + sc.custom1 = color.x; + sc.custom2 = color.y; + sc.custom3 = color.z; + } + + void blur(float roughness) + { + } + + float3 eval_reflect(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + float3 eval_transmit(const float3 &omega_out, const float3 &omega_in, float& pdf) const + { + pdf = 0.0f; + return make_float3(0.0f, 0.0f, 0.0f); + } + + int sample(const float3 &Ng, + const float3 &omega_out, const float3 &domega_out_dx, const float3 &domega_out_dy, + float randu, float randv, + float3 &omega_in, float3 &domega_in_dx, float3 &domega_in_dy, + float &pdf, float3 &eval) const + { + pdf = 0; + return LABEL_NONE; + } +}; + +class MicrofacetMultiGGXClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_prepare, MicrofacetMultiGGXClosure); + +class MicrofacetMultiGGXAnisoClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXAnisoClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_aniso_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.T), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data1), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_aniso_prepare, MicrofacetMultiGGXAnisoClosure); + +class MicrofacetMultiGGXGlassClosure : public MicrofacetMultiClosure { +public: + MicrofacetMultiGGXGlassClosure() : MicrofacetMultiClosure() {} + + void setup() + { + MicrofacetMultiClosure::setup(); + m_shaderdata_flag = bsdf_microfacet_multi_ggx_glass_setup(&sc); + } +}; + +ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params() +{ + static ClosureParam params[] = { + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, sc.N), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data0), + CLOSURE_FLOAT_PARAM(MicrofacetMultiGGXClosure, sc.data2), + CLOSURE_FLOAT3_PARAM(MicrofacetMultiGGXClosure, color), + CLOSURE_STRING_KEYPARAM(MicrofacetMultiGGXClosure, label, "label"), + CLOSURE_FINISH_PARAM(MicrofacetMultiGGXClosure) + }; + return params; +} +CCLOSURE_PREPARE(closure_bsdf_microfacet_multi_ggx_glass_prepare, MicrofacetMultiGGXGlassClosure); + CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h index 1578d06cd56..c5a1a29b6af 100644 --- a/intern/cycles/kernel/osl/osl_closures.h +++ b/intern/cycles/kernel/osl/osl_closures.h @@ -52,6 +52,9 @@ OSL::ClosureParam *closure_bssrdf_cubic_params(); OSL::ClosureParam *closure_bssrdf_gaussian_params(); OSL::ClosureParam *closure_bssrdf_burley_params(); OSL::ClosureParam *closure_henyey_greenstein_volume_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_glass_params(); +OSL::ClosureParam *closure_bsdf_microfacet_multi_ggx_aniso_params(); void closure_emission_prepare(OSL::RendererServices *, int id, void *data); void closure_background_prepare(OSL::RendererServices *, int id, void *data); @@ -63,6 +66,9 @@ void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_gaussian_prepare(OSL::RendererServices *, int id, void *data); void closure_bssrdf_burley_prepare(OSL::RendererServices *, int id, void *data); void closure_henyey_greenstein_volume_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_glass_prepare(OSL::RendererServices *, int id, void *data); +void closure_bsdf_microfacet_multi_ggx_aniso_prepare(OSL::RendererServices *, int id, void *data); #define CCLOSURE_PREPARE(name, classname) \ void name(RendererServices *, int id, void *data) \ diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp index ebe739ebd0e..2bb2be5e6b3 100644 --- a/intern/cycles/kernel/osl/osl_services.cpp +++ b/intern/cycles/kernel/osl/osl_services.cpp @@ -47,6 +47,7 @@ #include "kernel_camera.h" #include "kernels/cpu/kernel_cpu_image.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_projection.h" #include "kernel_accumulate.h" @@ -912,7 +913,7 @@ bool OSLRenderServices::texture(ustring filename, #endif bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp(slot, s, 1.0f - t); @@ -993,7 +994,7 @@ bool OSLRenderServices::texture3d(ustring filename, } bool status; - if(filename[0] == '@') { + if(filename.length() && filename[0] == '@') { int slot = atoi(filename.c_str() + 1); float4 rgba = kernel_tex_image_interp_3d(slot, P.x, P.y, P.z); diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp index f58368e6789..6cde7419e10 100644 --- a/intern/cycles/kernel/osl/osl_shader.cpp +++ b/intern/cycles/kernel/osl/osl_shader.cpp @@ -177,6 +177,7 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, case CClosurePrimitive::BSDF: { CBSDFClosure *bsdf = (CBSDFClosure *)prim; int scattering = bsdf->scattering(); + int shaderdata_flag = bsdf->shaderdata_flag(); /* caustic options */ if((scattering & LABEL_GLOSSY) && (path_flag & PATH_RAY_DIFFUSE)) { @@ -201,11 +202,16 @@ static void flatten_surface_closure_tree(ShaderData *sd, int path_flag, sc.data1 = bsdf->sc.data1; sc.data2 = bsdf->sc.data2; sc.prim = bsdf->sc.prim; + if(shaderdata_flag & SD_BSDF_HAS_CUSTOM) { + sc.custom1 = bsdf->sc.custom1; + sc.custom2 = bsdf->sc.custom2; + sc.custom3 = bsdf->sc.custom3; + } /* add */ if(sc.sample_weight > CLOSURE_WEIGHT_CUTOFF && sd->num_closure < MAX_CLOSURE) { sd->closure[sd->num_closure++] = sc; - sd->flag |= bsdf->shaderdata_flag(); + sd->flag |= shaderdata_flag; } break; } diff --git a/intern/cycles/kernel/shaders/CMakeLists.txt b/intern/cycles/kernel/shaders/CMakeLists.txt index 49030f33c26..b43f8402d42 100644 --- a/intern/cycles/kernel/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/shaders/CMakeLists.txt @@ -81,6 +81,7 @@ set(SRC_OSL node_wireframe.osl node_hair_bsdf.osl node_uv_map.osl + node_rgb_to_bw.osl ) set(SRC_OSL_HEADERS diff --git a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl index f7f89543aa9..bef6d7e8809 100644 --- a/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_anisotropic_bsdf.osl @@ -51,6 +51,8 @@ shader node_anisotropic_bsdf( BSDF = Color * microfacet_beckmann_aniso(Normal, T, RoughnessU, RoughnessV); else if (distribution == "GGX") BSDF = Color * microfacet_ggx_aniso(Normal, T, RoughnessU, RoughnessV); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_aniso(Normal, T, RoughnessU, RoughnessV, Color); else BSDF = Color * ashikhmin_shirley(Normal, T, RoughnessU, RoughnessV); } diff --git a/intern/cycles/kernel/shaders/node_glass_bsdf.osl b/intern/cycles/kernel/shaders/node_glass_bsdf.osl index 8fd0a2fd714..a9723a8300a 100644 --- a/intern/cycles/kernel/shaders/node_glass_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glass_bsdf.osl @@ -35,6 +35,8 @@ shader node_glass_bsdf( else if (distribution == "beckmann") BSDF = Color * (Fr * microfacet_beckmann(Normal, Roughness) + (1.0 - Fr) * microfacet_beckmann_refraction(Normal, Roughness, eta)); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx_glass(Normal, Roughness, eta, Color); else if (distribution == "GGX") BSDF = Color * (Fr * microfacet_ggx(Normal, Roughness) + (1.0 - Fr) * microfacet_ggx_refraction(Normal, Roughness, eta)); diff --git a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl index cc2a66fd46a..f4ea7e7dc6a 100644 --- a/intern/cycles/kernel/shaders/node_glossy_bsdf.osl +++ b/intern/cycles/kernel/shaders/node_glossy_bsdf.osl @@ -30,6 +30,8 @@ shader node_glossy_bsdf( BSDF = Color * microfacet_beckmann(Normal, Roughness); else if (distribution == "GGX") BSDF = Color * microfacet_ggx(Normal, Roughness); + else if (distribution == "Multiscatter GGX") + BSDF = Color * microfacet_multi_ggx(Normal, Roughness, Color); else BSDF = Color * ashikhmin_shirley(Normal, vector(0, 0, 0), Roughness, Roughness); diff --git a/intern/cycles/kernel/shaders/node_image_texture.osl b/intern/cycles/kernel/shaders/node_image_texture.osl index a00401845c8..7cd2922dd4f 100644 --- a/intern/cycles/kernel/shaders/node_image_texture.osl +++ b/intern/cycles/kernel/shaders/node_image_texture.osl @@ -88,7 +88,7 @@ shader node_image_texture( string color_space = "sRGB", string projection = "flat", string interpolation = "smartcubic", - string wrap = "periodic", + string extension = "periodic", float projection_blend = 0.0, int is_float = 1, int use_alpha = 1, @@ -108,7 +108,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } else if (projection == "box") { /* object space normal */ @@ -184,7 +184,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[0] * tmp_alpha; } if (weight[1] > 0.0) { @@ -195,7 +195,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[1] * tmp_alpha; } if (weight[2] > 0.0) { @@ -206,7 +206,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); Alpha += weight[2] * tmp_alpha; } } @@ -219,7 +219,7 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } else if (projection == "tube") { point projected = map_to_tube(texco_remap_square(p)); @@ -230,6 +230,6 @@ shader node_image_texture( use_alpha, is_float, interpolation, - wrap); + extension); } } diff --git a/intern/cycles/kernel/shaders/node_rgb_to_bw.osl b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl new file mode 100644 index 00000000000..903dfcdc881 --- /dev/null +++ b/intern/cycles/kernel/shaders/node_rgb_to_bw.osl @@ -0,0 +1,25 @@ +/* + * 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. + */ + +#include "stdosl.h" + +shader node_rgb_to_bw( + color Color = 0.0, + output float Val = 0.0) +{ + Val = Color[0] * 0.2126 + Color[1] * 0.7152 + Color[2] * 0.0722; +} + diff --git a/intern/cycles/kernel/shaders/stdosl.h b/intern/cycles/kernel/shaders/stdosl.h index 8d5d3746caf..a8dda8a12c9 100644 --- a/intern/cycles/kernel/shaders/stdosl.h +++ b/intern/cycles/kernel/shaders/stdosl.h @@ -527,6 +527,9 @@ closure color transparent() BUILTIN; closure color microfacet_ggx(normal N, float ag) BUILTIN; closure color microfacet_ggx_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN; +closure color microfacet_multi_ggx(normal N, float ag, color C) BUILTIN; +closure color microfacet_multi_ggx_aniso(normal N, vector T, float ax, float ay, color C) BUILTIN; +closure color microfacet_multi_ggx_glass(normal N, float ag, float eta, color C) BUILTIN; closure color microfacet_beckmann(normal N, float ab) BUILTIN; closure color microfacet_beckmann_aniso(normal N, vector T, float ax, float ay) BUILTIN; closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN; diff --git a/intern/cycles/kernel/split/kernel_shader_eval.h b/intern/cycles/kernel/split/kernel_shader_eval.h index e816a818915..cef64bf5f36 100644 --- a/intern/cycles/kernel/split/kernel_shader_eval.h +++ b/intern/cycles/kernel/split/kernel_shader_eval.h @@ -65,6 +65,6 @@ ccl_device void kernel_shader_eval( isect, &ray); float rbsdf = path_state_rng_1D_for_decision(kg, rng, state, PRNG_BSDF); - shader_eval_surface(kg, sd, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); + shader_eval_surface(kg, sd, rng, state, rbsdf, state->flag, SHADER_CONTEXT_MAIN); } } diff --git a/intern/cycles/kernel/split/kernel_split_common.h b/intern/cycles/kernel/split/kernel_split_common.h index e1c7e2cea99..88d6dab04d0 100644 --- a/intern/cycles/kernel/split/kernel_split_common.h +++ b/intern/cycles/kernel/split/kernel_split_common.h @@ -31,6 +31,7 @@ #include "kernel_camera.h" #include "geom/geom.h" +#include "bvh/bvh.h" #include "kernel_accumulate.h" #include "kernel_shader.h" diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index 543e31bcb35..de7e03e5a19 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -142,6 +142,7 @@ CCL_NAMESPACE_END #include "svm_noise.h" #include "svm_texture.h" +#include "svm_color_util.h" #include "svm_math_util.h" #include "svm_attribute.h" diff --git a/intern/cycles/kernel/svm/svm_brightness.h b/intern/cycles/kernel/svm/svm_brightness.h index e4d545a00ae..d71b0ee0b61 100644 --- a/intern/cycles/kernel/svm/svm_brightness.h +++ b/intern/cycles/kernel/svm/svm_brightness.h @@ -25,12 +25,7 @@ ccl_device void svm_node_brightness(ShaderData *sd, float *stack, uint in_color, float brightness = stack_load_float(stack, bright_offset); float contrast = stack_load_float(stack, contrast_offset); - float a = 1.0f + contrast; - float b = brightness - contrast*0.5f; - - color.x = max(a*color.x + b, 0.0f); - color.y = max(a*color.y + b, 0.0f); - color.z = max(a*color.z + b, 0.0f); + color = svm_brightness_contrast(color, brightness, contrast); if(stack_valid(out_color)) stack_store_float3(stack, out_color, color); diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h index 65512a0105c..fae89aade60 100644 --- a/intern/cycles/kernel/svm/svm_closure.h +++ b/intern/cycles/kernel/svm/svm_closure.h @@ -186,7 +186,8 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * case CLOSURE_BSDF_REFLECTION_ID: case CLOSURE_BSDF_MICROFACET_GGX_ID: case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: - case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: { + case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) break; @@ -206,6 +207,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) { + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_setup(sc); } @@ -307,8 +316,36 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * break; } + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID: { +#ifdef __CAUSTICS_TRICKS__ + if(!kernel_data.integrator.caustics_reflective && !kernel_data.integrator.caustics_refractive && (path_flag & PATH_RAY_DIFFUSE)) + break; +#endif + ShaderClosure *sc = svm_node_closure_get_bsdf(sd, mix_weight); + + if(sc) { + sc->N = N; + + sc->data0 = param1; + sc->data1 = param1; + float eta = fmaxf(param2, 1e-5f); + sc->data2 = (ccl_fetch(sd, flag) & SD_BACKFACING)? 1.0f/eta: eta; + + kernel_assert(stack_valid(data_node.z)); + float3 color = stack_load_float3(stack, data_node.z); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + + /* setup bsdf */ + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_glass_setup(sc); + } + + break; + } case CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID: case CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID: + case CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID: case CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID: { #ifdef __CAUSTICS_TRICKS__ if(!kernel_data.integrator.caustics_reflective && (path_flag & PATH_RAY_DIFFUSE)) @@ -346,6 +383,14 @@ ccl_device void svm_node_closure_bsdf(KernelGlobals *kg, ShaderData *sd, float * ccl_fetch(sd, flag) |= bsdf_microfacet_beckmann_aniso_setup(sc); else if(type == CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID) ccl_fetch(sd, flag) |= bsdf_microfacet_ggx_aniso_setup(sc); + else if(type == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) { + kernel_assert(stack_valid(data_node.w)); + float3 color = stack_load_float3(stack, data_node.w); + sc->custom1 = color.x; + sc->custom2 = color.y; + sc->custom3 = color.z; + ccl_fetch(sd, flag) |= bsdf_microfacet_multi_ggx_aniso_setup(sc); + } else ccl_fetch(sd, flag) |= bsdf_ashikhmin_shirley_aniso_setup(sc); } diff --git a/intern/cycles/kernel/svm/svm_color_util.h b/intern/cycles/kernel/svm/svm_color_util.h new file mode 100644 index 00000000000..258cdeb630e --- /dev/null +++ b/intern/cycles/kernel/svm/svm_color_util.h @@ -0,0 +1,306 @@ +/* + * 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. + */ + +CCL_NAMESPACE_BEGIN + +ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) +{ + return interp(col1, col2, t); +} + +ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 + col2, t); +} + +ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 * col2, t); +} + +ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 tm3 = make_float3(tm, tm, tm); + + return one - (tm3 + t*(one - col2))*(one - col1); +} + +ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(outcol.x < 0.5f) + outcol.x *= tm + 2.0f*t*col2.x; + else + outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); + + if(outcol.y < 0.5f) + outcol.y *= tm + 2.0f*t*col2.y; + else + outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); + + if(outcol.z < 0.5f) + outcol.z *= tm + 2.0f*t*col2.z; + else + outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); + + return outcol; +} + +ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) +{ + return interp(col1, col1 - col2, t); +} + +ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; + if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; + if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; + + return outcol; +} + +ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) +{ + return interp(col1, fabs(col1 - col2), t); +} + +ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) +{ + return min(col1, col2)*t + col1*(1.0f - t); +} + +ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) +{ + return max(col1, col2*t); +} + +ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + if(outcol.x != 0.0f) { + float tmp = 1.0f - t*col2.x; + if(tmp <= 0.0f) + outcol.x = 1.0f; + else if((tmp = outcol.x/tmp) > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + } + if(outcol.y != 0.0f) { + float tmp = 1.0f - t*col2.y; + if(tmp <= 0.0f) + outcol.y = 1.0f; + else if((tmp = outcol.y/tmp) > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + } + if(outcol.z != 0.0f) { + float tmp = 1.0f - t*col2.z; + if(tmp <= 0.0f) + outcol.z = 1.0f; + else if((tmp = outcol.z/tmp) > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + } + + return outcol; +} + +ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) +{ + float tmp, tm = 1.0f - t; + + float3 outcol = col1; + + tmp = tm + t*col2.x; + if(tmp <= 0.0f) + outcol.x = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) + outcol.x = 0.0f; + else if(tmp > 1.0f) + outcol.x = 1.0f; + else + outcol.x = tmp; + + tmp = tm + t*col2.y; + if(tmp <= 0.0f) + outcol.y = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) + outcol.y = 0.0f; + else if(tmp > 1.0f) + outcol.y = 1.0f; + else + outcol.y = tmp; + + tmp = tm + t*col2.z; + if(tmp <= 0.0f) + outcol.z = 0.0f; + else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) + outcol.z = 0.0f; + else if(tmp > 1.0f) + outcol.z = 1.0f; + else + outcol.z = tmp; + + return outcol; +} + +ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 outcol = col1; + + float3 hsv = rgb_to_hsv(outcol); + + if(hsv.y != 0.0f) { + float3 hsv2 = rgb_to_hsv(col2); + + hsv.y = tm*hsv.y + t*hsv2.y; + outcol = hsv_to_rgb(hsv); + } + + return outcol; +} + +ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 hsv = rgb_to_hsv(col1); + float3 hsv2 = rgb_to_hsv(col2); + + hsv.z = tm*hsv.z + t*hsv2.z; + + return hsv_to_rgb(hsv); +} + +ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) +{ + float3 outcol = col1; + float3 hsv2 = rgb_to_hsv(col2); + + if(hsv2.y != 0.0f) { + float3 hsv = rgb_to_hsv(outcol); + hsv.x = hsv2.x; + hsv.y = hsv2.y; + float3 tmp = hsv_to_rgb(hsv); + + outcol = interp(outcol, tmp, t); + } + + return outcol; +} + +ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) +{ + float tm = 1.0f - t; + + float3 one = make_float3(1.0f, 1.0f, 1.0f); + float3 scr = one - (one - col2)*(one - col1); + + return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); +} + +ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) +{ + return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); +} + +ccl_device float3 svm_mix_clamp(float3 col) +{ + float3 outcol = col; + + outcol.x = saturate(col.x); + outcol.y = saturate(col.y); + outcol.z = saturate(col.z); + + return outcol; +} + +ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) +{ + float t = saturate(fac); + + switch(type) { + case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); + case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); + case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); + case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); + case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); + case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); + case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); + case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); + case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); + case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); + case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); + case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); + case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); + case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); + case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); + case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); + case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); + case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); + case NODE_MIX_CLAMP: return svm_mix_clamp(c1); + } + + return make_float3(0.0f, 0.0f, 0.0f); +} + +ccl_device_inline float3 svm_brightness_contrast(float3 color, float brightness, float contrast) +{ + float a = 1.0f + contrast; + float b = brightness - contrast*0.5f; + + color.x = max(a*color.x + b, 0.0f); + color.y = max(a*color.y + b, 0.0f); + color.z = max(a*color.z + b, 0.0f); + + return color; +} + +CCL_NAMESPACE_END + diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h index 3d9ab405849..44732734c31 100644 --- a/intern/cycles/kernel/svm/svm_image.h +++ b/intern/cycles/kernel/svm/svm_image.h @@ -72,8 +72,16 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, uint width = info.x; uint height = info.y; uint offset = info.z; - uint periodic = (info.w & 0x1); - uint interpolation = info.w >> 1; + + /* Image Options */ + uint interpolation = (info.w & (1 << 0)) ? INTERPOLATION_CLOSEST : INTERPOLATION_LINEAR; + uint extension; + if(info.w & (1 << 1)) + extension = EXTENSION_REPEAT; + else if(info.w & (1 << 2)) + extension = EXTENSION_EXTEND; + else + extension = EXTENSION_CLIP; float4 r; int ix, iy, nix, niy; @@ -81,22 +89,26 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, svm_image_texture_frac(x*width, &ix); svm_image_texture_frac(y*height, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); } - else { + else if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + else { /* EXTENSION_EXTEND */ ix = svm_image_texture_wrap_clamp(ix, width); iy = svm_image_texture_wrap_clamp(iy, height); - } + r = svm_image_texture_read(kg, id, offset + ix + iy*width); } - else { /* We default to linear interpolation if it is not closest */ - float tx = svm_image_texture_frac(x*width, &ix); - float ty = svm_image_texture_frac(y*height, &iy); + else { /* INTERPOLATION_LINEAR */ + float tx = svm_image_texture_frac(x*width - 0.5f, &ix); + float ty = svm_image_texture_frac(y*height - 0.5f, &iy); - if(periodic) { + if(extension == EXTENSION_REPEAT) { ix = svm_image_texture_wrap_periodic(ix, width); iy = svm_image_texture_wrap_periodic(iy, height); @@ -104,14 +116,17 @@ ccl_device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y, niy = svm_image_texture_wrap_periodic(iy+1, height); } else { - ix = svm_image_texture_wrap_clamp(ix, width); - iy = svm_image_texture_wrap_clamp(iy, height); - + if(extension == EXTENSION_CLIP) { + if(x < 0.0f || y < 0.0f || x > 1.0f || y > 1.0f) { + return make_float4(0.0f, 0.0f, 0.0f, 0.0f); + } + } nix = svm_image_texture_wrap_clamp(ix+1, width); niy = svm_image_texture_wrap_clamp(iy+1, height); + ix = svm_image_texture_wrap_clamp(ix, width); + iy = svm_image_texture_wrap_clamp(iy, height); } - r = (1.0f - ty)*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + iy*width); r += (1.0f - ty)*tx*svm_image_texture_read(kg, id, offset + nix + iy*width); r += ty*(1.0f - tx)*svm_image_texture_read(kg, id, offset + ix + niy*width); diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h index 7cbda111d81..022a68d1928 100644 --- a/intern/cycles/kernel/svm/svm_mix.h +++ b/intern/cycles/kernel/svm/svm_mix.h @@ -16,280 +16,6 @@ CCL_NAMESPACE_BEGIN -ccl_device float3 svm_mix_blend(float t, float3 col1, float3 col2) -{ - return interp(col1, col2, t); -} - -ccl_device float3 svm_mix_add(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 + col2, t); -} - -ccl_device float3 svm_mix_mul(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 * col2, t); -} - -ccl_device float3 svm_mix_screen(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 tm3 = make_float3(tm, tm, tm); - - return one - (tm3 + t*(one - col2))*(one - col1); -} - -ccl_device float3 svm_mix_overlay(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(outcol.x < 0.5f) - outcol.x *= tm + 2.0f*t*col2.x; - else - outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x); - - if(outcol.y < 0.5f) - outcol.y *= tm + 2.0f*t*col2.y; - else - outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y); - - if(outcol.z < 0.5f) - outcol.z *= tm + 2.0f*t*col2.z; - else - outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z); - - return outcol; -} - -ccl_device float3 svm_mix_sub(float t, float3 col1, float3 col2) -{ - return interp(col1, col1 - col2, t); -} - -ccl_device float3 svm_mix_div(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x; - if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y; - if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z; - - return outcol; -} - -ccl_device float3 svm_mix_diff(float t, float3 col1, float3 col2) -{ - return interp(col1, fabs(col1 - col2), t); -} - -ccl_device float3 svm_mix_dark(float t, float3 col1, float3 col2) -{ - return min(col1, col2)*t + col1*(1.0f - t); -} - -ccl_device float3 svm_mix_light(float t, float3 col1, float3 col2) -{ - return max(col1, col2*t); -} - -ccl_device float3 svm_mix_dodge(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - if(outcol.x != 0.0f) { - float tmp = 1.0f - t*col2.x; - if(tmp <= 0.0f) - outcol.x = 1.0f; - else if((tmp = outcol.x/tmp) > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - } - if(outcol.y != 0.0f) { - float tmp = 1.0f - t*col2.y; - if(tmp <= 0.0f) - outcol.y = 1.0f; - else if((tmp = outcol.y/tmp) > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - } - if(outcol.z != 0.0f) { - float tmp = 1.0f - t*col2.z; - if(tmp <= 0.0f) - outcol.z = 1.0f; - else if((tmp = outcol.z/tmp) > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - } - - return outcol; -} - -ccl_device float3 svm_mix_burn(float t, float3 col1, float3 col2) -{ - float tmp, tm = 1.0f - t; - - float3 outcol = col1; - - tmp = tm + t*col2.x; - if(tmp <= 0.0f) - outcol.x = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f) - outcol.x = 0.0f; - else if(tmp > 1.0f) - outcol.x = 1.0f; - else - outcol.x = tmp; - - tmp = tm + t*col2.y; - if(tmp <= 0.0f) - outcol.y = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f) - outcol.y = 0.0f; - else if(tmp > 1.0f) - outcol.y = 1.0f; - else - outcol.y = tmp; - - tmp = tm + t*col2.z; - if(tmp <= 0.0f) - outcol.z = 0.0f; - else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f) - outcol.z = 0.0f; - else if(tmp > 1.0f) - outcol.z = 1.0f; - else - outcol.z = tmp; - - return outcol; -} - -ccl_device float3 svm_mix_hue(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_sat(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 outcol = col1; - - float3 hsv = rgb_to_hsv(outcol); - - if(hsv.y != 0.0f) { - float3 hsv2 = rgb_to_hsv(col2); - - hsv.y = tm*hsv.y + t*hsv2.y; - outcol = hsv_to_rgb(hsv); - } - - return outcol; -} - -ccl_device float3 svm_mix_val(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 hsv = rgb_to_hsv(col1); - float3 hsv2 = rgb_to_hsv(col2); - - hsv.z = tm*hsv.z + t*hsv2.z; - - return hsv_to_rgb(hsv); -} - -ccl_device float3 svm_mix_color(float t, float3 col1, float3 col2) -{ - float3 outcol = col1; - float3 hsv2 = rgb_to_hsv(col2); - - if(hsv2.y != 0.0f) { - float3 hsv = rgb_to_hsv(outcol); - hsv.x = hsv2.x; - hsv.y = hsv2.y; - float3 tmp = hsv_to_rgb(hsv); - - outcol = interp(outcol, tmp, t); - } - - return outcol; -} - -ccl_device float3 svm_mix_soft(float t, float3 col1, float3 col2) -{ - float tm = 1.0f - t; - - float3 one = make_float3(1.0f, 1.0f, 1.0f); - float3 scr = one - (one - col2)*(one - col1); - - return tm*col1 + t*((one - col1)*col2*col1 + col1*scr); -} - -ccl_device float3 svm_mix_linear(float t, float3 col1, float3 col2) -{ - return col1 + t*(2.0f*col2 + make_float3(-1.0f, -1.0f, -1.0f)); -} - -ccl_device float3 svm_mix_clamp(float3 col) -{ - float3 outcol = col; - - outcol.x = saturate(col.x); - outcol.y = saturate(col.y); - outcol.z = saturate(col.z); - - return outcol; -} - -ccl_device_noinline float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2) -{ - float t = saturate(fac); - - switch(type) { - case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2); - case NODE_MIX_ADD: return svm_mix_add(t, c1, c2); - case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2); - case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2); - case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2); - case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2); - case NODE_MIX_DIV: return svm_mix_div(t, c1, c2); - case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2); - case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2); - case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2); - case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2); - case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2); - case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2); - case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2); - case NODE_MIX_VAL: return svm_mix_val (t, c1, c2); - case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2); - case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2); - case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2); - case NODE_MIX_CLAMP: return svm_mix_clamp(c1); - } - - return make_float3(0.0f, 0.0f, 0.0f); -} - /* Node */ ccl_device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset) diff --git a/intern/cycles/kernel/svm/svm_ramp.h b/intern/cycles/kernel/svm/svm_ramp.h index 59dec409a70..24275d05c4a 100644 --- a/intern/cycles/kernel/svm/svm_ramp.h +++ b/intern/cycles/kernel/svm/svm_ramp.h @@ -92,11 +92,11 @@ ccl_device void svm_node_rgb_curves(KernelGlobals *kg, ShaderData *sd, float *st const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w); const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; + const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x; - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; + float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x; + float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y; + float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); @@ -121,11 +121,11 @@ ccl_device void svm_node_vector_curves(KernelGlobals *kg, ShaderData *sd, float const float min_x = __int_as_float(node.z), max_x = __int_as_float(node.w); const float range_x = max_x - min_x; - color = (color - make_float3(min_x, min_x, min_x)) / range_x; + const float3 relpos = (color - make_float3(min_x, min_x, min_x)) / range_x; - float r = rgb_ramp_lookup(kg, *offset, color.x, true, true, table_size).x; - float g = rgb_ramp_lookup(kg, *offset, color.y, true, true, table_size).y; - float b = rgb_ramp_lookup(kg, *offset, color.z, true, true, table_size).z; + float r = rgb_ramp_lookup(kg, *offset, relpos.x, true, true, table_size).x; + float g = rgb_ramp_lookup(kg, *offset, relpos.y, true, true, table_size).y; + float b = rgb_ramp_lookup(kg, *offset, relpos.z, true, true, table_size).z; color = (1.0f - fac)*color + fac*make_float3(r, g, b); stack_store_float3(stack, out_offset, color); diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h index 27fed89fdf7..276b6f26f5e 100644 --- a/intern/cycles/kernel/svm/svm_tex_coord.h +++ b/intern/cycles/kernel/svm/svm_tex_coord.h @@ -312,7 +312,7 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st /* apply normal map */ float3 B = sign * cross(normal, tangent); - N = normalize(color.x * tangent + color.y * B + color.z * normal); + N = safe_normalize(color.x * tangent + color.y * B + color.z * normal); /* transform to world space */ object_normal_transform(kg, sd, &N); @@ -330,14 +330,18 @@ ccl_device void svm_node_normal_map(KernelGlobals *kg, ShaderData *sd, float *st if(space == NODE_NORMAL_MAP_OBJECT || space == NODE_NORMAL_MAP_BLENDER_OBJECT) object_normal_transform(kg, sd, &N); else - N = normalize(N); + N = safe_normalize(N); } float strength = stack_load_float(stack, strength_offset); if(strength != 1.0f) { strength = max(strength, 0.0f); - N = normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + N = safe_normalize(ccl_fetch(sd, N) + (N - ccl_fetch(sd, N))*strength); + } + + if(is_zero(N)) { + N = ccl_fetch(sd, N); } stack_store_float3(stack, normal_offset, N); diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h index e57d22b1b13..e1a8ced6a34 100644 --- a/intern/cycles/kernel/svm/svm_types.h +++ b/intern/cycles/kernel/svm/svm_types.h @@ -396,8 +396,10 @@ typedef enum ClosureType { CLOSURE_BSDF_REFLECTION_ID, CLOSURE_BSDF_MICROFACET_GGX_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID, CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, @@ -413,6 +415,7 @@ typedef enum ClosureType { CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID, + CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID, CLOSURE_BSDF_SHARP_GLASS_ID, CLOSURE_BSDF_HAIR_TRANSMISSION_ID, diff --git a/intern/cycles/render/CMakeLists.txt b/intern/cycles/render/CMakeLists.txt index b14da3e63d0..a632ddc0598 100644 --- a/intern/cycles/render/CMakeLists.txt +++ b/intern/cycles/render/CMakeLists.txt @@ -22,6 +22,7 @@ set(SRC bake.cpp buffers.cpp camera.cpp + constant_fold.cpp film.cpp graph.cpp image.cpp @@ -49,6 +50,7 @@ set(SRC_HEADERS background.h buffers.h camera.h + constant_fold.h film.h graph.h image.h diff --git a/intern/cycles/render/constant_fold.cpp b/intern/cycles/render/constant_fold.cpp new file mode 100644 index 00000000000..1fee6b2c081 --- /dev/null +++ b/intern/cycles/render/constant_fold.cpp @@ -0,0 +1,122 @@ +/* + * 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. + */ + +#include "constant_fold.h" +#include "graph.h" + +#include "util_foreach.h" + +CCL_NAMESPACE_BEGIN + +ConstantFolder::ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output) +: graph(graph), node(node), output(output) +{ +} + +bool ConstantFolder::all_inputs_constant() const +{ + foreach(ShaderInput *input, node->inputs) { + if(input->link) { + return false; + } + } + + return true; +} + +void ConstantFolder::make_constant(float value) const +{ + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant(float3 value) const +{ + foreach(ShaderInput *sock, output->links) { + sock->set(value); + } + + graph->disconnect(output); +} + +void ConstantFolder::make_constant_clamp(float value, bool clamp) const +{ + make_constant(clamp ? saturate(value) : value); +} + +void ConstantFolder::make_constant_clamp(float3 value, bool clamp) const +{ + if (clamp) { + value.x = saturate(value.x); + value.y = saturate(value.y); + value.z = saturate(value.z); + } + + make_constant(value); +} + +void ConstantFolder::bypass(ShaderOutput *new_output) const +{ + assert(new_output); + + /* Remove all outgoing links from socket and connect them to new_output instead. + * The graph->relink method affects node inputs, so it's not safe to use in constant + * folding if the node has multiple outputs and will thus be folded multiple times. */ + vector<ShaderInput*> outputs = output->links; + + graph->disconnect(output); + + foreach(ShaderInput *sock, outputs) { + graph->connect(new_output, sock); + } +} + +void ConstantFolder::discard() const +{ + assert(output->type() == SocketType::CLOSURE); + graph->disconnect(output); +} + +void ConstantFolder::bypass_or_discard(ShaderInput *input) const +{ + assert(input->type() == SocketType::CLOSURE); + + if (input->link) { + bypass(input->link); + } + else { + discard(); + } +} + +bool ConstantFolder::try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const +{ + if(!input->link) { + make_constant_clamp(input_value, clamp); + return true; + } + else if(!clamp) { + bypass(input->link); + return true; + } + + return false; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/render/constant_fold.h b/intern/cycles/render/constant_fold.h new file mode 100644 index 00000000000..978c8e5335a --- /dev/null +++ b/intern/cycles/render/constant_fold.h @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef __CONSTANT_FOLD_H__ +#define __CONSTANT_FOLD_H__ + +#include "util_types.h" + +CCL_NAMESPACE_BEGIN + +class ShaderGraph; +class ShaderInput; +class ShaderNode; +class ShaderOutput; + +class ConstantFolder { +public: + ShaderGraph *const graph; + ShaderNode *const node; + ShaderOutput *const output; + + ConstantFolder(ShaderGraph *graph, ShaderNode *node, ShaderOutput *output); + + bool all_inputs_constant() const; + + /* Constant folding helpers, always return true for convenience. */ + void make_constant(float value) const; + void make_constant(float3 value) const; + void make_constant_clamp(float value, bool clamp) const; + void make_constant_clamp(float3 value, bool clamp) const; + + /* Bypass node, relinking to another output socket. */ + void bypass(ShaderOutput *output) const; + + /* For closure nodes, discard node entirely or bypass to one of its inputs. */ + void discard() const; + void bypass_or_discard(ShaderInput *input) const; + + /* Bypass or make constant, unless we can't due to clamp being true. */ + bool try_bypass_or_make_constant(ShaderInput *input, float3 input_value, bool clamp) const; +}; + +CCL_NAMESPACE_END + +#endif /* __CONSTANT_FOLD_H__ */ + diff --git a/intern/cycles/render/graph.cpp b/intern/cycles/render/graph.cpp index 9210221a261..ac78238dfee 100644 --- a/intern/cycles/render/graph.cpp +++ b/intern/cycles/render/graph.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * Copyright 2011-2016 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,6 +18,7 @@ #include "graph.h" #include "nodes.h" #include "shader.h" +#include "constant_fold.h" #include "util_algorithm.h" #include "util_debug.h" @@ -267,6 +268,17 @@ void ShaderGraph::connect(ShaderOutput *from, ShaderInput *to) } } +void ShaderGraph::disconnect(ShaderOutput *from) +{ + assert(!finalized); + + foreach(ShaderInput *sock, from->links) { + sock->link = NULL; + } + + from->links.clear(); +} + void ShaderGraph::disconnect(ShaderInput *to) { assert(!finalized); @@ -514,15 +526,8 @@ void ShaderGraph::constant_fold() } } /* Optimize current node. */ - if(node->constant_fold(this, output, output->links[0])) { - /* Apply optimized value to other connected sockets and disconnect. */ - vector<ShaderInput*> links(output->links); - for(size_t i = 0; i < links.size(); i++) { - if(i > 0) - links[i]->parent->copy_value(links[i]->socket_type, *links[0]->parent, links[0]->socket_type); - disconnect(links[i]); - } - } + ConstantFolder folder(this, node, output); + node->constant_fold(folder); } } } @@ -547,8 +552,8 @@ void ShaderGraph::deduplicate_nodes() * already deduplicated. */ - ShaderNodeSet scheduled; - map<ustring, ShaderNodeSet> done; + ShaderNodeSet scheduled, done; + map<ustring, ShaderNodeSet> candidates; queue<ShaderNode*> traverse_queue; /* Schedule nodes which doesn't have any dependencies. */ @@ -562,7 +567,7 @@ void ShaderGraph::deduplicate_nodes() while(!traverse_queue.empty()) { ShaderNode *node = traverse_queue.front(); traverse_queue.pop(); - done[node->name].insert(node); + done.insert(node); /* Schedule the nodes which were depending on the current node. */ foreach(ShaderOutput *output, node->outputs) { foreach(ShaderInput *input, output->links) { @@ -573,21 +578,28 @@ void ShaderGraph::deduplicate_nodes() continue; } /* Schedule node if its inputs are fully done. */ - if(check_node_inputs_traversed(input->parent, done[input->parent->name])) { + if(check_node_inputs_traversed(input->parent, done)) { traverse_queue.push(input->parent); scheduled.insert(input->parent); } } } /* Try to merge this node with another one. */ - foreach(ShaderNode *other_node, done[node->name]) { + ShaderNode *merge_with = NULL; + foreach(ShaderNode *other_node, candidates[node->type->name]) { if (node != other_node && node->equals(*other_node)) { - /* TODO(sergey): Consider making it an utility function. */ - for(int i = 0; i < node->outputs.size(); ++i) { - relink(node, node->outputs[i], other_node->outputs[i]); - } + merge_with = other_node; + break; } - break; + } + /* If found an equivalent, merge; otherwise keep node for later merges */ + if (merge_with != NULL) { + for(int i = 0; i < node->outputs.size(); ++i) { + relink(node, node->outputs[i], merge_with->outputs[i]); + } + } + else { + candidates[node->type->name].insert(node); } } } diff --git a/intern/cycles/render/graph.h b/intern/cycles/render/graph.h index dccd8c27b2f..b35be48d8ca 100644 --- a/intern/cycles/render/graph.h +++ b/intern/cycles/render/graph.h @@ -1,5 +1,5 @@ /* - * Copyright 2011-2013 Blender Foundation + * Copyright 2011-2016 Blender Foundation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,6 +41,7 @@ class ShaderGraph; class SVMCompiler; class OSLCompiler; class OutputNode; +class ConstantFolder; /* Bump * @@ -140,7 +141,7 @@ public: /* ** Node optimization ** */ /* Check whether the node can be replaced with single constant. */ - virtual bool constant_fold(ShaderGraph * /*graph*/, ShaderOutput * /*socket*/, ShaderInput * /*optimized*/) { return false; } + virtual void constant_fold(const ConstantFolder& /*folder*/) {} /* Simplify settings used by artists to the ones which are simpler to * evaluate in the kernel but keep the final result unchanged. @@ -249,6 +250,7 @@ public: OutputNode *output(); void connect(ShaderOutput *from, ShaderInput *to); + void disconnect(ShaderOutput *from); void disconnect(ShaderInput *to); void relink(ShaderNode *node, ShaderOutput *from, ShaderOutput *to); diff --git a/intern/cycles/render/image.cpp b/intern/cycles/render/image.cpp index 71dc85f5f03..614620c14af 100644 --- a/intern/cycles/render/image.cpp +++ b/intern/cycles/render/image.cpp @@ -54,10 +54,14 @@ ImageManager::ImageManager(const DeviceInfo& info) tex_num_images[IMAGE_DATA_TYPE_BYTE4] = TEX_NUM_BYTE4_ ## ARCH; \ tex_num_images[IMAGE_DATA_TYPE_FLOAT] = TEX_NUM_FLOAT_ ## ARCH; \ tex_num_images[IMAGE_DATA_TYPE_BYTE] = TEX_NUM_BYTE_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF4] = TEX_NUM_HALF4_ ## ARCH; \ + tex_num_images[IMAGE_DATA_TYPE_HALF] = TEX_NUM_HALF_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = TEX_START_FLOAT4_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_BYTE4] = TEX_START_BYTE4_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_FLOAT] = TEX_START_FLOAT_ ## ARCH; \ tex_start_images[IMAGE_DATA_TYPE_BYTE] = TEX_START_BYTE_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF4] = TEX_START_HALF4_ ## ARCH; \ + tex_start_images[IMAGE_DATA_TYPE_HALF] = TEX_START_HALF_ ## ARCH; \ } if(device_type == DEVICE_CPU) { @@ -80,10 +84,14 @@ ImageManager::ImageManager(const DeviceInfo& info) tex_num_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_num_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_num_images[IMAGE_DATA_TYPE_BYTE] = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_num_images[IMAGE_DATA_TYPE_HALF] = 0; tex_start_images[IMAGE_DATA_TYPE_FLOAT4] = 0; tex_start_images[IMAGE_DATA_TYPE_BYTE4] = 0; tex_start_images[IMAGE_DATA_TYPE_FLOAT] = 0; tex_start_images[IMAGE_DATA_TYPE_BYTE] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF4] = 0; + tex_start_images[IMAGE_DATA_TYPE_HALF] = 0; assert(0); } @@ -128,7 +136,7 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen void *builtin_data, bool& is_linear) { - bool is_float = false; + bool is_float = false, is_half = false; is_linear = false; int channels = 4; @@ -167,6 +175,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen } } + /* check if it's half float */ + if(spec.format == TypeDesc::HALF) + is_half = true; + channels = spec.nchannels; /* basic color space detection, not great but better than nothing @@ -192,7 +204,10 @@ ImageManager::ImageDataType ImageManager::get_image_metadata(const string& filen delete in; } - if(is_float) { + if(is_half) { + return (channels > 1) ? IMAGE_DATA_TYPE_HALF4 : IMAGE_DATA_TYPE_HALF; + } + else if(is_float) { return (channels > 1) ? IMAGE_DATA_TYPE_FLOAT4 : IMAGE_DATA_TYPE_FLOAT; } else { @@ -230,6 +245,10 @@ string ImageManager::name_from_type(int type) return "float"; else if(type == IMAGE_DATA_TYPE_BYTE) return "byte"; + else if(type == IMAGE_DATA_TYPE_HALF4) + return "half4"; + else if(type == IMAGE_DATA_TYPE_HALF) + return "half"; else return "byte4"; } @@ -265,11 +284,16 @@ int ImageManager::add_image(const string& filename, if(type == IMAGE_DATA_TYPE_FLOAT || type == IMAGE_DATA_TYPE_FLOAT4) is_float = true; - /* No single channel textures on CUDA (Fermi) and OpenCL, use available slots */ - if(type == IMAGE_DATA_TYPE_FLOAT && tex_num_images[type] == 0) + /* No single channel and half textures on CUDA (Fermi) and OpenCL, use available slots */ + if((type == IMAGE_DATA_TYPE_FLOAT || + type == IMAGE_DATA_TYPE_HALF4 || + type == IMAGE_DATA_TYPE_HALF) && + tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_FLOAT4; - if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) + } + if(type == IMAGE_DATA_TYPE_BYTE && tex_num_images[type] == 0) { type = IMAGE_DATA_TYPE_BYTE4; + } /* Fnd existing image. */ for(slot = 0; slot < images[type].size(); slot++) { @@ -645,6 +669,107 @@ bool ImageManager::file_load_float_image(Image *img, ImageDataType type, device_ return true; } +template<typename T> +bool ImageManager::file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img) +{ + ImageInput *in = NULL; + int width, height, depth, components; + + if(!file_load_image_generic(img, &in, width, height, depth, components)) + return false; + + /* read RGBA pixels */ + half *pixels = (half*)tex_img.resize(width, height, depth); + if(pixels == NULL) { + return false; + } + + if(in) { + half *readpixels = pixels; + vector<half> tmppixels; + + if(components > 4) { + tmppixels.resize(((size_t)width)*height*components); + readpixels = &tmppixels[0]; + } + + if(depth <= 1) { + int scanlinesize = width*components*sizeof(half); + + in->read_image(TypeDesc::HALF, + (uchar*)readpixels + (height-1)*scanlinesize, + AutoStride, + -scanlinesize, + AutoStride); + } + else { + in->read_image(TypeDesc::HALF, (uchar*)readpixels); + } + + if(components > 4) { + size_t dimensions = ((size_t)width)*height; + for(size_t i = dimensions-1, pixel = 0; pixel < dimensions; pixel++, i--) { + pixels[i*4+3] = tmppixels[i*components+3]; + pixels[i*4+2] = tmppixels[i*components+2]; + pixels[i*4+1] = tmppixels[i*components+1]; + pixels[i*4+0] = tmppixels[i*components+0]; + } + + tmppixels.clear(); + } + + in->close(); + delete in; + } +#if 0 + /* TODO(dingto): Support half for ImBuf. */ + else { + builtin_image_float_pixels_cb(img->filename, img->builtin_data, pixels); + } +#endif + + /* Check if we actually have a half4 slot, in case components == 1, but device + * doesn't support single channel textures. */ + if(type == IMAGE_DATA_TYPE_HALF4) { + size_t num_pixels = ((size_t)width) * height * depth; + if(components == 2) { + /* grayscale + alpha */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = pixels[i*2+1]; + pixels[i*4+2] = pixels[i*2+0]; + pixels[i*4+1] = pixels[i*2+0]; + pixels[i*4+0] = pixels[i*2+0]; + } + } + else if(components == 3) { + /* RGB */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i*3+2]; + pixels[i*4+1] = pixels[i*3+1]; + pixels[i*4+0] = pixels[i*3+0]; + } + } + else if(components == 1) { + /* grayscale */ + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + pixels[i*4+2] = pixels[i]; + pixels[i*4+1] = pixels[i]; + pixels[i*4+0] = pixels[i]; + } + } + + if(img->use_alpha == false) { + for(size_t i = num_pixels-1, pixel = 0; pixel < num_pixels; pixel++, i--) { + pixels[i*4+3] = 1.0f; + } + } + } + + return true; +} + void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progress) { if(progress->get_cancel()) @@ -744,7 +869,7 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -767,6 +892,55 @@ void ImageManager::device_load_image(Device *device, DeviceScene *dscene, ImageD img->extension); } } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + pixels[1] = TEX_IMAGE_MISSING_G; + pixels[2] = TEX_IMAGE_MISSING_B; + pixels[3] = TEX_IMAGE_MISSING_A; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + if(!file_load_half_image(img, type, tex_img)) { + /* on failure to load, we set a 1x1 pixels pink image */ + half *pixels = (half*)tex_img.resize(1, 1); + + pixels[0] = TEX_IMAGE_MISSING_R; + } + + if(!pack_images) { + thread_scoped_lock device_lock(device_mutex); + device->tex_alloc(name.c_str(), + tex_img, + img->interpolation, + img->extension); + } + } img->need_load = false; } @@ -812,7 +986,7 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } - else { + else if(type == IMAGE_DATA_TYPE_BYTE){ device_vector<uchar>& tex_img = dscene->tex_byte_image[slot]; if(tex_img.device_pointer) { @@ -822,6 +996,26 @@ void ImageManager::device_free_image(Device *device, DeviceScene *dscene, ImageD tex_img.clear(); } + else if(type == IMAGE_DATA_TYPE_HALF4){ + device_vector<half4>& tex_img = dscene->tex_half4_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } + else if(type == IMAGE_DATA_TYPE_HALF){ + device_vector<half>& tex_img = dscene->tex_half_image[slot]; + + if(tex_img.device_pointer) { + thread_scoped_lock device_lock(device_mutex); + device->tex_free(tex_img); + } + + tex_img.clear(); + } delete images[type][slot]; images[type][slot] = NULL; @@ -882,6 +1076,26 @@ void ImageManager::device_update_slot(Device *device, } } +uint8_t ImageManager::pack_image_options(ImageDataType type, size_t slot) +{ + uint8_t options = 0; + + /* Image Options are packed into one uint: + * bit 0 -> Interpolation + * bit 1 + 2 + 3-> Extension */ + if(images[type][slot]->interpolation == INTERPOLATION_CLOSEST) + options |= (1 << 0); + + if(images[type][slot]->extension == EXTENSION_REPEAT) + options |= (1 << 1); + else if(images[type][slot]->extension == EXTENSION_EXTEND) + options |= (1 << 2); + else /* EXTENSION_CLIP */ + options |= (1 << 3); + + return options; +} + void ImageManager::device_pack_images(Device *device, DeviceScene *dscene, Progress& /*progess*/) @@ -913,11 +1127,9 @@ void ImageManager::device_pack_images(Device *device, device_vector<uchar4>& tex_img = dscene->tex_byte4_image[slot]; - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_byte+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); @@ -945,11 +1157,8 @@ void ImageManager::device_pack_images(Device *device, /* todo: support 3D textures, only CPU for now */ - /* The image options are packed - bit 0 -> periodic - bit 1 + 2 -> interpolation type */ - uint8_t interpolation = (images[type][slot]->interpolation << 1) + 1; - info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, interpolation); + uint8_t options = pack_image_options(type, slot); + info[type_index_to_flattened_slot(slot, type)] = make_uint4(tex_img.data_width, tex_img.data_height, offset, options); memcpy(pixels_float+offset, (void*)tex_img.data_pointer, tex_img.memory_size()); offset += tex_img.size(); diff --git a/intern/cycles/render/image.h b/intern/cycles/render/image.h index 8735133fd91..07998684b23 100644 --- a/intern/cycles/render/image.h +++ b/intern/cycles/render/image.h @@ -41,6 +41,8 @@ public: IMAGE_DATA_TYPE_BYTE4 = 1, IMAGE_DATA_TYPE_FLOAT = 2, IMAGE_DATA_TYPE_BYTE = 3, + IMAGE_DATA_TYPE_HALF4 = 4, + IMAGE_DATA_TYPE_HALF = 5, IMAGE_DATA_NUM_TYPES }; @@ -113,10 +115,15 @@ private: template<typename T> bool file_load_float_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + template<typename T> + bool file_load_half_image(Image *img, ImageDataType type, device_vector<T>& tex_img); + int type_index_to_flattened_slot(int slot, ImageDataType type); int flattened_slot_to_type_index(int flat_slot, ImageDataType *type); string name_from_type(int type); + uint8_t pack_image_options(ImageDataType type, size_t slot); + void device_load_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot, Progress *progess); void device_free_image(Device *device, DeviceScene *dscene, ImageDataType type, int slot); diff --git a/intern/cycles/render/integrator.cpp b/intern/cycles/render/integrator.cpp index 2a10eb474a4..63914e57319 100644 --- a/intern/cycles/render/integrator.cpp +++ b/intern/cycles/render/integrator.cpp @@ -176,7 +176,7 @@ void Integrator::device_update(Device *device, DeviceScene *dscene, Scene *scene max_samples = max(max_samples, volume_samples); } - max_samples *= (max_bounce + transparent_max_bounce + 3); + max_samples *= (max_bounce + transparent_max_bounce + 3 + BSSRDF_MAX_HITS); int dimensions = PRNG_BASE_NUM + max_samples*PRNG_BOUNCE_NUM; dimensions = min(dimensions, SOBOL_MAX_DIMENSIONS); diff --git a/intern/cycles/render/mesh.cpp b/intern/cycles/render/mesh.cpp index 764a925983e..8b0ed9f77b2 100644 --- a/intern/cycles/render/mesh.cpp +++ b/intern/cycles/render/mesh.cpp @@ -73,6 +73,37 @@ void Mesh::Curve::bounds_grow(const int k, const float3 *curve_keys, const float bounds.grow(upper, mr); } +void Mesh::Curve::bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform& aligned_space, + BoundBox& bounds) const +{ + float3 P[4]; + + P[0] = curve_keys[max(first_key + k - 1,first_key)]; + P[1] = curve_keys[first_key + k]; + P[2] = curve_keys[first_key + k + 1]; + P[3] = curve_keys[min(first_key + k + 2, first_key + num_keys - 1)]; + + P[0] = transform_point(&aligned_space, P[0]); + P[1] = transform_point(&aligned_space, P[1]); + P[2] = transform_point(&aligned_space, P[2]); + P[3] = transform_point(&aligned_space, P[3]); + + float3 lower; + float3 upper; + + curvebounds(&lower.x, &upper.x, P, 0); + curvebounds(&lower.y, &upper.y, P, 1); + curvebounds(&lower.z, &upper.z, P, 2); + + float mr = max(curve_radius[first_key + k], curve_radius[first_key + k + 1]); + + bounds.grow(lower, mr); + bounds.grow(upper, mr); +} + /* Mesh */ NODE_DEFINE(Mesh) @@ -472,30 +503,19 @@ void Mesh::pack_normals(Scene *scene, uint *tri_shader, float4 *vnormal) } } -void Mesh::pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset) +void Mesh::pack_verts(const vector<uint>& tri_prim_index, + uint4 *tri_vindex, + size_t vert_offset, + size_t tri_offset) { - size_t verts_size = verts.size(); - - if(verts_size) { - float3 *verts_ptr = &verts[0]; - - for(size_t i = 0; i < verts_size; i++) { - float3 p = verts_ptr[i]; - tri_verts[i] = make_float4(p.x, p.y, p.z, 0.0f); - } - } - - size_t triangles_size = num_triangles(); - + const size_t triangles_size = num_triangles(); if(triangles_size) { for(size_t i = 0; i < triangles_size; i++) { Triangle t = get_triangle(i); - - tri_vindex[i] = make_float4( - __int_as_float(t.v[0] + vert_offset), - __int_as_float(t.v[1] + vert_offset), - __int_as_float(t.v[2] + vert_offset), - 0); + tri_vindex[i] = make_uint4(t.v[0] + vert_offset, + t.v[1] + vert_offset, + t.v[2] + vert_offset, + tri_prim_index[i + tri_offset]); } } } @@ -533,7 +553,11 @@ void Mesh::pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, s } } -void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total) +void Mesh::compute_bvh(DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total) { if(progress->get_cancel()) return; @@ -564,6 +588,8 @@ void Mesh::compute_bvh(SceneParams *params, Progress *progress, int n, int total BVHParams bparams; bparams.use_spatial_split = params->use_bvh_spatial_split; bparams.use_qbvh = params->use_qbvh; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + params->use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, objects); @@ -1070,42 +1096,82 @@ void MeshManager::device_update_attributes(Device *device, DeviceScene *dscene, } } -void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) +void MeshManager::mesh_calc_offset(Scene *scene) { - /* count and update offsets */ size_t vert_size = 0; size_t tri_size = 0; - size_t curve_key_size = 0; size_t curve_size = 0; foreach(Mesh *mesh, scene->meshes) { mesh->vert_offset = vert_size; mesh->tri_offset = tri_size; - mesh->curvekey_offset = curve_key_size; mesh->curve_offset = curve_size; vert_size += mesh->verts.size(); tri_size += mesh->num_triangles(); - curve_key_size += mesh->curve_keys.size(); curve_size += mesh->num_curves(); } +} +void MeshManager::device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress& progress) +{ + /* Count. */ + size_t vert_size = 0; + size_t tri_size = 0; + size_t curve_key_size = 0; + size_t curve_size = 0; + foreach(Mesh *mesh, scene->meshes) { + vert_size += mesh->verts.size(); + tri_size += mesh->num_triangles(); + curve_key_size += mesh->curve_keys.size(); + curve_size += mesh->num_curves(); + } + /* Create mapping from triangle to primitive triangle array. */ + vector<uint> tri_prim_index(tri_size); + if(for_displacement) { + /* For displacement kernels we do some trickery to make them believe + * we've got all required data ready. However, that data is different + * from final render kernels since we don't have BVH yet, so can't + * really use same semantic of arrays. + */ + foreach(Mesh *mesh, scene->meshes) { + for(size_t i = 0; i < mesh->num_triangles(); ++i) { + tri_prim_index[i + mesh->tri_offset] = 3 * (i + mesh->tri_offset); + } + } + } + else { + PackedBVH& pack = bvh->pack; + for(size_t i = 0; i < pack.prim_index.size(); ++i) { + if ((pack.prim_type[i] & PRIMITIVE_ALL_TRIANGLE) != 0) { + tri_prim_index[pack.prim_index[i]] = pack.prim_tri_index[i]; + } + } + } + /* Fill in all the arrays. */ if(tri_size != 0) { /* normals */ progress.set_status("Updating Mesh", "Computing normals"); uint *tri_shader = dscene->tri_shader.resize(tri_size); float4 *vnormal = dscene->tri_vnormal.resize(vert_size); - float4 *tri_verts = dscene->tri_verts.resize(vert_size); - float4 *tri_vindex = dscene->tri_vindex.resize(tri_size); + uint4 *tri_vindex = dscene->tri_vindex.resize(tri_size); foreach(Mesh *mesh, scene->meshes) { - mesh->pack_normals(scene, &tri_shader[mesh->tri_offset], &vnormal[mesh->vert_offset]); - mesh->pack_verts(&tri_verts[mesh->vert_offset], &tri_vindex[mesh->tri_offset], mesh->vert_offset); - + mesh->pack_normals(scene, + &tri_shader[mesh->tri_offset], + &vnormal[mesh->vert_offset]); + mesh->pack_verts(tri_prim_index, + &tri_vindex[mesh->tri_offset], + mesh->vert_offset, + mesh->tri_offset); if(progress.get_cancel()) return; } @@ -1114,10 +1180,8 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene device->tex_alloc("__tri_shader", dscene->tri_shader); device->tex_alloc("__tri_vnormal", dscene->tri_vnormal); - device->tex_alloc("__tri_verts", dscene->tri_verts); device->tex_alloc("__tri_vindex", dscene->tri_vindex); } - if(curve_size != 0) { progress.set_status("Updating Mesh", "Copying Strands to device"); @@ -1132,6 +1196,19 @@ void MeshManager::device_update_mesh(Device *device, DeviceScene *dscene, Scene device->tex_alloc("__curve_keys", dscene->curve_keys); device->tex_alloc("__curves", dscene->curves); } + if(for_displacement) { + float4 *prim_tri_verts = dscene->prim_tri_verts.resize(tri_size * 3); + foreach(Mesh *mesh, scene->meshes) { + for(size_t i = 0; i < mesh->num_triangles(); ++i) { + Mesh::Triangle t = mesh->get_triangle(i); + size_t offset = 3 * (i + mesh->tri_offset); + prim_tri_verts[offset + 0] = float3_to_float4(mesh->verts[t.v[0]]); + prim_tri_verts[offset + 1] = float3_to_float4(mesh->verts[t.v[1]]); + prim_tri_verts[offset + 2] = float3_to_float4(mesh->verts[t.v[2]]); + } + } + device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts); + } } void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress) @@ -1146,6 +1223,8 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * bparams.top_level = true; bparams.use_qbvh = scene->params.use_qbvh; bparams.use_spatial_split = scene->params.use_bvh_spatial_split; + bparams.use_unaligned_nodes = dscene->data.bvh.have_curves && + scene->params.use_bvh_unaligned_nodes; delete bvh; bvh = BVH::create(bparams, scene->objects); @@ -1170,9 +1249,13 @@ void MeshManager::device_update_bvh(Device *device, DeviceScene *dscene, Scene * dscene->object_node.reference((uint*)&pack.object_node[0], pack.object_node.size()); device->tex_alloc("__object_node", dscene->object_node); } - if(pack.tri_storage.size()) { - dscene->tri_storage.reference(&pack.tri_storage[0], pack.tri_storage.size()); - device->tex_alloc("__tri_storage", dscene->tri_storage); + if(pack.prim_tri_index.size()) { + dscene->prim_tri_index.reference((uint*)&pack.prim_tri_index[0], pack.prim_tri_index.size()); + device->tex_alloc("__prim_tri_index", dscene->prim_tri_index); + } + if(pack.prim_tri_verts.size()) { + dscene->prim_tri_verts.reference((float4*)&pack.prim_tri_verts[0], pack.prim_tri_verts.size()); + device->tex_alloc("__prim_tri_verts", dscene->prim_tri_verts); } if(pack.prim_type.size()) { dscene->prim_type.reference((uint*)&pack.prim_type[0], pack.prim_type.size()); @@ -1273,7 +1356,7 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen VLOG(1) << "Total " << scene->meshes.size() << " meshes."; - /* update normals */ + /* Update normals. */ foreach(Mesh *mesh, scene->meshes) { foreach(Shader *shader, mesh->used_shaders) { if(shader->need_update_attributes) @@ -1289,17 +1372,17 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } /* Update images needed for true displacement. */ - bool need_displacement_images = false; + bool true_displacement_used = false; bool old_need_object_flags_update = false; foreach(Mesh *mesh, scene->meshes) { if(mesh->need_update && mesh->displacement_method != Mesh::DISPLACE_BUMP) { - need_displacement_images = true; + true_displacement_used = true; break; } } - if(need_displacement_images) { + if(true_displacement_used) { VLOG(1) << "Updating images used for true displacement."; device_update_displacement_images(device, dscene, scene, progress); old_need_object_flags_update = scene->object_manager->need_flags_update; @@ -1310,49 +1393,52 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen false); } - /* device update */ + /* Device update. */ device_free(device, dscene); - device_update_mesh(device, dscene, scene, progress); + mesh_calc_offset(scene); + if(true_displacement_used) { + device_update_mesh(device, dscene, scene, true, progress); + } if(progress.get_cancel()) return; device_update_attributes(device, dscene, scene, progress); if(progress.get_cancel()) return; - /* update displacement */ + /* Update displacement. */ bool displacement_done = false; - - foreach(Mesh *mesh, scene->meshes) - if(mesh->need_update && displace(device, dscene, scene, mesh, progress)) + foreach(Mesh *mesh, scene->meshes) { + if(mesh->need_update && + displace(device, dscene, scene, mesh, progress)) + { displacement_done = true; + } + } - /* todo: properly handle cancel halfway displacement */ + /* TODO: properly handle cancel halfway displacement */ if(progress.get_cancel()) return; - /* device re-update after displacement */ + /* Device re-update after displacement. */ if(displacement_done) { device_free(device, dscene); - device_update_mesh(device, dscene, scene, progress); - if(progress.get_cancel()) return; - device_update_attributes(device, dscene, scene, progress); if(progress.get_cancel()) return; } - /* update bvh */ + /* Update bvh. */ size_t i = 0, num_bvh = 0; - - foreach(Mesh *mesh, scene->meshes) - if(mesh->need_update && mesh->need_build_bvh()) + foreach(Mesh *mesh, scene->meshes) { + if(mesh->need_update && mesh->need_build_bvh()) { num_bvh++; - + } + } TaskPool pool; - foreach(Mesh *mesh, scene->meshes) { if(mesh->need_update) { pool.push(function_bind(&Mesh::compute_bvh, mesh, + dscene, &scene->params, &progress, i, @@ -1362,14 +1448,14 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen } } } - TaskPool::Summary summary; pool.wait_work(&summary); VLOG(2) << "Objects BVH build pool statistics:\n" << summary.full_report(); - foreach(Shader *shader, scene->shaders) + foreach(Shader *shader, scene->shaders) { shader->need_update_attributes = false; + } #ifdef __OBJECT_MOTION__ Scene::MotionType need_motion = scene->need_motion(device->info.advanced_shading); @@ -1378,18 +1464,23 @@ void MeshManager::device_update(Device *device, DeviceScene *dscene, Scene *scen bool motion_blur = false; #endif - /* update obejcts */ + /* Update objects. */ vector<Object *> volume_objects; - foreach(Object *object, scene->objects) + foreach(Object *object, scene->objects) { object->compute_bounds(motion_blur); + } if(progress.get_cancel()) return; device_update_bvh(device, dscene, scene, progress); + if(progress.get_cancel()) return; + + device_update_mesh(device, dscene, scene, false, progress); + if(progress.get_cancel()) return; need_update = false; - if(need_displacement_images) { + if(true_displacement_used) { /* Re-tag flags for update, so they're re-evaluated * for meshes with correct bounding boxes. * @@ -1405,7 +1496,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->bvh_nodes); device->tex_free(dscene->bvh_leaf_nodes); device->tex_free(dscene->object_node); - device->tex_free(dscene->tri_storage); + device->tex_free(dscene->prim_tri_verts); + device->tex_free(dscene->prim_tri_index); device->tex_free(dscene->prim_type); device->tex_free(dscene->prim_visibility); device->tex_free(dscene->prim_index); @@ -1413,7 +1505,6 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) device->tex_free(dscene->tri_shader); device->tex_free(dscene->tri_vnormal); device->tex_free(dscene->tri_vindex); - device->tex_free(dscene->tri_verts); device->tex_free(dscene->curves); device->tex_free(dscene->curve_keys); device->tex_free(dscene->attributes_map); @@ -1423,7 +1514,8 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->bvh_nodes.clear(); dscene->object_node.clear(); - dscene->tri_storage.clear(); + dscene->prim_tri_verts.clear(); + dscene->prim_tri_index.clear(); dscene->prim_type.clear(); dscene->prim_visibility.clear(); dscene->prim_index.clear(); @@ -1431,7 +1523,6 @@ void MeshManager::device_free(Device *device, DeviceScene *dscene) dscene->tri_shader.clear(); dscene->tri_vnormal.clear(); dscene->tri_vindex.clear(); - dscene->tri_verts.clear(); dscene->curves.clear(); dscene->curve_keys.clear(); dscene->attributes_map.clear(); diff --git a/intern/cycles/render/mesh.h b/intern/cycles/render/mesh.h index edad6d32f00..0aea55544f2 100644 --- a/intern/cycles/render/mesh.h +++ b/intern/cycles/render/mesh.h @@ -72,7 +72,15 @@ public: int num_segments() { return num_keys - 1; } - void bounds_grow(const int k, const float3 *curve_keys, const float *curve_radius, BoundBox& bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + BoundBox& bounds) const; + void bounds_grow(const int k, + const float3 *curve_keys, + const float *curve_radius, + const Transform& aligned_space, + BoundBox& bounds) const; }; Curve get_curve(size_t i) const @@ -167,9 +175,16 @@ public: void add_vertex_normals(); void pack_normals(Scene *scene, uint *shader, float4 *vnormal); - void pack_verts(float4 *tri_verts, float4 *tri_vindex, size_t vert_offset); + void pack_verts(const vector<uint>& tri_prim_index, + uint4 *tri_vindex, + size_t vert_offset, + size_t tri_offset); void pack_curves(Scene *scene, float4 *curve_key_co, float4 *curve_data, size_t curvekey_offset); - void compute_bvh(SceneParams *params, Progress *progress, int n, int total); + void compute_bvh(DeviceScene *dscene, + SceneParams *params, + Progress *progress, + int n, + int total); bool need_attribute(Scene *scene, AttributeStandard std); bool need_attribute(Scene *scene, ustring name); @@ -213,15 +228,41 @@ public: void update_svm_attributes(Device *device, DeviceScene *dscene, Scene *scene, vector<AttributeRequestSet>& mesh_attributes); void device_update(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_object(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_mesh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_attributes(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_bvh(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); void device_update_flags(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); - void device_update_displacement_images(Device *device, DeviceScene *dscene, Scene *scene, Progress& progress); + void device_free(Device *device, DeviceScene *dscene); void tag_update(Scene *scene); + +protected: + /* Calculate verts/triangles/curves offsets in global arrays. */ + void mesh_calc_offset(Scene *scene); + + void device_update_object(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_mesh(Device *device, + DeviceScene *dscene, + Scene *scene, + bool for_displacement, + Progress& progress); + + void device_update_attributes(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_bvh(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); + + void device_update_displacement_images(Device *device, + DeviceScene *dscene, + Scene *scene, + Progress& progress); }; CCL_NAMESPACE_END diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp index 1157a1297ef..66c92bda54b 100644 --- a/intern/cycles/render/nodes.cpp +++ b/intern/cycles/render/nodes.cpp @@ -19,8 +19,10 @@ #include "nodes.h" #include "scene.h" #include "svm.h" +#include "svm_color_util.h" #include "svm_math_util.h" #include "osl.h" +#include "constant_fold.h" #include "util_sky_model.h" #include "util_foreach.h" @@ -397,7 +399,7 @@ void ImageTextureNode::compile(OSLCompiler& compiler) compiler.parameter("color_space", "sRGB"); compiler.parameter(this, "projection"); compiler.parameter(this, "projection_blend"); - compiler.parameter(this, "is_float"); + compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); compiler.parameter(this, "interpolation"); compiler.parameter(this, "extension"); @@ -580,7 +582,7 @@ void EnvironmentTextureNode::compile(OSLCompiler& compiler) compiler.parameter("color_space", "sRGB"); compiler.parameter(this, "interpolation"); - compiler.parameter(this, "is_float"); + compiler.parameter("is_float", is_float); compiler.parameter("use_alpha", !alpha_out->links.empty()); compiler.add(this, "node_environment_texture"); } @@ -610,10 +612,10 @@ static float sky_perez_function(float lam[6], float theta, float gamma) static void sky_texture_precompute_old(SunSky *sunsky, float3 dir, float turbidity) { /* - * We re-use the SunSky struct of the new model, to avoid extra variables - * zenith_Y/x/y is now radiance_x/y/z - * perez_Y/x/y is now config_x/y/z - */ + * We re-use the SunSky struct of the new model, to avoid extra variables + * zenith_Y/x/y is now radiance_x/y/z + * perez_Y/x/y is now config_x/y/z + */ float2 spherical = sky_spherical_coordinates(dir); float theta = spherical.x; @@ -1564,8 +1566,8 @@ NODE_DEFINE(RGBToBWNode) { NodeType* type = NodeType::add("rgb_to_bw", create, NodeType::SHADER); - SOCKET_IN_POINT(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_POINT(val, "Val"); + SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_OUT_FLOAT(val, "Val"); return type; } @@ -1575,14 +1577,11 @@ RGBToBWNode::RGBToBWNode() { } -bool RGBToBWNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void RGBToBWNode::constant_fold(const ConstantFolder& folder) { - if(inputs[0]->link == NULL) { - optimized->set(linear_rgb_to_gray(color)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(linear_rgb_to_gray(color)); } - - return false; } void RGBToBWNode::compile(SVMCompiler& compiler) @@ -1595,7 +1594,7 @@ void RGBToBWNode::compile(SVMCompiler& compiler) void RGBToBWNode::compile(OSLCompiler& compiler) { - compiler.add(this, "node_convert_from_color"); + compiler.add(this, "node_rgb_to_bw"); } /* Convert */ @@ -1660,40 +1659,35 @@ ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool auto special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT; } -bool ConvertNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ConvertNode::constant_fold(const ConstantFolder& folder) { /* proxy nodes should have been removed at this point */ assert(special_type != SHADER_SPECIAL_TYPE_PROXY); - ShaderInput *in = inputs[0]; - /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */ - if(in->link == NULL) { + if(folder.all_inputs_constant()) { if(from == SocketType::FLOAT) { if(SocketType::is_float3(to)) { - optimized->set(make_float3(value_float, value_float, value_float)); - return true; + folder.make_constant(make_float3(value_float, value_float, value_float)); } } else if(SocketType::is_float3(from)) { if(to == SocketType::FLOAT) { - if(from == SocketType::COLOR) + if(from == SocketType::COLOR) { /* color to float */ - optimized->set(linear_rgb_to_gray(value_color)); - else + folder.make_constant(linear_rgb_to_gray(value_color)); + } + else { /* vector/point/normal to float */ - optimized->set(average(value_vector)); - return true; + folder.make_constant(average(value_vector)); + } } else if(SocketType::is_float3(to)) { - optimized->set(value_color); - return true; + folder.make_constant(value_color); } } } - - return false; } void ConvertNode::compile(SVMCompiler& compiler) @@ -1829,6 +1823,7 @@ NODE_DEFINE(AnisotropicBsdfNode) static NodeEnum distribution_enum; distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ANISO_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID); distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ANISO_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ANISO_ID); @@ -1865,7 +1860,10 @@ void AnisotropicBsdfNode::compile(SVMCompiler& compiler) { closure = distribution; - BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); + if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ANISO_ID) + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation")); } void AnisotropicBsdfNode::compile(OSLCompiler& compiler) @@ -1889,6 +1887,7 @@ NODE_DEFINE(GlossyBsdfNode) distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID); SOCKET_IN_FLOAT(roughness, "Roughness", 0.2f); @@ -1938,6 +1937,8 @@ void GlossyBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_REFLECTION_ID) BsdfNode::compile(compiler, NULL, NULL); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID) + BsdfNode::compile(compiler, input("Roughness"), NULL, input("Color")); else BsdfNode::compile(compiler, input("Roughness"), NULL); } @@ -1962,6 +1963,7 @@ NODE_DEFINE(GlassBsdfNode) distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID); distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID); distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); + distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID); SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID); SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f); SOCKET_IN_FLOAT(IOR, "IOR", 0.3f); @@ -2012,6 +2014,8 @@ void GlassBsdfNode::compile(SVMCompiler& compiler) if(closure == CLOSURE_BSDF_SHARP_GLASS_ID) BsdfNode::compile(compiler, NULL, input("IOR")); + else if(closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID) + BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color")); else BsdfNode::compile(compiler, input("Roughness"), input("IOR")); } @@ -2353,13 +2357,15 @@ void EmissionNode::compile(OSLCompiler& compiler) compiler.add(this, "node_emission"); } -bool EmissionNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void EmissionNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Background Closure */ @@ -2403,13 +2409,15 @@ void BackgroundNode::compile(OSLCompiler& compiler) compiler.add(this, "node_background"); } -bool BackgroundNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *) +void BackgroundNode::constant_fold(const ConstantFolder& folder) { ShaderInput *color_in = input("Color"); ShaderInput *strength_in = input("Strength"); - return ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || - (!strength_in->link && strength == 0.0f)); + if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) || + (!strength_in->link && strength == 0.0f)) { + folder.discard(); + } } /* Holdout Closure */ @@ -3371,10 +3379,9 @@ ValueNode::ValueNode() { } -bool ValueNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ValueNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ValueNode::compile(SVMCompiler& compiler) @@ -3407,10 +3414,9 @@ ColorNode::ColorNode() { } -bool ColorNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void ColorNode::constant_fold(const ConstantFolder& folder) { - optimized->set(value); - return true; + folder.make_constant(value); } void ColorNode::compile(SVMCompiler& compiler) @@ -3459,6 +3465,20 @@ void AddClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_add_closure"); } +void AddClosureNode::constant_fold(const ConstantFolder& folder) +{ + ShaderInput *closure1_in = input("Closure1"); + ShaderInput *closure2_in = input("Closure2"); + + /* remove useless add closures nodes */ + if(!closure1_in->link) { + folder.bypass_or_discard(closure2_in); + } + else if(!closure2_in->link) { + folder.bypass_or_discard(closure1_in); + } +} + /* Mix Closure */ NODE_DEFINE(MixClosureNode) @@ -3490,35 +3510,28 @@ void MixClosureNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix_closure"); } -bool MixClosureNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +void MixClosureNode::constant_fold(const ConstantFolder& folder) { ShaderInput *fac_in = input("Fac"); ShaderInput *closure1_in = input("Closure1"); ShaderInput *closure2_in = input("Closure2"); - ShaderOutput *closure_out = output("Closure"); /* remove useless mix closures nodes */ if(closure1_in->link == closure2_in->link) { - graph->relink(this, closure_out, closure1_in->link); - return true; + folder.bypass_or_discard(closure1_in); } - - /* remove unused mix closure input when factor is 0.0 or 1.0 */ - /* check for closure links and make sure factor link is disconnected */ - if(closure1_in->link && closure2_in->link && !fac_in->link) { + /* remove unused mix closure input when factor is 0.0 or 1.0 + * check for closure links and make sure factor link is disconnected */ + else if(!fac_in->link) { /* factor 0.0 */ - if(fac == 0.0f) { - graph->relink(this, closure_out, closure1_in->link); - return true; + if(fac <= 0.0f) { + folder.bypass_or_discard(closure1_in); } /* factor 1.0 */ - else if(fac == 1.0f) { - graph->relink(this, closure_out, closure2_in->link); - return true; + else if(fac >= 1.0f) { + folder.bypass_or_discard(closure2_in); } } - - return false; } /* Mix Closure */ @@ -3580,6 +3593,23 @@ InvertNode::InvertNode() { } +void InvertNode::constant_fold(const ConstantFolder& folder) +{ + ShaderInput *fac_in = input("Fac"); + ShaderInput *color_in = input("Color"); + + if(!fac_in->link) { + /* evaluate fully constant node */ + if(!color_in->link) { + folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac)); + } + /* remove no-op node */ + else if(fac == 0.0f) { + folder.bypass(color_in->link); + } + } +} + void InvertNode::compile(SVMCompiler& compiler) { ShaderInput *fac_in = input("Fac"); @@ -3666,44 +3696,47 @@ void MixNode::compile(OSLCompiler& compiler) compiler.add(this, "node_mix"); } -bool MixNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *optimized) +void MixNode::constant_fold(const ConstantFolder& folder) { - if(type != NODE_MIX_BLEND) { - return false; - } - ShaderInput *fac_in = input("Fac"); ShaderInput *color1_in = input("Color1"); ShaderInput *color2_in = input("Color2"); - ShaderOutput *color_out = output("Color"); - /* remove useless mix colors nodes */ - if(color1_in->link && color1_in->link == color2_in->link) { - graph->relink(this, color_out, color1_in->link); - return true; + /* evaluate fully constant node */ + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp); + return; } - /* remove unused mix color input when factor is 0.0 or 1.0 */ - if(!fac_in->link) { - /* factor 0.0 */ - if(fac == 0.0f) { - if(color1_in->link) - graph->relink(this, color_out, color1_in->link); - else - optimized->set(color1); - return true; + /* remove no-op node when factor is 0.0 */ + if(!fac_in->link && fac <= 0.0f) { + /* note that some of the modes will clamp out of bounds values even without use_clamp */ + if(type == NODE_MIX_LIGHT || type == NODE_MIX_DODGE || type == NODE_MIX_BURN) { + if(!color1_in->link) { + folder.make_constant_clamp(svm_mix(type, 0.0f, color1, color1), use_clamp); + return; + } } - /* factor 1.0 */ - else if(fac == 1.0f) { - if(color2_in->link) - graph->relink(this, color_out, color2_in->link); - else - optimized->set(color2); - return true; + else if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; } } - return false; + if(type == NODE_MIX_BLEND) { + /* remove useless mix colors nodes */ + if(color1_in->link ? (color1_in->link == color2_in->link) : (!color2_in->link && color1 == color2)) { + if(folder.try_bypass_or_make_constant(color1_in, color1, use_clamp)) { + return; + } + } + + /* remove no-op mix color node when factor is 1.0 */ + if(!fac_in->link && fac >= 1.0f) { + if(folder.try_bypass_or_make_constant(color2_in, color2, use_clamp)) { + return; + } + } + } } /* Combine RGB */ @@ -3726,6 +3759,13 @@ CombineRGBNode::CombineRGBNode() { } +void CombineRGBNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(r, g, b)); + } +} + void CombineRGBNode::compile(SVMCompiler& compiler) { ShaderInput *red_in = input("R"); @@ -3761,7 +3801,7 @@ NODE_DEFINE(CombineXYZNode) SOCKET_IN_FLOAT(y, "Y", 0.0f); SOCKET_IN_FLOAT(z, "Z", 0.0f); - SOCKET_OUT_COLOR(color, "Image"); + SOCKET_OUT_VECTOR(vector, "Vector"); return type; } @@ -3771,6 +3811,13 @@ CombineXYZNode::CombineXYZNode() { } +void CombineXYZNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(make_float3(x, y, z)); + } +} + void CombineXYZNode::compile(SVMCompiler& compiler) { ShaderInput *x_in = input("X"); @@ -3816,6 +3863,13 @@ CombineHSVNode::CombineHSVNode() { } +void CombineHSVNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(hsv_to_rgb(make_float3(h, s, v))); + } +} + void CombineHSVNode::compile(SVMCompiler& compiler) { ShaderInput *hue_in = input("H"); @@ -3854,17 +3908,11 @@ GammaNode::GammaNode() { } -bool GammaNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void GammaNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *color_in = input("Color"); - ShaderInput *gamma_in = input("Gamma"); - - if(color_in->link == NULL && gamma_in->link == NULL) { - optimized->set(svm_math_gamma_color(color, gamma)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_gamma_color(color, gamma)); } - - return false; } void GammaNode::compile(SVMCompiler& compiler) @@ -3904,6 +3952,13 @@ BrightContrastNode::BrightContrastNode() { } +void BrightContrastNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + folder.make_constant(svm_brightness_contrast(color, bright, contrast)); + } +} + void BrightContrastNode::compile(SVMCompiler& compiler) { ShaderInput *color_in = input("Color"); @@ -3944,6 +3999,18 @@ SeparateRGBNode::SeparateRGBNode() { } +void SeparateRGBNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(color[channel]); + return; + } + } + } +} + void SeparateRGBNode::compile(SVMCompiler& compiler) { ShaderInput *color_in = input("Image"); @@ -3989,6 +4056,18 @@ SeparateXYZNode::SeparateXYZNode() { } +void SeparateXYZNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(vector[channel]); + return; + } + } + } +} + void SeparateXYZNode::compile(SVMCompiler& compiler) { ShaderInput *vector_in = input("Vector"); @@ -4034,6 +4113,20 @@ SeparateHSVNode::SeparateHSVNode() { } +void SeparateHSVNode::constant_fold(const ConstantFolder& folder) +{ + if(folder.all_inputs_constant()) { + float3 hsv = rgb_to_hsv(color); + + for(int channel = 0; channel < 3; channel++) { + if(outputs[channel] == folder.output) { + folder.make_constant(hsv[channel]); + return; + } + } + } +} + void SeparateHSVNode::compile(SVMCompiler& compiler) { ShaderInput *color_in = input("Color"); @@ -4417,16 +4510,11 @@ BlackbodyNode::BlackbodyNode() { } -bool BlackbodyNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void BlackbodyNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *temperature_in = input("Temperature"); - - if(temperature_in->link == NULL) { - optimized->set(svm_math_blackbody_color(temperature)); - return true; + if(folder.all_inputs_constant()) { + folder.make_constant(svm_math_blackbody_color(temperature)); } - - return false; } void BlackbodyNode::compile(SVMCompiler& compiler) @@ -4528,24 +4616,11 @@ MathNode::MathNode() { } -bool MathNode::constant_fold(ShaderGraph *, ShaderOutput *, ShaderInput *optimized) +void MathNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *value1_in = input("Value1"); - ShaderInput *value2_in = input("Value2"); - - if(value1_in->link == NULL && value2_in->link == NULL) { - float value = svm_math(type, value1, value2); - - if(use_clamp) { - value = saturate(value); - } - - optimized->set(value); - - return true; + if(folder.all_inputs_constant()) { + folder.make_constant_clamp(svm_math(type, value1, value2), use_clamp); } - - return false; } void MathNode::compile(SVMCompiler& compiler) @@ -4599,32 +4674,25 @@ VectorMathNode::VectorMathNode() { } -bool VectorMathNode::constant_fold(ShaderGraph *, ShaderOutput *socket, ShaderInput *optimized) +void VectorMathNode::constant_fold(const ConstantFolder& folder) { - ShaderInput *vector1_in = input("Vector1"); - ShaderInput *vector2_in = input("Vector2"); - float value; float3 vector; - if(vector1_in->link == NULL && vector2_in->link == NULL) { + if(folder.all_inputs_constant()) { svm_vector_math(&value, &vector, type, vector1, vector2); - if(socket == output("Value")) { - optimized->set(value); - return true; + if(folder.output == output("Value")) { + folder.make_constant(value); } - else if(socket == output("Vector")) { - optimized->set(vector); - return true; + else if(folder.output == output("Vector")) { + folder.make_constant(vector); } } - - return false; } void VectorMathNode::compile(SVMCompiler& compiler) @@ -4758,7 +4826,7 @@ void BumpNode::compile(OSLCompiler& compiler) compiler.add(this, "node_bump"); } -bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) +void BumpNode::constant_fold(const ConstantFolder& folder) { ShaderInput *height_in = input("Height"); ShaderInput *normal_in = input("Normal"); @@ -4766,56 +4834,36 @@ bool BumpNode::constant_fold(ShaderGraph *graph, ShaderOutput *, ShaderInput *) if(height_in->link == NULL) { if(normal_in->link == NULL) { GeometryNode *geom = new GeometryNode(); - graph->add(geom); - graph->relink(this, outputs[0], geom->output("Normal")); + folder.graph->add(geom); + folder.bypass(geom->output("Normal")); } else { - graph->relink(this, outputs[0], normal_in->link); + folder.bypass(normal_in->link); } - return true; } /* TODO(sergey): Ignore bump with zero strength. */ - - return false; } -/* RGBCurvesNode */ - -NODE_DEFINE(RGBCurvesNode) -{ - NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER); - - SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); - SOCKET_FLOAT(min_x, "Min X", 0.0f); - SOCKET_FLOAT(max_x, "Max X", 1.0f); - - SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_COLOR(color, "Color"); +/* Curve node */ - return type; -} - -RGBCurvesNode::RGBCurvesNode() +CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type) { } -void RGBCurvesNode::compile(SVMCompiler& compiler) +void CurvesNode::compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out) { if(curves.size() == 0) return; ShaderInput *fac_in = input("Fac"); - ShaderInput *color_in = input("Color"); - ShaderOutput *color_out = output("Color"); - compiler.add_node(NODE_RGB_CURVES, + compiler.add_node(type, compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(color_in), - compiler.stack_assign(color_out)), + compiler.stack_assign(value_in), + compiler.stack_assign(value_out)), __float_as_int(min_x), __float_as_int(max_x)); @@ -4824,7 +4872,7 @@ void RGBCurvesNode::compile(SVMCompiler& compiler) compiler.add_node(float3_to_float4(curves[i])); } -void RGBCurvesNode::compile(OSLCompiler& compiler) +void CurvesNode::compile(OSLCompiler& compiler, const char* name) { if(curves.size() == 0) return; @@ -4832,7 +4880,50 @@ void RGBCurvesNode::compile(OSLCompiler& compiler) compiler.parameter_color_array("ramp", curves); compiler.parameter(this, "min_x"); compiler.parameter(this, "max_x"); - compiler.add(this, "node_rgb_curves"); + compiler.add(this, name); +} + +void CurvesNode::compile(SVMCompiler& /*compiler*/) +{ + assert(0); +} + +void CurvesNode::compile(OSLCompiler& /*compiler*/) +{ + assert(0); +} + +/* RGBCurvesNode */ + +NODE_DEFINE(RGBCurvesNode) +{ + NodeType* type = NodeType::add("rgb_curves", create, NodeType::SHADER); + + SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>()); + SOCKET_FLOAT(min_x, "Min X", 0.0f); + SOCKET_FLOAT(max_x, "Max X", 1.0f); + + SOCKET_IN_FLOAT(fac, "Fac", 0.0f); + SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f)); + + SOCKET_OUT_COLOR(value, "Color"); + + return type; +} + +RGBCurvesNode::RGBCurvesNode() +: CurvesNode(node_type) +{ +} + +void RGBCurvesNode::compile(SVMCompiler& compiler) +{ + CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color")); +} + +void RGBCurvesNode::compile(OSLCompiler& compiler) +{ + CurvesNode::compile(compiler, "node_rgb_curves"); } /* VectorCurvesNode */ @@ -4846,48 +4937,26 @@ NODE_DEFINE(VectorCurvesNode) SOCKET_FLOAT(max_x, "Max X", 1.0f); SOCKET_IN_FLOAT(fac, "Fac", 0.0f); - SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f)); + SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f)); - SOCKET_OUT_VECTOR(vector, "Vector"); + SOCKET_OUT_VECTOR(value, "Vector"); return type; } VectorCurvesNode::VectorCurvesNode() -: ShaderNode(node_type) +: CurvesNode(node_type) { } void VectorCurvesNode::compile(SVMCompiler& compiler) { - if(curves.size() == 0) - return; - - ShaderInput *fac_in = input("Fac"); - ShaderInput *vector_in = input("Vector"); - ShaderOutput *vector_out = output("Vector"); - - compiler.add_node(NODE_VECTOR_CURVES, - compiler.encode_uchar4(compiler.stack_assign(fac_in), - compiler.stack_assign(vector_in), - compiler.stack_assign(vector_out)), - __float_as_int(min_x), - __float_as_int(max_x)); - - compiler.add_node(curves.size()); - for(int i = 0; i < curves.size(); i++) - compiler.add_node(float3_to_float4(curves[i])); + CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector")); } void VectorCurvesNode::compile(OSLCompiler& compiler) { - if(curves.size() == 0) - return; - - compiler.parameter_color_array("ramp", curves); - compiler.parameter(this, "min_x"); - compiler.parameter(this, "max_x"); - compiler.add(this, "node_vector_curves"); + CurvesNode::compile(compiler, "node_vector_curves"); } /* RGBRampNode */ @@ -4991,6 +5060,13 @@ OSLNode::~OSLNode() delete type; } +ShaderNode *OSLNode::clone() const +{ + OSLNode *node = new OSLNode(*this); + node->type = new NodeType(*type); + return node; +} + OSLNode* OSLNode::create(size_t num_inputs) { /* allocate space for the node itself and parameters, aligned to 16 bytes diff --git a/intern/cycles/render/nodes.h b/intern/cycles/render/nodes.h index 41894dce86a..c98ff6f278d 100644 --- a/intern/cycles/render/nodes.h +++ b/intern/cycles/render/nodes.h @@ -289,7 +289,7 @@ public: class RGBToBWNode : public ShaderNode { public: SHADER_NODE_CLASS(RGBToBWNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 color; }; @@ -299,7 +299,7 @@ public: ConvertNode(SocketType::Type from, SocketType::Type to, bool autoconvert = false); SHADER_NODE_BASE_CLASS(ConvertNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); SocketType::Type from, to; @@ -436,7 +436,7 @@ public: class EmissionNode : public ShaderNode { public: SHADER_NODE_CLASS(EmissionNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_EMISSION_ID; } bool has_surface_emission() { return true; } @@ -449,7 +449,7 @@ public: class BackgroundNode : public ShaderNode { public: SHADER_NODE_CLASS(BackgroundNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual ClosureType get_closure_type() { return CLOSURE_BACKGROUND_ID; } float3 color; @@ -605,7 +605,7 @@ class ValueNode : public ShaderNode { public: SHADER_NODE_CLASS(ValueNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value; }; @@ -614,7 +614,7 @@ class ColorNode : public ShaderNode { public: SHADER_NODE_CLASS(ColorNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 value; }; @@ -622,12 +622,13 @@ public: class AddClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(AddClosureNode) + void constant_fold(const ConstantFolder& folder); }; class MixClosureNode : public ShaderNode { public: SHADER_NODE_CLASS(MixClosureNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float fac; }; @@ -643,7 +644,7 @@ public: class InvertNode : public ShaderNode { public: SHADER_NODE_CLASS(InvertNode) - + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float fac; @@ -653,7 +654,7 @@ public: class MixNode : public ShaderNode { public: SHADER_NODE_CLASS(MixNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } @@ -667,6 +668,7 @@ public: class CombineRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineRGBNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float r, g, b; @@ -675,6 +677,7 @@ public: class CombineHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineHSVNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float h, s, v; @@ -683,6 +686,7 @@ public: class CombineXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(CombineXYZNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float x, y, z; @@ -691,7 +695,7 @@ public: class GammaNode : public ShaderNode { public: SHADER_NODE_CLASS(GammaNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -701,6 +705,7 @@ public: class BrightContrastNode : public ShaderNode { public: SHADER_NODE_CLASS(BrightContrastNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_1; } float3 color; @@ -711,6 +716,7 @@ public: class SeparateRGBNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateRGBNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -719,6 +725,7 @@ public: class SeparateHSVNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateHSVNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 color; @@ -727,6 +734,7 @@ public: class SeparateXYZNode : public ShaderNode { public: SHADER_NODE_CLASS(SeparateXYZNode) + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float3 vector; @@ -799,7 +807,7 @@ public: class BlackbodyNode : public ShaderNode { public: SHADER_NODE_CLASS(BlackbodyNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); virtual int get_group() { return NODE_GROUP_LEVEL_3; } float temperature; @@ -809,7 +817,7 @@ class MathNode : public ShaderNode { public: SHADER_NODE_CLASS(MathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float value1; float value2; @@ -830,7 +838,7 @@ class VectorMathNode : public ShaderNode { public: SHADER_NODE_CLASS(VectorMathNode) virtual int get_group() { return NODE_GROUP_LEVEL_1; } - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); float3 vector1; float3 vector2; @@ -852,7 +860,7 @@ public: class BumpNode : public ShaderNode { public: SHADER_NODE_CLASS(BumpNode) - bool constant_fold(ShaderGraph *graph, ShaderOutput *socket, ShaderInput *optimized); + void constant_fold(const ConstantFolder& folder); bool has_spatial_varying() { return true; } virtual int get_feature() { return NODE_FEATURE_BUMP; @@ -868,26 +876,30 @@ public: float distance; }; -class RGBCurvesNode : public ShaderNode { +class CurvesNode : public ShaderNode { public: - SHADER_NODE_CLASS(RGBCurvesNode) + explicit CurvesNode(const NodeType *node_type); + SHADER_NODE_BASE_CLASS(CurvesNode); virtual int get_group() { return NODE_GROUP_LEVEL_3; } + bool has_spatial_varying() { return true; } + void compile(SVMCompiler& compiler, int type, ShaderInput *value_in, ShaderOutput *value_out); + void compile(OSLCompiler& compiler, const char *name); + array<float3> curves; float min_x, max_x, fac; - float3 color; + float3 value; }; -class VectorCurvesNode : public ShaderNode { +class RGBCurvesNode : public CurvesNode { public: - SHADER_NODE_CLASS(VectorCurvesNode) - - virtual int get_group() { return NODE_GROUP_LEVEL_3; } + SHADER_NODE_CLASS(RGBCurvesNode) +}; - array<float3> curves; - float min_x, max_x, fac; - float3 vector; +class VectorCurvesNode : public CurvesNode { +public: + SHADER_NODE_CLASS(VectorCurvesNode) }; class RGBRampNode : public ShaderNode { @@ -912,11 +924,13 @@ public: static OSLNode *create(size_t num_inputs); ~OSLNode(); + ShaderNode *clone() const; + char* input_default_value(); void add_input(ustring name, SocketType::Type type); void add_output(ustring name, SocketType::Type type); - SHADER_NODE_BASE_CLASS(OSLNode) + SHADER_NODE_NO_CLONE_CLASS(OSLNode) /* ideally we could beter detect this, but we can't query this now */ bool has_spatial_varying() { return true; } @@ -924,9 +938,6 @@ public: string filepath; string bytecode_hash; - -private: - OSLNode(); }; class NormalMapNode : public ShaderNode { diff --git a/intern/cycles/render/object.cpp b/intern/cycles/render/object.cpp index ff1f678c2d2..662d87e8b6b 100644 --- a/intern/cycles/render/object.cpp +++ b/intern/cycles/render/object.cpp @@ -184,7 +184,7 @@ void Object::apply_transform(bool apply_to_motion) } /* tfm is not reset to identity, all code that uses it needs to check the - transform_applied boolean */ + * transform_applied boolean */ } void Object::tag_update(Scene *scene) diff --git a/intern/cycles/render/scene.cpp b/intern/cycles/render/scene.cpp index e8367e1eb36..b341837b7e8 100644 --- a/intern/cycles/render/scene.cpp +++ b/intern/cycles/render/scene.cpp @@ -263,6 +263,14 @@ Scene::MotionType Scene::need_motion(bool advanced_shading) return MOTION_NONE; } +float Scene::motion_shutter_time() +{ + if(need_motion() == Scene::MOTION_PASS) + return 2.0f; + else + return camera->shuttertime; +} + bool Scene::need_global_attribute(AttributeStandard std) { if(std == ATTR_STD_UV) diff --git a/intern/cycles/render/scene.h b/intern/cycles/render/scene.h index b34d6127118..05e807ff60c 100644 --- a/intern/cycles/render/scene.h +++ b/intern/cycles/render/scene.h @@ -63,7 +63,8 @@ public: device_vector<float4> bvh_nodes; device_vector<float4> bvh_leaf_nodes; device_vector<uint> object_node; - device_vector<float4> tri_storage; + device_vector<uint> prim_tri_index; + device_vector<float4> prim_tri_verts; device_vector<uint> prim_type; device_vector<uint> prim_visibility; device_vector<uint> prim_index; @@ -72,8 +73,7 @@ public: /* mesh */ device_vector<uint> tri_shader; device_vector<float4> tri_vnormal; - device_vector<float4> tri_vindex; - device_vector<float4> tri_verts; + device_vector<uint4> tri_vindex; device_vector<float4> curves; device_vector<float4> curve_keys; @@ -113,6 +113,8 @@ public: device_vector<float4> tex_float4_image[TEX_NUM_FLOAT4_CPU]; device_vector<float> tex_float_image[TEX_NUM_FLOAT_CPU]; device_vector<uchar> tex_byte_image[TEX_NUM_BYTE_CPU]; + device_vector<half4> tex_half4_image[TEX_NUM_HALF4_CPU]; + device_vector<half> tex_half_image[TEX_NUM_HALF_CPU]; /* opencl images */ device_vector<uchar4> tex_image_byte4_packed; @@ -134,6 +136,7 @@ public: BVH_NUM_TYPES, } bvh_type; bool use_bvh_spatial_split; + bool use_bvh_unaligned_nodes; bool use_qbvh; bool persistent_data; @@ -142,6 +145,7 @@ public: shadingsystem = SHADINGSYSTEM_SVM; bvh_type = BVH_DYNAMIC; use_bvh_spatial_split = false; + use_bvh_unaligned_nodes = true; use_qbvh = false; persistent_data = false; } @@ -150,6 +154,7 @@ public: { return !(shadingsystem == params.shadingsystem && bvh_type == params.bvh_type && use_bvh_spatial_split == params.use_bvh_spatial_split + && use_bvh_unaligned_nodes == params.use_bvh_unaligned_nodes && use_qbvh == params.use_qbvh && persistent_data == params.persistent_data); } }; @@ -208,6 +213,7 @@ public: enum MotionType { MOTION_NONE = 0, MOTION_PASS, MOTION_BLUR }; MotionType need_motion(bool advanced_shading = true); + float motion_shutter_time(); bool need_update(); bool need_reset(); diff --git a/intern/cycles/util/util_boundbox.h b/intern/cycles/util/util_boundbox.h index cef5adc0a61..599222da9c5 100644 --- a/intern/cycles/util/util_boundbox.h +++ b/intern/cycles/util/util_boundbox.h @@ -151,7 +151,7 @@ public: (isfinite(max.x) && isfinite(max.y) && isfinite(max.z)); } - BoundBox transformed(const Transform *tfm) + BoundBox transformed(const Transform *tfm) const { BoundBox result = BoundBox::empty; diff --git a/intern/cycles/util/util_half.h b/intern/cycles/util/util_half.h index f4bac9888a5..ae85ab3a915 100644 --- a/intern/cycles/util/util_half.h +++ b/intern/cycles/util/util_half.h @@ -85,6 +85,27 @@ ccl_device_inline void float4_store_half(half *h, float4 f, float scale) #endif } +ccl_device_inline float half_to_float(half h) +{ + float f; + + *((int*) &f) = ((h & 0x8000) << 16) | (((h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13); + + return f; +} + +ccl_device_inline float4 half4_to_float4(half4 h) +{ + float4 f; + + f.x = half_to_float(h.x); + f.y = half_to_float(h.y); + f.z = half_to_float(h.z); + f.w = half_to_float(h.w); + + return f; +} + #endif #endif diff --git a/intern/cycles/util/util_math.h b/intern/cycles/util/util_math.h index 53944ec1cc4..cfe6fa65143 100644 --- a/intern/cycles/util/util_math.h +++ b/intern/cycles/util/util_math.h @@ -545,6 +545,11 @@ ccl_device_inline float3 normalize(const float3 a) #endif +ccl_device_inline float3 saturate3(float3 a) +{ + return make_float3(saturate(a.x), saturate(a.y), saturate(a.z)); +} + ccl_device_inline float3 normalize_len(const float3 a, float *t) { *t = len(a); @@ -1329,6 +1334,15 @@ ccl_device float safe_modulo(float a, float b) return (b != 0.0f)? fmodf(a, b): 0.0f; } +ccl_device_inline float beta(float x, float y) +{ +#ifndef __KERNEL_OPENCL__ + return expf(lgammaf(x) + lgammaf(y) - lgammaf(x+y)); +#else + return expf(lgamma(x) + lgamma(y) - lgamma(x+y)); +#endif +} + /* Ray Intersection */ ccl_device bool ray_sphere_intersect( diff --git a/intern/cycles/util/util_math_fast.h b/intern/cycles/util/util_math_fast.h index deb2013daae..d3960deb3b4 100644 --- a/intern/cycles/util/util_math_fast.h +++ b/intern/cycles/util/util_math_fast.h @@ -547,6 +547,9 @@ ccl_device_inline float fast_erff(float x) const float a5 = 0.0002765672f; const float a6 = 0.0000430638f; const float a = fabsf(x); + if(a >= 12.3f) { + return copysignf(1.0f, x); + } const float b = 1.0f - (1.0f - a); /* Crush denormals. */ const float r = madd(madd(madd(madd(madd(madd(a6, b, a5), b, a4), b, a3), b, a2), b, a1), b, 1.0f); const float s = r * r; /* ^2 */ diff --git a/intern/cycles/util/util_string.cpp b/intern/cycles/util/util_string.cpp index e16a83d56d0..c1c5a6b084b 100644 --- a/intern/cycles/util/util_string.cpp +++ b/intern/cycles/util/util_string.cpp @@ -260,7 +260,11 @@ string string_human_readable_size(size_t size) string string_human_readable_number(size_t num) { - /* add thousands separators */ + if(num == 0) { + return "0"; + } + + /* Add thousands separators. */ char buf[32]; char* p = buf+31; diff --git a/intern/cycles/util/util_texture.h b/intern/cycles/util/util_texture.h index e00edc046f7..2ef47283029 100644 --- a/intern/cycles/util/util_texture.h +++ b/intern/cycles/util/util_texture.h @@ -26,40 +26,56 @@ CCL_NAMESPACE_BEGIN #define TEX_NUM_BYTE4_CPU 1024 #define TEX_NUM_FLOAT_CPU 1024 #define TEX_NUM_BYTE_CPU 1024 +#define TEX_NUM_HALF4_CPU 1024 +#define TEX_NUM_HALF_CPU 1024 #define TEX_START_FLOAT4_CPU 0 #define TEX_START_BYTE4_CPU TEX_NUM_FLOAT4_CPU #define TEX_START_FLOAT_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU) -#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_BYTE_CPU) +#define TEX_START_BYTE_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU) +#define TEX_START_HALF4_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU) +#define TEX_START_HALF_CPU (TEX_NUM_FLOAT4_CPU + TEX_NUM_BYTE4_CPU + TEX_NUM_FLOAT_CPU + TEX_NUM_BYTE_CPU + TEX_NUM_HALF4_CPU) /* CUDA (Geforce 4xx and 5xx) */ #define TEX_NUM_FLOAT4_CUDA 5 #define TEX_NUM_BYTE4_CUDA 88 #define TEX_NUM_FLOAT_CUDA 0 #define TEX_NUM_BYTE_CUDA 0 +#define TEX_NUM_HALF4_CUDA 0 +#define TEX_NUM_HALF_CUDA 0 #define TEX_START_FLOAT4_CUDA 0 #define TEX_START_BYTE4_CUDA TEX_NUM_FLOAT4_CUDA #define TEX_START_FLOAT_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA) -#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_BYTE_CUDA) +#define TEX_START_BYTE_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA) +#define TEX_START_HALF4_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA) +#define TEX_START_HALF_CUDA (TEX_NUM_FLOAT4_CUDA + TEX_NUM_BYTE4_CUDA + TEX_NUM_FLOAT_CUDA + TEX_NUM_BYTE_CUDA + TEX_NUM_HALF4_CUDA) /* CUDA (Kepler, Geforce 6xx and above) */ #define TEX_NUM_FLOAT4_CUDA_KEPLER 1024 #define TEX_NUM_BYTE4_CUDA_KEPLER 1024 #define TEX_NUM_FLOAT_CUDA_KEPLER 1024 #define TEX_NUM_BYTE_CUDA_KEPLER 1024 +#define TEX_NUM_HALF4_CUDA_KEPLER 0 +#define TEX_NUM_HALF_CUDA_KEPLER 0 #define TEX_START_FLOAT4_CUDA_KEPLER 0 #define TEX_START_BYTE4_CUDA_KEPLER TEX_NUM_FLOAT4_CUDA_KEPLER #define TEX_START_FLOAT_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER) -#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) +#define TEX_START_BYTE_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER) +#define TEX_START_HALF4_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER) +#define TEX_START_HALF_CUDA_KEPLER (TEX_NUM_FLOAT4_CUDA_KEPLER + TEX_NUM_BYTE4_CUDA_KEPLER + TEX_NUM_FLOAT_CUDA_KEPLER + TEX_NUM_BYTE_CUDA_KEPLER + TEX_NUM_HALF4_CUDA_KEPLER) /* OpenCL */ #define TEX_NUM_FLOAT4_OPENCL 1024 #define TEX_NUM_BYTE4_OPENCL 1024 #define TEX_NUM_FLOAT_OPENCL 0 #define TEX_NUM_BYTE_OPENCL 0 +#define TEX_NUM_HALF4_OPENCL 0 +#define TEX_NUM_HALF_OPENCL 0 #define TEX_START_FLOAT4_OPENCL 0 #define TEX_START_BYTE4_OPENCL TEX_NUM_FLOAT4_OPENCL #define TEX_START_FLOAT_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL) -#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_BYTE_OPENCL) +#define TEX_START_BYTE_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL) +#define TEX_START_HALF4_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL) +#define TEX_START_HALF_OPENCL (TEX_NUM_FLOAT4_OPENCL + TEX_NUM_BYTE4_OPENCL + TEX_NUM_FLOAT_OPENCL + TEX_NUM_BYTE_OPENCL + TEX_NUM_HALF4_OPENCL) /* Color to use when textures are not found. */ diff --git a/intern/cycles/util/util_transform.h b/intern/cycles/util/util_transform.h index f01db64a79b..6fed18a3db8 100644 --- a/intern/cycles/util/util_transform.h +++ b/intern/cycles/util/util_transform.h @@ -127,6 +127,19 @@ ccl_device_inline Transform make_transform(float a, float b, float c, float d, return t; } +/* Constructs a coordinate frame from a normalized normal. */ +ccl_device_inline Transform make_transform_frame(float3 N) +{ + const float3 dx0 = cross(make_float3(1.0f, 0.0f, 0.0f), N); + const float3 dx1 = cross(make_float3(0.0f, 1.0f, 0.0f), N); + const float3 dx = normalize((dot(dx0,dx0) > dot(dx1,dx1))? dx0: dx1); + const float3 dy = normalize(cross(N, dx)); + return make_transform(dx.x, dx.y, dx.z, 0.0f, + dy.x, dy.y, dy.z, 0.0f, + N.x , N.y, N.z, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + #ifndef __KERNEL_GPU__ ccl_device_inline Transform operator*(const Transform a, const Transform b) diff --git a/intern/cycles/util/util_types.h b/intern/cycles/util/util_types.h index 972befa185b..257c6ad7491 100644 --- a/intern/cycles/util/util_types.h +++ b/intern/cycles/util/util_types.h @@ -37,6 +37,7 @@ #define ccl_device_noinline static #define ccl_global #define ccl_constant +#define ccl_restrict __restrict #define __KERNEL_WITH_SSE_ALIGN__ #if defined(_WIN32) && !defined(FREE_WINDOWS) diff --git a/intern/decklink/DeckLinkAPI.cpp b/intern/decklink/DeckLinkAPI.cpp index 73a1264176b..aff25af70eb 100644 --- a/intern/decklink/DeckLinkAPI.cpp +++ b/intern/decklink/DeckLinkAPI.cpp @@ -15,19 +15,19 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ /** \file decklink/DeckLinkAPI.cpp -* \ingroup decklink -*/ + * \ingroup decklink + */ #include "DeckLinkAPI.h" diff --git a/intern/decklink/DeckLinkAPI.h b/intern/decklink/DeckLinkAPI.h index f6d2b79f53e..2a429c18c3c 100644 --- a/intern/decklink/DeckLinkAPI.h +++ b/intern/decklink/DeckLinkAPI.h @@ -15,19 +15,19 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ /** \file decklink/DeckLinkAPI.h -* \ingroup decklink -*/ + * \ingroup decklink + */ #ifndef __DECKLINKAPI_H__ #define __DECKLINKAPI_H__ diff --git a/intern/ghost/GHOST_Types.h b/intern/ghost/GHOST_Types.h index 7e77ba3a41f..0dd5d15b011 100644 --- a/intern/ghost/GHOST_Types.h +++ b/intern/ghost/GHOST_Types.h @@ -530,7 +530,7 @@ typedef struct { #ifdef _WIN32 -typedef long GHOST_TEmbedderWindowID; +typedef void* GHOST_TEmbedderWindowID; #endif // _WIN32 #ifndef _WIN32 diff --git a/intern/ghost/intern/GHOST_ContextGLX.cpp b/intern/ghost/intern/GHOST_ContextGLX.cpp index d4f67da1242..9ac61db4041 100644 --- a/intern/ghost/intern/GHOST_ContextGLX.cpp +++ b/intern/ghost/intern/GHOST_ContextGLX.cpp @@ -155,15 +155,7 @@ void GHOST_ContextGLX::initContextGLXEW() GHOST_TSuccess GHOST_ContextGLX::initializeDrawingContext() { -#ifdef WITH_X11_XINPUT - /* use our own event handlers to avoid exiting blender, - * this would happen for eg: - * if you open blender, unplug a tablet, then open a new window. */ - XErrorHandler old_handler = XSetErrorHandler (GHOST_X11_ApplicationErrorHandler ); - XIOErrorHandler old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); -#endif - - + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); /* -------------------------------------------------------------------- */ /* Begin Inline Glew */ @@ -350,11 +342,8 @@ const bool GLXEW_ARB_create_context_robustness = success = GHOST_kFailure; } -#ifdef WITH_X11_XINPUT - /* Restore handler */ - XSetErrorHandler (old_handler); - XSetIOErrorHandler(old_handler_io); -#endif + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); return success; } diff --git a/intern/ghost/intern/GHOST_ContextWGL.cpp b/intern/ghost/intern/GHOST_ContextWGL.cpp index eeb6a2469ee..abce3ea6588 100644 --- a/intern/ghost/intern/GHOST_ContextWGL.cpp +++ b/intern/ghost/intern/GHOST_ContextWGL.cpp @@ -707,6 +707,7 @@ int GHOST_ContextWGL::choose_pixel_format( PIXELFORMATDESCRIPTOR preferredPFD = { sizeof(PIXELFORMATDESCRIPTOR), /* size */ 1, /* version */ + (DWORD) ( PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW | PFD_SWAP_COPY | /* support swap copy */ @@ -717,16 +718,16 @@ int GHOST_ContextWGL::choose_pixel_format( needAlpha ? PFD_SUPPORT_COMPOSITION : /* support composition for transparent background */ #endif 0 - ), + )), PFD_TYPE_RGBA, /* color type */ - (needAlpha ? 32 : 24), /* preferred color depth */ + (BYTE) (needAlpha ? 32 : 24), /* preferred color depth */ 0, 0, 0, 0, 0, 0, /* color bits (ignored) */ - needAlpha ? 8 : 0, /* alpha buffer */ + (BYTE) (needAlpha ? 8 : 0), /* alpha buffer */ 0, /* alpha shift (ignored) */ 0, /* no accumulation buffer */ 0, 0, 0, 0, /* accum bits (ignored) */ 24, /* depth buffer */ - needStencil ? 8 : 0, /* stencil buffer */ + (BYTE) (needStencil ? 8 : 0), /* stencil buffer */ 0, /* no auxiliary buffers */ PFD_MAIN_PLANE, /* main layer */ 0, /* reserved */ diff --git a/intern/ghost/intern/GHOST_ImeWin32.cpp b/intern/ghost/intern/GHOST_ImeWin32.cpp index af5a2ed7097..96bd12faef8 100644 --- a/intern/ghost/intern/GHOST_ImeWin32.cpp +++ b/intern/ghost/intern/GHOST_ImeWin32.cpp @@ -64,7 +64,7 @@ bool GHOST_ImeWin32::SetInputLanguage() * while composing a text. */ HKL keyboard_layout = ::GetKeyboardLayout(0); - input_language_id_ = reinterpret_cast<LANGID>(keyboard_layout); + input_language_id_ = LOWORD(keyboard_layout); ime_status_ = ::ImmIsIME(keyboard_layout); return ime_status_; } diff --git a/intern/ghost/intern/GHOST_SystemX11.cpp b/intern/ghost/intern/GHOST_SystemX11.cpp index aeda95d5d4d..6f349543eed 100644 --- a/intern/ghost/intern/GHOST_SystemX11.cpp +++ b/intern/ghost/intern/GHOST_SystemX11.cpp @@ -73,6 +73,10 @@ /* for debugging - so we can breakpoint X11 errors */ // #define USE_X11_ERROR_HANDLERS +#ifdef WITH_X11_XINPUT +# define USE_XINPUT_HOTPLUG +#endif + /* see [#34039] Fix Alt key glitch on Unity desktop */ #define USE_UNITY_WORKAROUND @@ -169,11 +173,36 @@ GHOST_SystemX11( } #ifdef WITH_X11_XINPUT + /* detect if we have xinput (for reuse) */ + { + memset(&m_xinput_version, 0, sizeof(m_xinput_version)); + XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + if (version && (version != (XExtensionVersion *)NoSuchExtension)) { + if (version->present) { + m_xinput_version = *version; + } + XFree(version); + } + } + +#ifdef USE_XINPUT_HOTPLUG + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + DevicePresence(m_display, xi_presence, class_presence); + XSelectExtensionEvent( + m_display, + RootWindow(m_display, DefaultScreen(m_display)), + &class_presence, 1); + (void)xi_presence; + } +#endif /* USE_XINPUT_HOTPLUG */ + /* initialize incase X11 fails to load */ memset(&m_xtablet, 0, sizeof(m_xtablet)); - initXInputDevices(); -#endif + refreshXInputDevices(); +#endif /* WITH_X11_XINPUT */ } GHOST_SystemX11:: @@ -627,8 +656,13 @@ static bool checkTabletProximity(Display *display, XDevice *device) return false; } + /* needed since unplugging will abort() without this */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); + state = XQueryDeviceState(display, device); + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); + if (state) { XInputClass *cls = state->data; // printf("%d class%s :\n", state->num_classes, @@ -661,6 +695,41 @@ GHOST_SystemX11::processEvent(XEvent *xe) GHOST_WindowX11 *window = findGhostWindow(xe->xany.window); GHOST_Event *g_event = NULL; +#ifdef USE_XINPUT_HOTPLUG + /* Hot-Plug support */ + if (m_xinput_version.present) { + XEventClass class_presence; + int xi_presence; + + DevicePresence(m_display, xi_presence, class_presence); + (void)class_presence; + + if (xe->type == xi_presence) { + XDevicePresenceNotifyEvent *notify_event = (XDevicePresenceNotifyEvent *)xe; + if ((notify_event->devchange == DeviceEnabled) || + (notify_event->devchange == DeviceDisabled) || + (notify_event->devchange == DeviceAdded) || + (notify_event->devchange == DeviceRemoved)) + { + refreshXInputDevices(); + + /* update all window events */ + { + vector<GHOST_IWindow *> & win_vec = m_windowManager->getWindows(); + vector<GHOST_IWindow *>::iterator win_it = win_vec.begin(); + vector<GHOST_IWindow *>::const_iterator win_end = win_vec.end(); + + for (; win_it != win_end; ++win_it) { + GHOST_WindowX11 *window = static_cast<GHOST_WindowX11 *>(*win_it); + window->refreshXInputDevices(); + } + } + } + } + } +#endif /* USE_XINPUT_HOTPLUG */ + + if (!window) { return; } @@ -680,7 +749,6 @@ GHOST_SystemX11::processEvent(XEvent *xe) } } #endif /* WITH_X11_XINPUT */ - switch (xe->type) { case Expose: { @@ -1917,11 +1985,8 @@ GHOST_TSuccess GHOST_SystemX11::pushDragDropEvent(GHOST_TEventType eventType, ); } #endif - -#if defined(USE_X11_ERROR_HANDLERS) || defined(WITH_X11_XINPUT) -/* +/** * These callbacks can be used for debugging, so we can breakpoint on an X11 error. - * * Dummy function to get around IO Handler exiting if device invalid * Basically it will not crash blender now if you have a X device that @@ -1952,7 +2017,6 @@ int GHOST_X11_ApplicationIOErrorHandler(Display * /*display*/) /* No exit! - but keep lint happy */ return 0; } -#endif #ifdef WITH_X11_XINPUT /* These C functions are copied from Wine 1.1.13's wintab.c */ @@ -2049,23 +2113,27 @@ static BOOL is_eraser(const char *name, const char *type) #undef FALSE /* end code copied from wine */ -void GHOST_SystemX11::initXInputDevices() +void GHOST_SystemX11::refreshXInputDevices() { - static XErrorHandler old_handler = (XErrorHandler) 0; - static XIOErrorHandler old_handler_io = (XIOErrorHandler) 0; + if (m_xinput_version.present) { + + if (m_xtablet.StylusDevice) { + XCloseDevice(m_display, m_xtablet.StylusDevice); + m_xtablet.StylusDevice = NULL; + } + + if (m_xtablet.EraserDevice) { + XCloseDevice(m_display, m_xtablet.EraserDevice); + m_xtablet.EraserDevice = NULL; + } - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); + /* Install our error handler to override Xlib's termination behavior */ + GHOST_X11_ERROR_HANDLERS_OVERRIDE(handler_store); - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { + { int device_count; XDeviceInfo *device_info = XListInputDevices(m_display, &device_count); - m_xtablet.StylusDevice = NULL; - m_xtablet.EraserDevice = NULL; - /* Install our error handler to override Xlib's termination behavior */ - old_handler = XSetErrorHandler(GHOST_X11_ApplicationErrorHandler); - old_handler_io = XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler); for (int i = 0; i < device_count; ++i) { char *device_type = device_info[i].type ? XGetAtomName(m_display, device_info[i].type) : NULL; @@ -2124,13 +2192,10 @@ void GHOST_SystemX11::initXInputDevices() } } - /* Restore handler */ - (void) XSetErrorHandler(old_handler); - (void) XSetIOErrorHandler(old_handler_io); - XFreeDeviceList(device_info); } - XFree(version); + + GHOST_X11_ERROR_HANDLERS_RESTORE(handler_store); } } diff --git a/intern/ghost/intern/GHOST_SystemX11.h b/intern/ghost/intern/GHOST_SystemX11.h index a0088dbe8f0..e60cab6a194 100644 --- a/intern/ghost/intern/GHOST_SystemX11.h +++ b/intern/ghost/intern/GHOST_SystemX11.h @@ -52,6 +52,20 @@ int GHOST_X11_ApplicationErrorHandler(Display *display, XErrorEvent *theEvent); int GHOST_X11_ApplicationIOErrorHandler(Display *display); +#define GHOST_X11_ERROR_HANDLERS_OVERRIDE(var) \ + struct { \ + XErrorHandler handler; \ + XIOErrorHandler handler_io; \ + } var = { \ + XSetErrorHandler(GHOST_X11_ApplicationErrorHandler), \ + XSetIOErrorHandler(GHOST_X11_ApplicationIOErrorHandler), \ + } + +#define GHOST_X11_ERROR_HANDLERS_RESTORE(var) \ + { \ + (void)XSetErrorHandler(var.handler); \ + (void)XSetIOErrorHandler(var.handler_io); \ + } ((void)0) class GHOST_WindowX11; @@ -328,6 +342,10 @@ public: #endif } m_atom; +#ifdef WITH_X11_XINPUT + XExtensionVersion m_xinput_version; +#endif + private: Display *m_display; @@ -367,7 +385,7 @@ private: #endif #ifdef WITH_X11_XINPUT - void initXInputDevices(); + void refreshXInputDevices(); #endif GHOST_WindowX11 * diff --git a/intern/ghost/intern/GHOST_WindowWin32.cpp b/intern/ghost/intern/GHOST_WindowWin32.cpp index c9bcb38ab68..6a27d7aadf9 100644 --- a/intern/ghost/intern/GHOST_WindowWin32.cpp +++ b/intern/ghost/intern/GHOST_WindowWin32.cpp @@ -95,31 +95,6 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, m_parentWindowHwnd(parentwindowhwnd), m_debug_context(is_debug) { - OSVERSIONINFOEX versionInfo; - bool hasMinVersionForTaskbar = false; - - ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX)); - - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - if (!GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); - if (GetVersionEx((OSVERSIONINFO *)&versionInfo)) { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - } - else { - if ((versionInfo.dwMajorVersion == 6 && versionInfo.dwMinorVersion >= 1) || - (versionInfo.dwMajorVersion >= 7)) - { - hasMinVersionForTaskbar = true; - } - } - if (state != GHOST_kWindowStateFullScreen) { RECT rect; MONITORINFO monitor; @@ -341,11 +316,7 @@ GHOST_WindowWin32::GHOST_WindowWin32(GHOST_SystemWin32 *system, } } } - - if (hasMinVersionForTaskbar) - CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList, (LPVOID *)&m_Bar); - else - m_Bar = NULL; + CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (LPVOID *)&m_Bar); } diff --git a/intern/ghost/intern/GHOST_WindowX11.cpp b/intern/ghost/intern/GHOST_WindowX11.cpp index a12ecec6371..fd002cec80c 100644 --- a/intern/ghost/intern/GHOST_WindowX11.cpp +++ b/intern/ghost/intern/GHOST_WindowX11.cpp @@ -566,7 +566,7 @@ GHOST_WindowX11(GHOST_SystemX11 *system, } #ifdef WITH_X11_XINPUT - initXInputDevices(); + refreshXInputDevices(); m_tabletData.Active = GHOST_kTabletModeNone; #endif @@ -633,45 +633,40 @@ bool GHOST_WindowX11::createX11_XIC() #endif #ifdef WITH_X11_XINPUT -void GHOST_WindowX11::initXInputDevices() +void GHOST_WindowX11::refreshXInputDevices() { - XExtensionVersion *version = XGetExtensionVersion(m_display, INAME); - - if (version && (version != (XExtensionVersion *)NoSuchExtension)) { - if (version->present) { - GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); - XEventClass xevents[8], ev; - int dcount = 0; - - /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets - * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, - * otherwise we do not get any tablet motion event once pen is pressed... See T43367. - */ - - if (xtablet.StylusDevice) { - DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); - if (ev) xevents[dcount++] = ev; - } - if (xtablet.EraserDevice) { - DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); - if (ev) xevents[dcount++] = ev; - DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); - if (ev) xevents[dcount++] = ev; - ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); - if (ev) xevents[dcount++] = ev; - } + if (m_system->m_xinput_version.present) { + GHOST_SystemX11::GHOST_TabletX11 &xtablet = m_system->GetXTablet(); + XEventClass xevents[8], ev; + int dcount = 0; + + /* With modern XInput (xlib 1.6.2 at least and/or evdev 2.9.0) and some 'no-name' tablets + * like 'UC-LOGIC Tablet WP5540U', we also need to 'select' ButtonPress for motion event, + * otherwise we do not get any tablet motion event once pen is pressed... See T43367. + */ - XSelectExtensionEvent(m_display, m_window, xevents, dcount); + if (xtablet.StylusDevice) { + DeviceMotionNotify(xtablet.StylusDevice, xtablet.MotionEvent, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.StylusDevice, xtablet.PressEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.StylusDevice, xtablet.ProxInEvent, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.StylusDevice, xtablet.ProxOutEvent, ev); + if (ev) xevents[dcount++] = ev; } - XFree(version); + if (xtablet.EraserDevice) { + DeviceMotionNotify(xtablet.EraserDevice, xtablet.MotionEventEraser, ev); + if (ev) xevents[dcount++] = ev; + DeviceButtonPress(xtablet.EraserDevice, xtablet.PressEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityIn(xtablet.EraserDevice, xtablet.ProxInEventEraser, ev); + if (ev) xevents[dcount++] = ev; + ProximityOut(xtablet.EraserDevice, xtablet.ProxOutEventEraser, ev); + if (ev) xevents[dcount++] = ev; + } + + XSelectExtensionEvent(m_display, m_window, xevents, dcount); } } diff --git a/intern/ghost/intern/GHOST_WindowX11.h b/intern/ghost/intern/GHOST_WindowX11.h index 0738e3d47b8..9380aa9d631 100644 --- a/intern/ghost/intern/GHOST_WindowX11.h +++ b/intern/ghost/intern/GHOST_WindowX11.h @@ -212,6 +212,10 @@ public: bool createX11_XIC(); #endif +#ifdef WITH_X11_XINPUT + void refreshXInputDevices(); +#endif + #ifdef WITH_XDND GHOST_DropTargetX11 *getDropTarget() { @@ -315,10 +319,6 @@ private: Cursor getEmptyCursor( ); - -#ifdef WITH_X11_XINPUT - void initXInputDevices(); -#endif Window m_window; Display *m_display; diff --git a/intern/gpudirect/dvpapi.cpp b/intern/gpudirect/dvpapi.cpp index 8ae5cdbf17b..56b58e0a348 100644 --- a/intern/gpudirect/dvpapi.cpp +++ b/intern/gpudirect/dvpapi.cpp @@ -1,33 +1,33 @@ /* -* ***** BEGIN GPL LICENSE BLOCK ***** -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -* The Original Code is Copyright (C) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. -* -* ***** END GPL LICENSE BLOCK ***** -*/ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ /** \file gpudirect/dvpapi.c -* \ingroup gpudirect -*/ + * \ingroup gpudirect + */ #ifdef WIN32 diff --git a/intern/gpudirect/dvpapi.h b/intern/gpudirect/dvpapi.h index 4cc259f0fe8..cafc4e862ae 100644 --- a/intern/gpudirect/dvpapi.h +++ b/intern/gpudirect/dvpapi.h @@ -1,33 +1,33 @@ /* -* ***** BEGIN GPL LICENSE BLOCK ***** -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -* The Original Code is Copyright (C) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. -* -* ***** END GPL LICENSE BLOCK ***** -*/ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. + * + * ***** END GPL LICENSE BLOCK ***** + */ /** \file gpudirect/dvpapi.h -* \ingroup gpudirect -*/ + * \ingroup gpudirect + */ #ifndef __DVPAPI_H__ #define __DVPAPI_H__ diff --git a/intern/guardedalloc/test/simpletest/memtest.c b/intern/guardedalloc/test/simpletest/memtest.c index 841b47bd4f1..79d55dd02cc 100644 --- a/intern/guardedalloc/test/simpletest/memtest.c +++ b/intern/guardedalloc/test/simpletest/memtest.c @@ -26,7 +26,6 @@ */ /** - * Copyright (C) 2001 NaN Technologies B.V. * Simple test of memory. */ diff --git a/intern/libmv/libmv/multiview/projection.h b/intern/libmv/libmv/multiview/projection.h index 3220bc2dbbc..8f304f31ec6 100644 --- a/intern/libmv/libmv/multiview/projection.h +++ b/intern/libmv/libmv/multiview/projection.h @@ -122,7 +122,7 @@ inline void Project(const Mat34 &P, const Vec3 &X, Vec3 *x) { inline void Project(const Mat34 &P, const Vec3 &X, Vec2 *x) { Vec3 hx; - Project(P, X, x); + Project(P, X, &hx); *x = hx.head<2>() / hx(2); } diff --git a/intern/libmv/libmv/numeric/numeric.h b/intern/libmv/libmv/numeric/numeric.h index 20a4a29e5ba..a42dab8c7a2 100644 --- a/intern/libmv/libmv/numeric/numeric.h +++ b/intern/libmv/libmv/numeric/numeric.h @@ -148,7 +148,7 @@ using Eigen::Matrix; // A = U * diag(s) * VT // template <typename TMat, typename TVec> -inline void SVD(TMat *A, Vec *s, Mat *U, Mat *VT) { +inline void SVD(TMat * /*A*/, Vec * /*s*/, Mat * /*U*/, Mat * /*VT*/) { assert(0); } diff --git a/intern/opensubdiv/opensubdiv_converter.cc b/intern/opensubdiv/opensubdiv_converter.cc index 3fadde68d32..0ad72c88a12 100644 --- a/intern/opensubdiv/opensubdiv_converter.cc +++ b/intern/opensubdiv/opensubdiv_converter.cc @@ -332,7 +332,6 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog else { /* Special handle of non-manifold vertex. */ for (int i = 0; i < num_vert_edges; ++i) { - bool start_found = false; edge_start = vert_edges[i]; IndexArray edge_faces = getBaseEdgeFaces(refiner, edge_start); if (edge_faces.size() == 1) { @@ -343,14 +342,10 @@ inline bool TopologyRefinerFactory<OpenSubdiv_Converter>::assignComponentTopolog face_edges = getBaseFaceEdges(refiner, face_start); face_vert_start = findInArray(face_verts, vert); if (edge_start == face_edges[face_vert_start]) { - start_found = true; break; } } } - if (start_found) { - break; - } /* Reset indices for sanity check below. */ face_start = edge_start = face_vert_start = -1; } diff --git a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py index 636b6b0f46b..98a117e95a6 100644 --- a/release/scripts/modules/bl_i18n_utils/utils_spell_check.py +++ b/release/scripts/modules/bl_i18n_utils/utils_spell_check.py @@ -58,7 +58,6 @@ class SpellChecker: "vertices", # Merged words - #~ "addon", "addons", "antialiasing", "arcsine", "arccosine", "arctangent", "autoclip", @@ -127,6 +126,7 @@ class SpellChecker: "multipaint", "multires", "multiresolution", "multisampling", + "multiscatter", "multitexture", "multithreaded", "multiuser", @@ -530,6 +530,7 @@ class SpellChecker: "futura", "fx", "gfx", + "ggx", "gl", "glsl", "gpl", diff --git a/release/scripts/modules/bpy/utils/__init__.py b/release/scripts/modules/bpy/utils/__init__.py index d190ddc6f2f..a31b2939099 100644 --- a/release/scripts/modules/bpy/utils/__init__.py +++ b/release/scripts/modules/bpy/utils/__init__.py @@ -52,15 +52,15 @@ __all__ = ( ) from _bpy import ( + _utils_units as units, + blend_paths, escape_identifier, register_class, - unregister_class, - blend_paths, resource_path, + script_paths as _bpy_script_paths, + unregister_class, + user_resource as _user_resource, ) -from _bpy import script_paths as _bpy_script_paths -from _bpy import user_resource as _user_resource -from _bpy import _utils_units as units import bpy as _bpy import os as _os @@ -641,11 +641,10 @@ def unregister_module(module, verbose=False): # we start with the built-in default mapping def _blender_default_map(): - import sys import rna_manual_reference as ref_mod ret = (ref_mod.url_manual_prefix, ref_mod.url_manual_mapping) # avoid storing in memory - del sys.modules["rna_manual_reference"] + del _sys.modules["rna_manual_reference"] return ret # hooks for doc lookups diff --git a/release/scripts/startup/bl_operators/file.py b/release/scripts/startup/bl_operators/file.py index 64cc0aeddb3..51e079164b6 100644 --- a/release/scripts/startup/bl_operators/file.py +++ b/release/scripts/startup/bl_operators/file.py @@ -97,13 +97,9 @@ class WM_OT_previews_batch_generate(Operator): return {'RUNNING_MODAL'} def execute(self, context): - if "subprocess" in locals(): - import imp - imp.reload(preview_render) - else: - import os - import subprocess - from bl_previews_utils import bl_previews_render as preview_render + import os + import subprocess + from bl_previews_utils import bl_previews_render as preview_render context.window_manager.progress_begin(0, len(self.files)) context.window_manager.progress_update(0) @@ -210,13 +206,9 @@ class WM_OT_previews_batch_clear(Operator): return {'RUNNING_MODAL'} def execute(self, context): - if "subprocess" in locals(): - import imp - imp.reload(preview_render) - else: - import os - import subprocess - from bl_previews_utils import bl_previews_render as preview_render + import os + import subprocess + from bl_previews_utils import bl_previews_render as preview_render context.window_manager.progress_begin(0, len(self.files)) context.window_manager.progress_update(0) diff --git a/release/scripts/startup/bl_operators/object.py b/release/scripts/startup/bl_operators/object.py index b89890a223c..6356da216b1 100644 --- a/release/scripts/startup/bl_operators/object.py +++ b/release/scripts/startup/bl_operators/object.py @@ -685,6 +685,91 @@ class ClearAllRestrictRender(Operator): return {'FINISHED'} +class TransformsToDeltas(Operator): + """Convert normal object transforms to delta transforms, """ \ + """any existing delta transforms will be included as well""" + bl_idname = "object.transforms_to_deltas" + bl_label = "Transforms to Deltas" + bl_options = {'REGISTER', 'UNDO'} + + mode = EnumProperty( + items=(('ALL', + "All Transforms", + "Transfer location, rotation, and scale transforms", + ), + ('LOC', + "Location", + "Transfer location transforms only", + ), + ('ROT', + "Rotation", + "Transfer rotation transforms only", + ), + ('SCALE', + "Scale", + "Transfer scale transforms only", + ), + ), + name="Mode", + description="Which transforms to transfer", + default='ALL', + ) + reset_values = BoolProperty( + name="Reset Values", + description=("Clear transform values after transferring to deltas"), + default=True, + ) + + @classmethod + def poll(cls, context): + obs = context.selected_editable_objects + return (obs is not None) + + def execute(self, context): + for obj in context.selected_editable_objects: + if self.mode in {'ALL', 'LOC'}: + self.transfer_location(obj) + + if self.mode in {'ALL', 'ROT'}: + self.transfer_rotation(obj) + + if self.mode in {'ALL', 'SCALE'}: + self.transfer_scale(obj) + + return {'FINISHED'} + + def transfer_location(self, obj): + obj.delta_location += obj.location + + if self.reset_values: + obj.location.zero() + + def transfer_rotation(self, obj): + # TODO: add transforms together... + if obj.rotation_mode == 'QUATERNION': + obj.delta_rotation_quaternion += obj.rotation_quaternion + + if self.reset_values: + obj.rotation_quaternion.identity() + elif obj.rotation_mode == 'AXIS_ANGLE': + pass # Unsupported + else: + delta = obj.delta_rotation_euler.copy() + obj.delta_rotation_euler = obj.rotation_euler + obj.delta_rotation_euler.rotate(delta) + + if self.reset_values: + obj.rotation_euler.zero() + + def transfer_scale(self, obj): + obj.delta_scale[0] *= obj.scale[0] + obj.delta_scale[1] *= obj.scale[1] + obj.delta_scale[2] *= obj.scale[2] + + if self.reset_values: + obj.scale[:] = (1, 1, 1) + + class TransformsToDeltasAnim(Operator): """Convert object animation for normal transforms to delta transforms""" bl_idname = "object.anim_transforms_to_deltas" diff --git a/release/scripts/startup/bl_operators/uvcalc_lightmap.py b/release/scripts/startup/bl_operators/uvcalc_lightmap.py index a120e2b2461..3b095c883a3 100644 --- a/release/scripts/startup/bl_operators/uvcalc_lightmap.py +++ b/release/scripts/startup/bl_operators/uvcalc_lightmap.py @@ -285,8 +285,7 @@ def lightmap_uvpack(meshes, for face_sel in face_groups: print("\nStarting unwrap") - if len(face_sel) < 4: - print("\tWarning, less then 4 faces, skipping") + if not face_sel: continue pretty_faces = [prettyface(f) for f in face_sel if f.loop_total >= 4] diff --git a/release/scripts/startup/bl_ui/properties_data_curve.py b/release/scripts/startup/bl_ui/properties_data_curve.py index 81ecd2e8db5..33af812b6c4 100644 --- a/release/scripts/startup/bl_ui/properties_data_curve.py +++ b/release/scripts/startup/bl_ui/properties_data_curve.py @@ -125,7 +125,7 @@ class DATA_PT_shape_curve(CurveButtonsPanel, Panel): col.prop(curve, "use_fill_deform") if is_curve: - col.label(text="Path / Curve-Deform:") + col.label(text="Path/Curve-Deform:") sub = col.column() subsub = sub.row() subsub.prop(curve, "use_radius") @@ -370,8 +370,11 @@ class DATA_PT_paragraph(CurveButtonsPanelText, Panel): text = context.curve - layout.label(text="Align:") - layout.prop(text, "align", expand=True) + layout.label(text="Horizontal Alignment:") + layout.prop(text, "align_x", expand=True) + + layout.label(text="Vertical Alignment:") + layout.prop(text, "align_y", expand=True) split = layout.split() diff --git a/release/scripts/startup/bl_ui/properties_data_modifier.py b/release/scripts/startup/bl_ui/properties_data_modifier.py index 2a17af9f37f..39ab3d926ac 100644 --- a/release/scripts/startup/bl_ui/properties_data_modifier.py +++ b/release/scripts/startup/bl_ui/properties_data_modifier.py @@ -155,21 +155,16 @@ class DATA_PT_modifiers(ModifierButtonsPanel, Panel): col = split.column() col.label(text="Operation:") col.prop(md, "operation", text="") + row = layout.row() + row.label("Solver:") + row.prop(md, "solver", expand=True) col = split.column() col.label(text="Object:") col.prop(md, "object", text="") - """ - layout.prop(md, "use_bmesh") - if md.use_bmesh: - box = layout.box() - box.label("BMesh Options:") - box.prop(md, "use_bmesh_separate") - box.prop(md, "use_bmesh_dissolve") - box.prop(md, "use_bmesh_connect_regions") - box.prop(md, "threshold") - """ + if md.solver == 'BMESH': + layout.prop(md, "double_threshold") def BUILD(self, layout, ob, md): split = layout.split() diff --git a/release/scripts/startup/bl_ui/properties_game.py b/release/scripts/startup/bl_ui/properties_game.py index 8baad4ea0f2..300be708049 100644 --- a/release/scripts/startup/bl_ui/properties_game.py +++ b/release/scripts/startup/bl_ui/properties_game.py @@ -404,6 +404,7 @@ class RENDER_PT_game_shading(RenderButtonsPanel, Panel): col.prop(gs, "use_glsl_lights", text="Lights") col.prop(gs, "use_glsl_shaders", text="Shaders") col.prop(gs, "use_glsl_shadows", text="Shadows") + col.prop(gs, "use_glsl_environment_lighting", text="Environment Lighting") col = split.column() col.prop(gs, "use_glsl_ramps", text="Ramps") @@ -599,9 +600,35 @@ class WORLD_PT_game_world(WorldButtonsPanel, Panel): row = layout.row() row.column().prop(world, "horizon_color") + row.column().prop(world, "zenith_color") row.column().prop(world, "ambient_color") +class WORLD_PT_game_environment_lighting(WorldButtonsPanel, Panel): + bl_label = "Environment Lighting" + COMPAT_ENGINES = {'BLENDER_GAME'} + + @classmethod + def poll(cls, context): + scene = context.scene + return (scene.world and scene.render.engine in cls.COMPAT_ENGINES) + + def draw_header(self, context): + light = context.world.light_settings + self.layout.prop(light, "use_environment_light", text="") + + def draw(self, context): + layout = self.layout + + light = context.world.light_settings + + layout.active = light.use_environment_light + + split = layout.split() + split.prop(light, "environment_energy", text="Energy") + split.prop(light, "environment_color", text="") + + class WORLD_PT_game_mist(WorldButtonsPanel, Panel): bl_label = "Mist" COMPAT_ENGINES = {'BLENDER_GAME'} diff --git a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py index a823789f2c3..ac412688fa1 100644 --- a/release/scripts/startup/bl_ui/properties_grease_pencil_common.py +++ b/release/scripts/startup/bl_ui/properties_grease_pencil_common.py @@ -63,6 +63,9 @@ class GreasePencilDrawingToolsPanel: def draw(self, context): layout = self.layout + is_3d_view = context.space_data.type == 'VIEW_3D' + is_clip_editor = context.space_data.type == 'CLIP_EDITOR' + col = layout.column(align=True) col.label(text="Draw:") @@ -85,9 +88,9 @@ class GreasePencilDrawingToolsPanel: col.separator() col.label("Data Source:") row = col.row(align=True) - if context.space_data.type == 'VIEW_3D': + if is_3d_view: row.prop(context.tool_settings, "grease_pencil_source", expand=True) - elif context.space_data.type == 'CLIP_EDITOR': + elif is_clip_editor: row.prop(context.space_data, "grease_pencil_source", expand=True) col.separator() @@ -97,19 +100,19 @@ class GreasePencilDrawingToolsPanel: gpd = context.gpencil_data - if gpd: + if gpd and not is_3d_view: layout.separator() layout.separator() col = layout.column(align=True) col.prop(gpd, "use_stroke_edit_mode", text="Enable Editing", icon='EDIT', toggle=True) - if context.space_data.type == 'VIEW_3D': + if is_3d_view: col.separator() col.separator() col.label(text="Tools:") - col.operator("gpencil.convert", text="Convert...") + col.operator_menu_enum("gpencil.convert", text="Convert to Geometry...", property="type") col.operator("view3d.ruler") @@ -133,20 +136,23 @@ class GreasePencilStrokeEditPanel: def draw(self, context): layout = self.layout - layout.label(text="Select:") - col = layout.column(align=True) - col.operator("gpencil.select_all", text="Select All") - col.operator("gpencil.select_border") - col.operator("gpencil.select_circle") + is_3d_view = context.space_data.type == 'VIEW_3D' - layout.separator() + if not is_3d_view: + layout.label(text="Select:") + col = layout.column(align=True) + col.operator("gpencil.select_all", text="Select All") + col.operator("gpencil.select_border") + col.operator("gpencil.select_circle") - col = layout.column(align=True) - col.operator("gpencil.select_linked") - col.operator("gpencil.select_more") - col.operator("gpencil.select_less") + layout.separator() - layout.separator() + col = layout.column(align=True) + col.operator("gpencil.select_linked") + col.operator("gpencil.select_more") + col.operator("gpencil.select_less") + + layout.separator() layout.label(text="Edit:") row = layout.row(align=True) @@ -160,12 +166,13 @@ class GreasePencilStrokeEditPanel: layout.separator() - col = layout.column(align=True) - col.operator("transform.translate") # icon='MAN_TRANS' - col.operator("transform.rotate") # icon='MAN_ROT' - col.operator("transform.resize", text="Scale") # icon='MAN_SCALE' + if not is_3d_view: + col = layout.column(align=True) + col.operator("transform.translate") # icon='MAN_TRANS' + col.operator("transform.rotate") # icon='MAN_ROT' + col.operator("transform.resize", text="Scale") # icon='MAN_SCALE' - layout.separator() + layout.separator() col = layout.column(align=True) col.operator("transform.bend", text="Bend") diff --git a/release/scripts/startup/bl_ui/properties_render.py b/release/scripts/startup/bl_ui/properties_render.py index 4ea1c3a5cc7..794ef5189d6 100644 --- a/release/scripts/startup/bl_ui/properties_render.py +++ b/release/scripts/startup/bl_ui/properties_render.py @@ -193,7 +193,6 @@ class RENDER_PT_antialiasing(RenderButtonsPanel, Panel): col = split.column() col.row().prop(rd, "antialiasing_samples", expand=True) sub = col.row() - sub.enabled = not rd.use_border sub.prop(rd, "use_full_sample") col = split.column() @@ -280,7 +279,7 @@ class RENDER_PT_performance(RenderButtonsPanel, Panel): col = split.column() col.label(text="Memory:") sub = col.column() - sub.enabled = not (rd.use_border or rd.use_full_sample) + sub.enabled = not rd.use_full_sample sub.prop(rd, "use_save_buffers") sub = col.column() sub.active = rd.use_compositing diff --git a/release/scripts/startup/bl_ui/space_clip.py b/release/scripts/startup/bl_ui/space_clip.py index e809ef9ffde..58bb956f653 100644 --- a/release/scripts/startup/bl_ui/space_clip.py +++ b/release/scripts/startup/bl_ui/space_clip.py @@ -950,7 +950,7 @@ class CLIP_PT_stabilization(CLIP_PT_reconstruction_panel, Panel): class CLIP_PT_proxy(CLIP_PT_clip_view_panel, Panel): bl_space_type = 'CLIP_EDITOR' bl_region_type = 'UI' - bl_label = "Proxy / Timecode" + bl_label = "Proxy/Timecode" bl_options = {'DEFAULT_CLOSED'} def draw_header(self, context): @@ -1186,8 +1186,8 @@ class CLIP_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class CLIP_MT_clip(Menu): diff --git a/release/scripts/startup/bl_ui/space_console.py b/release/scripts/startup/bl_ui/space_console.py index 327fb94cb95..4266abc5ad7 100644 --- a/release/scripts/startup/bl_ui/space_console.py +++ b/release/scripts/startup/bl_ui/space_console.py @@ -70,8 +70,8 @@ class CONSOLE_MT_console(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class CONSOLE_MT_language(Menu): diff --git a/release/scripts/startup/bl_ui/space_dopesheet.py b/release/scripts/startup/bl_ui/space_dopesheet.py index 0eeba5be369..d6d91980201 100644 --- a/release/scripts/startup/bl_ui/space_dopesheet.py +++ b/release/scripts/startup/bl_ui/space_dopesheet.py @@ -101,6 +101,7 @@ def dopesheet_filter(layout, context, genericFiltersOnly=False): if bpy.data.grease_pencil: row.prop(dopesheet, "show_gpencil", text="") + layout.prop(dopesheet, "use_datablock_sort", text="") ####################################### # DopeSheet Editor - General/Standard UI @@ -232,8 +233,8 @@ class DOPESHEET_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class DOPESHEET_MT_select(Menu): @@ -250,6 +251,8 @@ class DOPESHEET_MT_select(Menu): layout.operator("action.select_border").axis_range = False layout.operator("action.select_border", text="Border Axis Range").axis_range = True + layout.operator("action.select_circle") + layout.separator() layout.operator("action.select_column", text="Columns on Selected Keys").mode = 'KEYS' layout.operator("action.select_column", text="Column on Current Frame").mode = 'CFRA' diff --git a/release/scripts/startup/bl_ui/space_graph.py b/release/scripts/startup/bl_ui/space_graph.py index 82497f11bb1..446df9e6e79 100644 --- a/release/scripts/startup/bl_ui/space_graph.py +++ b/release/scripts/startup/bl_ui/space_graph.py @@ -129,8 +129,8 @@ class GRAPH_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class GRAPH_MT_select(Menu): @@ -154,6 +154,8 @@ class GRAPH_MT_select(Menu): props.axis_range = False props.include_handles = True + layout.operator("graph.select_circle") + layout.separator() layout.operator("graph.select_column", text="Columns on Selected Keys").mode = 'KEYS' layout.operator("graph.select_column", text="Column on Current Frame").mode = 'CFRA' diff --git a/release/scripts/startup/bl_ui/space_image.py b/release/scripts/startup/bl_ui/space_image.py index fbea07a317e..c191a4b5bdc 100644 --- a/release/scripts/startup/bl_ui/space_image.py +++ b/release/scripts/startup/bl_ui/space_image.py @@ -123,8 +123,8 @@ class IMAGE_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class IMAGE_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_logic.py b/release/scripts/startup/bl_ui/space_logic.py index 48b54feba17..1b316a3eede 100644 --- a/release/scripts/startup/bl_ui/space_logic.py +++ b/release/scripts/startup/bl_ui/space_logic.py @@ -127,8 +127,8 @@ class LOGIC_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True if __name__ == "__main__": # only for live edit. bpy.utils.register_module(__name__) diff --git a/release/scripts/startup/bl_ui/space_nla.py b/release/scripts/startup/bl_ui/space_nla.py index 64d3b427260..8fbf9bfc6ac 100644 --- a/release/scripts/startup/bl_ui/space_nla.py +++ b/release/scripts/startup/bl_ui/space_nla.py @@ -77,6 +77,7 @@ class NLA_MT_view(Menu): layout.prop(st, "show_locked_time") layout.prop(st, "show_strip_curves") + layout.prop(st, "show_local_markers") layout.separator() layout.operator("anim.previewrange_set") @@ -90,8 +91,8 @@ class NLA_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class NLA_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py index 986edc7405b..ee342265f3d 100644 --- a/release/scripts/startup/bl_ui/space_node.py +++ b/release/scripts/startup/bl_ui/space_node.py @@ -192,8 +192,8 @@ class NODE_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class NODE_MT_select(Menu): diff --git a/release/scripts/startup/bl_ui/space_outliner.py b/release/scripts/startup/bl_ui/space_outliner.py index 7b1dfb9579a..708db2eec8d 100644 --- a/release/scripts/startup/bl_ui/space_outliner.py +++ b/release/scripts/startup/bl_ui/space_outliner.py @@ -99,8 +99,8 @@ class OUTLINER_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class OUTLINER_MT_search(Menu): diff --git a/release/scripts/startup/bl_ui/space_sequencer.py b/release/scripts/startup/bl_ui/space_sequencer.py index 65fd0a43619..4d1b9104344 100644 --- a/release/scripts/startup/bl_ui/space_sequencer.py +++ b/release/scripts/startup/bl_ui/space_sequencer.py @@ -221,8 +221,8 @@ class SEQUENCER_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class SEQUENCER_MT_select(Menu): @@ -972,7 +972,7 @@ class SEQUENCER_PT_filter(SequencerButtonsPanel, Panel): class SEQUENCER_PT_proxy(SequencerButtonsPanel, Panel): - bl_label = "Proxy / Timecode" + bl_label = "Proxy/Timecode" @classmethod def poll(cls, context): diff --git a/release/scripts/startup/bl_ui/space_text.py b/release/scripts/startup/bl_ui/space_text.py index 5eb4e333130..1fd10575e07 100644 --- a/release/scripts/startup/bl_ui/space_text.py +++ b/release/scripts/startup/bl_ui/space_text.py @@ -181,8 +181,8 @@ class TEXT_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class TEXT_MT_text(Menu): diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 5b0075b4147..508e62e4f56 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -152,8 +152,8 @@ class TIME_MT_view(Menu): layout.separator() layout.operator("screen.area_dupli") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class TIME_MT_cache(Menu): diff --git a/release/scripts/startup/bl_ui/space_userpref.py b/release/scripts/startup/bl_ui/space_userpref.py index dc46aed08c0..5e4e102cbc9 100644 --- a/release/scripts/startup/bl_ui/space_userpref.py +++ b/release/scripts/startup/bl_ui/space_userpref.py @@ -489,7 +489,7 @@ class USERPREF_PT_system(Panel): col.separator() - col.label(text="Sequencer / Clip Editor:") + col.label(text="Sequencer/Clip Editor:") # currently disabled in the code # col.prop(system, "prefetch_frames") col.prop(system, "memory_cache_limit") diff --git a/release/scripts/startup/bl_ui/space_view3d.py b/release/scripts/startup/bl_ui/space_view3d.py index e8d3329c0da..5e8eaf55d0b 100644 --- a/release/scripts/startup/bl_ui/space_view3d.py +++ b/release/scripts/startup/bl_ui/space_view3d.py @@ -81,7 +81,20 @@ class VIEW3D_HT_header(Header): row.prop(toolsettings, "proportional_edit_falloff", icon_only=True) # Snap - if not obj or mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + show_snap = False + if obj is None: + show_snap = True + else: + if mode not in {'SCULPT', 'VERTEX_PAINT', 'WEIGHT_PAINT', 'TEXTURE_PAINT'}: + show_snap = True + else: + paint_settings = UnifiedPaintPanel.paint_settings(context) + if paint_settings: + brush = paint_settings.brush + if brush and brush.stroke_method == 'CURVE': + show_snap = True + + if show_snap: snap_element = toolsettings.snap_element row = layout.row(align=True) row.prop(toolsettings, "use_snap", text="") @@ -283,10 +296,6 @@ class VIEW3D_MT_transform_object(VIEW3D_MT_transform_base): layout.operator("object.randomize_transform") layout.operator("object.align") - layout.separator() - - layout.operator("object.anim_transforms_to_deltas") - # Armature EditMode extensions to Transform menu class VIEW3D_MT_transform_armature(VIEW3D_MT_transform_base): @@ -358,6 +367,7 @@ class VIEW3D_MT_snap(Menu): layout.operator("view3d.snap_selected_to_grid", text="Selection to Grid") layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor").use_offset = False layout.operator("view3d.snap_selected_to_cursor", text="Selection to Cursor (Offset)").use_offset = True + layout.operator("view3d.snap_selected_to_active", text="Selection to Active") layout.separator() @@ -458,8 +468,8 @@ class VIEW3D_MT_view(Menu): layout.operator("screen.area_dupli") layout.operator("screen.region_quadview") - layout.operator("screen.screen_full_area", text="Toggle Maximize Area") - layout.operator("screen.screen_full_area").use_hide_panels = True + layout.operator("screen.screen_full_area") + layout.operator("screen.screen_full_area", text="Toggle Fullscreen Area").use_hide_panels = True class VIEW3D_MT_view_navigation(Menu): @@ -1495,6 +1505,15 @@ class VIEW3D_MT_object_apply(Menu): props.location, props.rotation, props.scale = False, True, True layout.separator() + + layout.operator("object.transforms_to_deltas", text="Location to Deltas", text_ctxt=i18n_contexts.default).mode = 'LOC' + layout.operator("object.transforms_to_deltas", text="Rotation to Deltas", text_ctxt=i18n_contexts.default).mode = 'ROT' + layout.operator("object.transforms_to_deltas", text="Scale to Deltas", text_ctxt=i18n_contexts.default).mode = 'SCALE' + + layout.operator("object.transforms_to_deltas", text="All Transforms to Deltas", text_ctxt=i18n_contexts.default).mode = 'ALL' + layout.operator("object.anim_transforms_to_deltas") + + layout.separator() layout.operator("object.visual_transform_apply", text="Visual Transform", text_ctxt=i18n_contexts.default) layout.operator("object.duplicates_make_real") @@ -1726,6 +1745,13 @@ class VIEW3D_MT_paint_vertex(Menu): layout.operator("paint.vertex_color_smooth") layout.operator("paint.vertex_color_dirt") + layout.separator() + + layout.operator("paint.vertex_color_invert", text="Invert") + layout.operator("paint.vertex_color_levels", text="Levels") + layout.operator("paint.vertex_color_hsv", text="Hue Saturation Value") + layout.operator("paint.vertex_color_brightness_contrast", text="Bright/Contrast") + class VIEW3D_MT_hook(Menu): bl_label = "Hooks" @@ -2567,6 +2593,7 @@ class VIEW3D_MT_edit_mesh_clean(Menu): layout.separator() + layout.operator("mesh.decimate") layout.operator("mesh.dissolve_degenerate") layout.operator("mesh.dissolve_limited") layout.operator("mesh.face_make_planar") @@ -2617,7 +2644,7 @@ class VIEW3D_MT_edit_gpencil_delete(Menu): layout.separator() - layout.operator("gpencil.active_frame_delete") + layout.operator("gpencil.active_frames_delete_all") # Edit Curve diff --git a/release/scripts/startup/bl_ui/space_view3d_toolbar.py b/release/scripts/startup/bl_ui/space_view3d_toolbar.py index 49c7600c055..b0cc2c63b18 100644 --- a/release/scripts/startup/bl_ui/space_view3d_toolbar.py +++ b/release/scripts/startup/bl_ui/space_view3d_toolbar.py @@ -1532,6 +1532,15 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): def poll(cls, context): return (context.sculpt_object and context.tool_settings.sculpt) + def draw_header(self, context): + layout = self.layout + layout.operator( + "sculpt.dynamic_topology_toggle", + icon='CHECKBOX_HLT' if context.sculpt_object.use_dynamic_topology_sculpting else 'CHECKBOX_DEHLT', + text="", + emboss=False, + ) + def draw(self, context): layout = self.layout @@ -1540,11 +1549,6 @@ class VIEW3D_PT_sculpt_dyntopo(Panel, View3DPaintPanel): settings = self.paint_settings(context) brush = settings.brush - if context.sculpt_object.use_dynamic_topology_sculpting: - layout.operator("sculpt.dynamic_topology_toggle", icon='X', text="Disable Dyntopo") - else: - layout.operator("sculpt.dynamic_topology_toggle", icon='SCULPT_DYNTOPO', text="Enable Dyntopo") - col = layout.column() col.active = context.sculpt_object.use_dynamic_topology_sculpting sub = col.column(align=True) @@ -1603,7 +1607,7 @@ class VIEW3D_PT_sculpt_options(Panel, View3DPaintPanel): class VIEW3D_PT_sculpt_symmetry(Panel, View3DPaintPanel): bl_category = "Tools" - bl_label = "Symmetry / Lock" + bl_label = "Symmetry/Lock" bl_options = {'DEFAULT_CLOSED'} @classmethod diff --git a/release/scripts/templates_py/script_stub.py b/release/scripts/templates_py/external_script_stub.py index 5505ca64078..5505ca64078 100644 --- a/release/scripts/templates_py/script_stub.py +++ b/release/scripts/templates_py/external_script_stub.py diff --git a/source/blender/blenkernel/BKE_DerivedMesh.h b/source/blender/blenkernel/BKE_DerivedMesh.h index 8ccc4a6eb0e..606488f85cc 100644 --- a/source/blender/blenkernel/BKE_DerivedMesh.h +++ b/source/blender/blenkernel/BKE_DerivedMesh.h @@ -694,7 +694,7 @@ DerivedMesh *mesh_create_derived_render( CustomDataMask dataMask); DerivedMesh *getEditDerivedBMesh( - struct BMEditMesh *em, struct Object *ob, + struct BMEditMesh *em, struct Object *ob, CustomDataMask data_mask, float (*vertexCos)[3]); DerivedMesh *mesh_create_derived_index_render( @@ -723,7 +723,7 @@ DerivedMesh *mesh_create_derived_physics( CustomDataMask dataMask); DerivedMesh *editbmesh_get_derived_base( - struct Object *, struct BMEditMesh *em); + struct Object *ob, struct BMEditMesh *em, CustomDataMask data_mask); DerivedMesh *editbmesh_get_derived_cage( struct Scene *scene, struct Object *, struct BMEditMesh *em, CustomDataMask dataMask); diff --git a/source/blender/blenkernel/BKE_action.h b/source/blender/blenkernel/BKE_action.h index cb282b46bec..ac9b0b6fb10 100644 --- a/source/blender/blenkernel/BKE_action.h +++ b/source/blender/blenkernel/BKE_action.h @@ -58,13 +58,12 @@ extern "C" { struct bAction *add_empty_action(struct Main *bmain, const char name[]); /* Allocate a copy of the given Action and all its data */ -struct bAction *BKE_action_copy(struct bAction *src); +struct bAction *BKE_action_copy(struct Main *bmain, struct bAction *src); /* Deallocate all of the Action's data, but not the Action itself */ void BKE_action_free(struct bAction *act); -// XXX is this needed? -void BKE_action_make_local(struct bAction *act); +void BKE_action_make_local(struct Main *bmain, struct bAction *act, const bool force_local); /* Action API ----------------- */ diff --git a/source/blender/blenkernel/BKE_animsys.h b/source/blender/blenkernel/BKE_animsys.h index 6524afff051..983f3ce22b8 100644 --- a/source/blender/blenkernel/BKE_animsys.h +++ b/source/blender/blenkernel/BKE_animsys.h @@ -50,7 +50,8 @@ struct AnimMapper; /* AnimData API */ /* Check if the given ID-block can have AnimData */ -bool id_type_can_have_animdata(struct ID *id); +bool id_type_can_have_animdata(const short id_type); +bool id_can_have_animdata(const struct ID *id); /* Get AnimData from the given ID-block */ struct AnimData *BKE_animdata_from_id(struct ID *id); @@ -62,7 +63,7 @@ struct AnimData *BKE_animdata_add_id(struct ID *id); bool BKE_animdata_set_action(struct ReportList *reports, struct ID *id, struct bAction *act); /* Free AnimData */ -void BKE_animdata_free(struct ID *id); +void BKE_animdata_free(struct ID *id, const bool do_id_user); /* Copy AnimData */ struct AnimData *BKE_animdata_copy(struct AnimData *adt, const bool do_action); diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index cc082c084ce..bfd4a7e3dd8 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -76,8 +76,8 @@ struct bArmature *BKE_armature_from_object(struct Object *ob); int BKE_armature_bonelist_count(struct ListBase *lb); void BKE_armature_bonelist_free(struct ListBase *lb); void BKE_armature_free(struct bArmature *arm); -void BKE_armature_make_local(struct bArmature *arm); -struct bArmature *BKE_armature_copy(struct bArmature *arm); +void BKE_armature_make_local(struct Main *bmain, struct bArmature *arm, const bool force_local); +struct bArmature *BKE_armature_copy(struct Main *bmain, struct bArmature *arm); /* Bounding box. */ struct BoundBox *BKE_armature_boundbox_get(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_blender.h b/source/blender/blenkernel/BKE_blender.h index 8ce85c8e615..d2d9c763031 100644 --- a/source/blender/blenkernel/BKE_blender.h +++ b/source/blender/blenkernel/BKE_blender.h @@ -50,6 +50,11 @@ void BKE_blender_userdef_refresh(void); void BKE_blender_callback_test_break_set(void (*func)(void)); int BKE_blender_test_break(void); +/* Blenders' own atexit (avoids leaking) */ +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data); +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data); +void BKE_blender_atexit(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_blender_undo.h b/source/blender/blenkernel/BKE_blender_undo.h index cd18bd8db40..9547eeb9838 100644 --- a/source/blender/blenkernel/BKE_blender_undo.h +++ b/source/blender/blenkernel/BKE_blender_undo.h @@ -45,6 +45,8 @@ extern const char *BKE_undo_get_name(int nr, bool *r_active); extern bool BKE_undo_save_file(const char *filename); extern struct Main *BKE_undo_get_main(struct Scene **r_scene); +extern void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_brush.h b/source/blender/blenkernel/BKE_brush.h index c663458963c..4be4d95490b 100644 --- a/source/blender/blenkernel/BKE_brush.h +++ b/source/blender/blenkernel/BKE_brush.h @@ -44,8 +44,8 @@ void BKE_brush_system_exit(void); void BKE_brush_init(struct Brush *brush); struct Brush *BKE_brush_add(struct Main *bmain, const char *name, short ob_mode); struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode); -struct Brush *BKE_brush_copy(struct Brush *brush); -void BKE_brush_make_local(struct Brush *brush); +struct Brush *BKE_brush_copy(struct Main *bmain, struct Brush *brush); +void BKE_brush_make_local(struct Main *bmain, struct Brush *brush, const bool force_local); void BKE_brush_unlink(struct Main *bmain, struct Brush *brush); void BKE_brush_free(struct Brush *brush); diff --git a/source/blender/blenkernel/BKE_bvhutils.h b/source/blender/blenkernel/BKE_bvhutils.h index 7bd3ca88076..07db2217bac 100644 --- a/source/blender/blenkernel/BKE_bvhutils.h +++ b/source/blender/blenkernel/BKE_bvhutils.h @@ -43,9 +43,11 @@ struct BMEditMesh; struct MVert; struct MFace; +typedef struct LinkNode BVHCache; + /** -* struct that kepts basic information about a BVHTree build from a editmesh -*/ + * struct that kepts basic information about a BVHTree build from a editmesh + */ typedef struct BVHTreeFromEditMesh { struct BVHTree *tree; @@ -54,11 +56,13 @@ typedef struct BVHTreeFromEditMesh { BVHTree_RayCastCallback raycast_callback; BVHTree_NearestToRayCallback nearest_to_ray_callback; + struct BMEditMesh *em; + /* radius for raycast */ float sphere_radius; /* Private data */ - struct BMEditMesh *em; + bool cached; } BVHTreeFromEditMesh; @@ -118,6 +122,14 @@ BVHTree *bvhtree_from_mesh_verts_ex( const bool vert_allocated, const BLI_bitmap *mask, int verts_num_active, float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis); +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis); + BVHTree *bvhtree_from_mesh_edges( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); @@ -133,12 +145,12 @@ BVHTree *bvhtree_from_mesh_faces_ex( float epsilon, int tree_type, int axis); BVHTree *bvhtree_from_editmesh_looptri( - BVHTreeFromEditMesh *data, struct BMEditMesh *em, float epsilon, - int tree_type, int axis); + BVHTreeFromEditMesh *data, struct BMEditMesh *em, + float epsilon, int tree_type, int axis, BVHCache **bvhCache); BVHTree *bvhtree_from_editmesh_looptri_ex( BVHTreeFromEditMesh *data, struct BMEditMesh *em, const BLI_bitmap *mask, int looptri_num_active, - float epsilon, int tree_type, int axis); + float epsilon, int tree_type, int axis, BVHCache **bvhCache); BVHTree *bvhtree_from_mesh_looptri( struct BVHTreeFromMesh *data, struct DerivedMesh *mesh, float epsilon, int tree_type, int axis); @@ -165,9 +177,7 @@ float bvhtree_ray_tri_intersection( float bvhtree_sphereray_tri_intersection( const BVHTreeRay *ray, float radius, const float m_dist, const float v0[3], const float v1[3], const float v2[3]); -float nearest_point_in_tri_surface_squared( - const float v0[3], const float v1[3], const float v2[3], - const float p[3], int *v, int *e, float nearest[3]); + /** * BVHCache @@ -179,9 +189,10 @@ enum { BVHTREE_FROM_EDGES = 1, BVHTREE_FROM_FACES = 2, BVHTREE_FROM_LOOPTRI = 3, + + BVHTREE_FROM_EM_LOOPTRI = 4, }; -typedef struct LinkNode BVHCache; BVHTree *bvhcache_find(BVHCache *cache, int type); bool bvhcache_has_tree(const BVHCache *cache, const BVHTree *tree); @@ -189,4 +200,5 @@ void bvhcache_insert(BVHCache **cache_p, BVHTree *tree, int type); void bvhcache_init(BVHCache **cache_p); void bvhcache_free(BVHCache **cache_p); + #endif diff --git a/source/blender/blenkernel/BKE_camera.h b/source/blender/blenkernel/BKE_camera.h index d13a711c589..3ae0e0e1111 100644 --- a/source/blender/blenkernel/BKE_camera.h +++ b/source/blender/blenkernel/BKE_camera.h @@ -52,8 +52,8 @@ struct GPUFXSettings; void BKE_camera_init(struct Camera *cam); void *BKE_camera_add(struct Main *bmain, const char *name); -struct Camera *BKE_camera_copy(struct Camera *cam); -void BKE_camera_make_local(struct Camera *cam); +struct Camera *BKE_camera_copy(struct Main *bmain, struct Camera *cam); +void BKE_camera_make_local(struct Main *bmain, struct Camera *cam, const bool force_local); void BKE_camera_free(struct Camera *ca); /* Camera Usage */ diff --git a/source/blender/blenkernel/BKE_curve.h b/source/blender/blenkernel/BKE_curve.h index 061270b8b41..c2a0404e96e 100644 --- a/source/blender/blenkernel/BKE_curve.h +++ b/source/blender/blenkernel/BKE_curve.h @@ -66,13 +66,12 @@ typedef struct CurveCache { #define CU_DO_2DFILL(cu) ((((cu)->flag & CU_3D) == 0) && (((cu)->flag & (CU_FRONT | CU_BACK)) != 0)) /* ** Curve ** */ -void BKE_curve_unlink(struct Curve *cu); void BKE_curve_free(struct Curve *cu); void BKE_curve_editfont_free(struct Curve *cu); void BKE_curve_init(struct Curve *cu); struct Curve *BKE_curve_add(struct Main *bmain, const char *name, int type); -struct Curve *BKE_curve_copy(struct Curve *cu); -void BKE_curve_make_local(struct Curve *cu); +struct Curve *BKE_curve_copy(struct Main *bmain, struct Curve *cu); +void BKE_curve_make_local(struct Main *bmain, struct Curve *cu, const bool force_local); short BKE_curve_type_get(struct Curve *cu); void BKE_curve_type_test(struct Object *ob); void BKE_curve_curve_dimension_update(struct Curve *cu); @@ -151,6 +150,16 @@ void BKE_nurb_minmax(struct Nurb *nu, bool use_radius, float min[3], float max[3 void BKE_nurb_makeFaces(struct Nurb *nu, float *coord_array, int rowstride, int resolu, int resolv); void BKE_nurb_makeCurve(struct Nurb *nu, float *coord_array, float *tilt_array, float *radius_array, float *weight_array, int resolu, int stride); +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint); +void BKE_curve_calc_coords_axis( + const struct BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points); + void BKE_nurb_knot_calc_u(struct Nurb *nu); void BKE_nurb_knot_calc_v(struct Nurb *nu); diff --git a/source/blender/blenkernel/BKE_displist.h b/source/blender/blenkernel/BKE_displist.h index 3b096773d96..9625f05192a 100644 --- a/source/blender/blenkernel/BKE_displist.h +++ b/source/blender/blenkernel/BKE_displist.h @@ -45,10 +45,14 @@ #define DL_VERTS 7 /* dl->flag */ -#define DL_CYCL_U 1 -#define DL_CYCL_V 2 -#define DL_FRONT_CURVE 4 -#define DL_BACK_CURVE 8 +enum { + /** U/V swapped here compared with #Nurb.flagu, #Nurb.flagv and #CU_NURB_CYCLIC */ + DL_CYCL_U = (1 << 0), + DL_CYCL_V = (1 << 1), + + DL_FRONT_CURVE = (1 << 2), + DL_BACK_CURVE = (1 << 3), +}; /* prototypes */ @@ -70,7 +74,7 @@ typedef struct DispList { int charidx; int totindex; /* indexed array drawing surfaces */ - unsigned int *bevelSplitFlag; + unsigned int *bevel_split; /* BLI_bitmap */ } DispList; void BKE_displist_copy(struct ListBase *lbn, struct ListBase *lb); diff --git a/source/blender/blenkernel/BKE_global.h b/source/blender/blenkernel/BKE_global.h index 26a40597ca8..5ef5a807f63 100644 --- a/source/blender/blenkernel/BKE_global.h +++ b/source/blender/blenkernel/BKE_global.h @@ -178,6 +178,7 @@ enum { #define G_FILE_MESH_COMPAT (1 << 26) /* On write, restore paths after editing them (G_FILE_RELATIVE_REMAP) */ #define G_FILE_SAVE_COPY (1 << 27) +#define G_FILE_GLSL_NO_ENV_LIGHTING (1 << 28) #define G_FILE_FLAGS_RUNTIME (G_FILE_NO_UI | G_FILE_RELATIVE_REMAP | G_FILE_MESH_COMPAT | G_FILE_SAVE_COPY) diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 24e330d927f..6159531d8bd 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -36,6 +36,7 @@ struct bGPdata; struct bGPDlayer; struct bGPDframe; struct bGPDstroke; +struct Main; /* ------------ Grease-Pencil API ------------------ */ @@ -53,7 +54,7 @@ struct bGPdata *gpencil_data_addnew(const char name[]); struct bGPDframe *gpencil_frame_duplicate(struct bGPDframe *src); struct bGPDlayer *gpencil_layer_duplicate(struct bGPDlayer *src); -struct bGPdata *gpencil_data_duplicate(struct bGPdata *gpd, bool internal_copy); +struct bGPdata *gpencil_data_duplicate(struct Main *bmain, struct bGPdata *gpd, bool internal_copy); void gpencil_frame_delete_laststroke(struct bGPDlayer *gpl, struct bGPDframe *gpf); diff --git a/source/blender/blenkernel/BKE_group.h b/source/blender/blenkernel/BKE_group.h index 9056e48cf50..4f2c89070cb 100644 --- a/source/blender/blenkernel/BKE_group.h +++ b/source/blender/blenkernel/BKE_group.h @@ -41,9 +41,8 @@ struct Object; struct Scene; void BKE_group_free(struct Group *group); -void BKE_group_unlink(struct Main *bmain, struct Group *group); struct Group *BKE_group_add(struct Main *bmain, const char *name); -struct Group *BKE_group_copy(struct Group *group); +struct Group *BKE_group_copy(struct Main *bmain, struct Group *group); bool BKE_group_object_add(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); bool BKE_group_object_unlink(struct Group *group, struct Object *ob, struct Scene *scene, struct Base *base); struct Group *BKE_group_object_find(struct Group *group, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_icons.h b/source/blender/blenkernel/BKE_icons.h index 763a3874d4e..7839b9e2154 100644 --- a/source/blender/blenkernel/BKE_icons.h +++ b/source/blender/blenkernel/BKE_icons.h @@ -55,7 +55,7 @@ void BKE_icons_init(int first_dyn_id); /* return icon id for library object or create new icon if not found */ int BKE_icon_id_ensure(struct ID *id); -int BKE_icon_preview_ensure(struct PreviewImage *preview); +int BKE_icon_preview_ensure(struct ID *id, struct PreviewImage *preview); /* retrieve icon for id */ struct Icon *BKE_icon_get(int icon_id); diff --git a/source/blender/blenkernel/BKE_image.h b/source/blender/blenkernel/BKE_image.h index eb98268c9f0..db73b42d894 100644 --- a/source/blender/blenkernel/BKE_image.h +++ b/source/blender/blenkernel/BKE_image.h @@ -108,7 +108,7 @@ struct anim *openanim_noload(const char *name, int flags, int streamindex, char void BKE_image_de_interlace(struct Image *ima, int odd); -void BKE_image_make_local(struct Image *ima); +void BKE_image_make_local(struct Main *bmain, struct Image *ima, const bool force_local); void BKE_image_tag_time(struct Image *ima); diff --git a/source/blender/blenkernel/BKE_key.h b/source/blender/blenkernel/BKE_key.h index 1edbb455ca4..e590ff148d7 100644 --- a/source/blender/blenkernel/BKE_key.h +++ b/source/blender/blenkernel/BKE_key.h @@ -39,6 +39,7 @@ struct ListBase; struct Curve; struct Object; struct Lattice; +struct Main; struct Mesh; struct WeightsArrayCache; @@ -50,9 +51,8 @@ extern "C" { void BKE_key_free(struct Key *sc); void BKE_key_free_nolib(struct Key *key); struct Key *BKE_key_add(struct ID *id); -struct Key *BKE_key_copy(struct Key *key); +struct Key *BKE_key_copy(struct Main *bmain, struct Key *key); struct Key *BKE_key_copy_nolib(struct Key *key); -void BKE_key_make_local(struct Key *key); void BKE_key_sort(struct Key *key); void key_curve_position_weights(float t, float data[4], int type); diff --git a/source/blender/blenkernel/BKE_lamp.h b/source/blender/blenkernel/BKE_lamp.h index d830c19651f..dc977eabbb1 100644 --- a/source/blender/blenkernel/BKE_lamp.h +++ b/source/blender/blenkernel/BKE_lamp.h @@ -44,9 +44,9 @@ struct Scene; void BKE_lamp_init(struct Lamp *la); struct Lamp *BKE_lamp_add(struct Main *bmain, const char *name) ATTR_WARN_UNUSED_RESULT; -struct Lamp *BKE_lamp_copy(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; +struct Lamp *BKE_lamp_copy(struct Main *bmain, struct Lamp *la) ATTR_WARN_UNUSED_RESULT; struct Lamp *localize_lamp(struct Lamp *la) ATTR_WARN_UNUSED_RESULT; -void BKE_lamp_make_local(struct Lamp *la); +void BKE_lamp_make_local(struct Main *bmain, struct Lamp *la, const bool force_local); void BKE_lamp_free(struct Lamp *la); void lamp_drivers_update(struct Scene *scene, struct Lamp *la, float ctime); diff --git a/source/blender/blenkernel/BKE_lattice.h b/source/blender/blenkernel/BKE_lattice.h index 828a40de1c9..4f72bbecff4 100644 --- a/source/blender/blenkernel/BKE_lattice.h +++ b/source/blender/blenkernel/BKE_lattice.h @@ -47,9 +47,9 @@ struct MDeformVert; void BKE_lattice_resize(struct Lattice *lt, int u, int v, int w, struct Object *ltOb); void BKE_lattice_init(struct Lattice *lt); struct Lattice *BKE_lattice_add(struct Main *bmain, const char *name); -struct Lattice *BKE_lattice_copy(struct Lattice *lt); +struct Lattice *BKE_lattice_copy(struct Main *bmain, struct Lattice *lt); void BKE_lattice_free(struct Lattice *lt); -void BKE_lattice_make_local(struct Lattice *lt); +void BKE_lattice_make_local(struct Main *bmain, struct Lattice *lt, const bool force_local); void calc_lat_fudu(int flag, int res, float *r_fu, float *r_du); struct LatticeDeformData; diff --git a/source/blender/blenkernel/BKE_library.h b/source/blender/blenkernel/BKE_library.h index 2215fbfbd7d..3e8ede638ca 100644 --- a/source/blender/blenkernel/BKE_library.h +++ b/source/blender/blenkernel/BKE_library.h @@ -52,21 +52,22 @@ struct PropertyRNA; void *BKE_libblock_alloc_notest(short type); void *BKE_libblock_alloc(struct Main *bmain, short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_init_empty(struct ID *id); -void *BKE_libblock_copy_ex(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void *BKE_libblock_copy(struct Main *bmain, struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void *BKE_libblock_copy_nolib(struct ID *id, const bool do_action) ATTR_NONNULL(); -void *BKE_libblock_copy(struct ID *id) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); void BKE_libblock_copy_data(struct ID *id, const struct ID *id_from, const bool do_action); void BKE_libblock_relink(struct ID *id); void BKE_libblock_rename(struct Main *bmain, struct ID *id, const char *name) ATTR_NONNULL(); void BLI_libblock_ensure_unique_name(struct Main *bmain, const char *name) ATTR_NONNULL(); +struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); + +/* library_remap.c (keep here since they're general functions) */ void BKE_libblock_free(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_ex(struct Main *bmain, void *idv, bool do_id_user) ATTR_NONNULL(); void BKE_libblock_free_us(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_libblock_free_data(struct Main *bmain, struct ID *id) ATTR_NONNULL(); - -struct ID *BKE_libblock_find_name_ex(struct Main *bmain, const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); -struct ID *BKE_libblock_find_name(const short type, const char *name) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(); +void BKE_libblock_delete(struct Main *bmain, void *idv) ATTR_NONNULL(); void BKE_id_lib_local_paths(struct Main *bmain, struct Library *lib, struct ID *id); void id_lib_extern(struct ID *id); @@ -79,11 +80,11 @@ void id_us_min(struct ID *id); void id_fake_user_set(struct ID *id); void id_fake_user_clear(struct ID *id); -bool id_make_local(struct ID *id, bool test); +bool id_make_local(struct Main *bmain, struct ID *id, const bool test, const bool force_local); bool id_single_user(struct bContext *C, struct ID *id, struct PointerRNA *ptr, struct PropertyRNA *prop); -bool id_copy(struct ID *id, struct ID **newid, bool test); -bool id_unlink(struct ID *id, int test); +bool id_copy(struct Main *bmain, struct ID *id, struct ID **newid, bool test); void id_sort_by_name(struct ListBase *lb, struct ID *id); +void BKE_id_expand_local(struct ID *id); bool new_id(struct ListBase *lb, struct ID *id, const char *name); void id_clear_lib_data(struct Main *bmain, struct ID *id); @@ -119,16 +120,11 @@ void BKE_main_lib_objects_recalc_all(struct Main *bmain); /* (MAX_ID_NAME - 2) + 3 */ void BKE_id_ui_prefix(char name[66 + 1], const struct ID *id); +void BKE_library_free(struct Library *lib); + void BKE_library_make_local( struct Main *bmain, const struct Library *lib, const bool untagged_only, const bool set_fake); -typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); -typedef void (*BKE_library_free_notifier_reference_cb)(const void *); -typedef void (*BKE_library_free_editor_id_reference_cb)(const struct ID *); - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func); /* use when "" is given to new_id() */ #define ID_FALLBACK_NAME N_("Untitled") diff --git a/source/blender/blenkernel/BKE_library_query.h b/source/blender/blenkernel/BKE_library_query.h index 2e73be576f9..c5f575c8c0f 100644 --- a/source/blender/blenkernel/BKE_library_query.h +++ b/source/blender/blenkernel/BKE_library_query.h @@ -32,6 +32,7 @@ */ struct ID; +struct Main; /* Tips for the callback for cases it's gonna to modify the pointer. */ enum { @@ -40,6 +41,12 @@ enum { IDWALK_NEVER_SELF = (1 << 1), /** + * Indicates whether this is direct (i.e. by local data) or indirect (i.e. by linked data) usage. + * \note Object proxies are half-local, half-linked... + */ + IDWALK_INDIRECT_USAGE = (1 << 2), + + /** * Adjusts #ID.us reference-count. * \note keep in sync with 'newlibadr_us' use in readfile.c */ @@ -52,7 +59,7 @@ enum { enum { IDWALK_RET_NOP = 0, - IDWALK_RET_STOP_ITER = 1 << 0, /* Completly top iteration. */ + IDWALK_RET_STOP_ITER = 1 << 0, /* Completly stop iteration. */ IDWALK_RET_STOP_RECURSION = 1 << 1, /* Stop recursion, that is, do not loop over ID used by current one. */ }; @@ -75,4 +82,10 @@ void BKE_library_update_ID_link_user(struct ID *id_dst, struct ID *id_src, const int BKE_library_ID_use_ID(struct ID *id_user, struct ID *id_used); +bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used); + +bool BKE_library_ID_is_locally_used(struct Main *bmain, void *idv); +bool BKE_library_ID_is_indirectly_used(struct Main *bmain, void *idv); +void BKE_library_ID_test_usages(struct Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked); + #endif /* __BKE_LIBRARY_QUERY_H__ */ diff --git a/source/blender/blenkernel/BKE_library_remap.h b/source/blender/blenkernel/BKE_library_remap.h new file mode 100644 index 00000000000..e974b79ee66 --- /dev/null +++ b/source/blender/blenkernel/BKE_library_remap.h @@ -0,0 +1,80 @@ +/* + * ***** 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 ***** + */ +#ifndef __BKE_LIBRARY_REMAP_H__ +#define __BKE_LIBRARY_REMAP_H__ + +/** \file BKE_library_remap.h + * \ingroup bke + */ +#ifdef __cplusplus +extern "C" { +#endif + +#include "BLI_compiler_attrs.h" + +/* BKE_libblock_free, delete are declared in BKE_library.h for convenience. */ + +/* Also IDRemap->flag. */ +enum { + /* Do not remap indirect usages of IDs (that is, when user is some linked data). */ + ID_REMAP_SKIP_INDIRECT_USAGE = 1 << 0, + /* This flag should always be set, *except for 'unlink' scenarios* (only relevant when new_id == NULL). + * Basically, when unset, NEVER_NULL ID usages will keep pointing to old_id, but (if needed) old_id user count + * will still be decremented. This is mandatory for 'delete ID' case, but in all other situation this would lead + * to invalid user counts! */ + ID_REMAP_SKIP_NEVER_NULL_USAGE = 1 << 1, + /* This tells the callback func to flag with LIB_DOIT all IDs using target one with a 'never NULL' pointer + * (like e.g. Object->data). */ + ID_REMAP_FLAG_NEVER_NULL_USAGE = 1 << 2, + /* This tells the callback func to force setting IDs using target one with a 'never NULL' pointer to NULL. + * WARNING! Use with extreme care, this will leave database in broken state! */ + ID_REMAP_FORCE_NEVER_NULL_USAGE = 1 << 3, +}; + +/* Note: Requiring new_id to be non-null, this *may* not be the case ultimately, but makes things simpler for now. */ +void BKE_libblock_remap_locked( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); +void BKE_libblock_remap( + struct Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) ATTR_NONNULL(1, 2); + +void BKE_libblock_unlink( + struct Main *bmain, void *idv, + const bool do_flag_never_null, const bool do_skip_indirect) ATTR_NONNULL(); + +void BKE_libblock_relink_ex( + struct Main *bmain, void *idv, void *old_idv, void *new_idv, + const bool us_min_never_null) ATTR_NONNULL(1, 2); + + +typedef void (*BKE_library_free_window_manager_cb)(struct bContext *, struct wmWindowManager *); +typedef void (*BKE_library_free_notifier_reference_cb)(const void *); +typedef void (*BKE_library_remap_editor_id_reference_cb)(struct ID *, struct ID *); + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func); +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func); +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func); + +#ifdef __cplusplus +} +#endif + +#endif /* __BKE_LIBRARY_REMAP_H__ */ diff --git a/source/blender/blenkernel/BKE_linestyle.h b/source/blender/blenkernel/BKE_linestyle.h index e3eead4102c..e343cd29622 100644 --- a/source/blender/blenkernel/BKE_linestyle.h +++ b/source/blender/blenkernel/BKE_linestyle.h @@ -79,8 +79,6 @@ void BKE_linestyle_geometry_modifier_move(FreestyleLineStyle *linestyle, LineSty void BKE_linestyle_modifier_list_color_ramps(FreestyleLineStyle *linestyle, ListBase *listbase); char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, struct ColorBand *color_ramp); -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob); - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes); void BKE_linestyle_default_shader(const struct bContext *C, FreestyleLineStyle *linestyle); diff --git a/source/blender/blenkernel/BKE_mask.h b/source/blender/blenkernel/BKE_mask.h index 25893d54dca..97bfd0f3f07 100644 --- a/source/blender/blenkernel/BKE_mask.h +++ b/source/blender/blenkernel/BKE_mask.h @@ -123,10 +123,9 @@ void BKE_mask_point_select_set_handle(struct MaskSplinePoint *point, const eMask /* general */ struct Mask *BKE_mask_new(struct Main *bmain, const char *name); struct Mask *BKE_mask_copy_nolib(struct Mask *mask); -struct Mask *BKE_mask_copy(struct Mask *mask); +struct Mask *BKE_mask_copy(struct Main *bmain, struct Mask *mask); -void BKE_mask_free_nolib(struct Mask *mask); -void BKE_mask_free(struct Main *bmain, struct Mask *mask); +void BKE_mask_free(struct Mask *mask); void BKE_mask_coord_from_frame(float r_co[2], const float co[2], const float frame_size[2]); void BKE_mask_coord_from_movieclip(struct MovieClip *clip, struct MovieClipUser *user, float r_co[2], const float co[2]); diff --git a/source/blender/blenkernel/BKE_material.h b/source/blender/blenkernel/BKE_material.h index 852564c8d90..bbe104cd6ee 100644 --- a/source/blender/blenkernel/BKE_material.h +++ b/source/blender/blenkernel/BKE_material.h @@ -47,17 +47,17 @@ struct Scene; void init_def_material(void); void BKE_material_free(struct Material *ma); void BKE_material_free_ex(struct Material *ma, bool do_id_user); -void test_object_materials(struct Main *bmain, struct ID *id); +void test_object_materials(struct Object *ob, struct ID *id); +void test_all_objects_materials(struct Main *bmain, struct ID *id); void BKE_material_resize_object(struct Object *ob, const short totcol, bool do_id_user); void BKE_material_init(struct Material *ma); void BKE_material_remap_object(struct Object *ob, const unsigned int *remap); void BKE_material_remap_object_calc(struct Object *ob_dst, struct Object *ob_src, short *remap_src_to_dst); struct Material *BKE_material_add(struct Main *bmain, const char *name); -struct Material *BKE_material_copy(struct Material *ma); +struct Material *BKE_material_copy(struct Main *bmain, struct Material *ma); struct Material *localize_material(struct Material *ma); struct Material *give_node_material(struct Material *ma); /* returns node material or self */ -void BKE_material_make_local(struct Material *ma); -void extern_local_matarar(struct Material **matar, short totcol); +void BKE_material_make_local(struct Main *bmain, struct Material *ma, const bool force_local); /* UNUSED */ // void automatname(struct Material *); diff --git a/source/blender/blenkernel/BKE_mball.h b/source/blender/blenkernel/BKE_mball.h index 0574b88bef3..191e8721099 100644 --- a/source/blender/blenkernel/BKE_mball.h +++ b/source/blender/blenkernel/BKE_mball.h @@ -38,13 +38,12 @@ struct Object; struct Scene; struct MetaElem; -void BKE_mball_unlink(struct MetaBall *mb); void BKE_mball_free(struct MetaBall *mb); void BKE_mball_init(struct MetaBall *mb); struct MetaBall *BKE_mball_add(struct Main *bmain, const char *name); -struct MetaBall *BKE_mball_copy(struct MetaBall *mb); +struct MetaBall *BKE_mball_copy(struct Main *bmain, struct MetaBall *mb); -void BKE_mball_make_local(struct MetaBall *mb); +void BKE_mball_make_local(struct Main *bmain, struct MetaBall *mb, const bool force_local); bool BKE_mball_is_basis_for(struct Object *ob1, struct Object *ob2); bool BKE_mball_is_basis(struct Object *ob); diff --git a/source/blender/blenkernel/BKE_mesh.h b/source/blender/blenkernel/BKE_mesh.h index d8d869015a3..ef8d1c98318 100644 --- a/source/blender/blenkernel/BKE_mesh.h +++ b/source/blender/blenkernel/BKE_mesh.h @@ -32,6 +32,7 @@ */ struct ID; +struct BMeshCreateParams; struct BoundBox; struct EdgeHash; struct ListBase; @@ -69,7 +70,9 @@ extern "C" { /* *** mesh.c *** */ -struct BMesh *BKE_mesh_to_bmesh(struct Mesh *me, struct Object *ob, const bool add_key_index); +struct BMesh *BKE_mesh_to_bmesh( + struct Mesh *me, struct Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params); int poly_find_loop_from_vert( const struct MPoly *poly, @@ -81,16 +84,14 @@ int poly_get_adj_loops_from_vert( int BKE_mesh_edge_other_vert(const struct MEdge *e, int v); -void BKE_mesh_unlink(struct Mesh *me); -void BKE_mesh_free(struct Mesh *me, int unlink); +void BKE_mesh_free(struct Mesh *me); void BKE_mesh_init(struct Mesh *me); struct Mesh *BKE_mesh_add(struct Main *bmain, const char *name); -struct Mesh *BKE_mesh_copy_ex(struct Main *bmain, struct Mesh *me); -struct Mesh *BKE_mesh_copy(struct Mesh *me); +struct Mesh *BKE_mesh_copy(struct Main *bmain, struct Mesh *me); void BKE_mesh_update_customdata_pointers(struct Mesh *me, const bool do_ensure_tess_cd); void BKE_mesh_ensure_skin_customdata(struct Mesh *me); -void BKE_mesh_make_local(struct Mesh *me); +void BKE_mesh_make_local(struct Main *bmain, struct Mesh *me, const bool force_local); void BKE_mesh_boundbox_calc(struct Mesh *me, float r_loc[3], float r_size[3]); void BKE_mesh_texspace_calc(struct Mesh *me); float (*BKE_mesh_orco_verts_get(struct Object *ob))[3]; diff --git a/source/blender/blenkernel/BKE_movieclip.h b/source/blender/blenkernel/BKE_movieclip.h index afca326c727..3d963ac109c 100644 --- a/source/blender/blenkernel/BKE_movieclip.h +++ b/source/blender/blenkernel/BKE_movieclip.h @@ -40,7 +40,6 @@ struct MovieClipUser; struct MovieDistortion; void BKE_movieclip_free(struct MovieClip *clip); -void BKE_movieclip_unlink(struct Main *bmain, struct MovieClip *clip); struct MovieClip *BKE_movieclip_file_add(struct Main *bmain, const char *name); struct MovieClip *BKE_movieclip_file_add_exists_ex(struct Main *bmain, const char *name, bool *r_exists); diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 2cbf98a2366..db46ec2497f 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -337,10 +337,9 @@ void ntreeInitDefault(struct bNodeTree *ntree); struct bNodeTree *ntreeAddTree(struct Main *bmain, const char *name, const char *idname); /* copy/free funcs, need to manage ID users */ -void ntreeFreeTree_ex(struct bNodeTree *ntree, const bool do_id_user); void ntreeFreeTree(struct bNodeTree *ntree); struct bNodeTree *ntreeCopyTree_ex(struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); -struct bNodeTree *ntreeCopyTree(struct bNodeTree *ntree); +struct bNodeTree *ntreeCopyTree(struct Main *bmain, struct bNodeTree *ntree); void ntreeSwitchID_ex(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to, const bool do_id_user); void ntreeSwitchID(struct bNodeTree *ntree, struct ID *sce_from, struct ID *sce_to); /* node->id user count */ @@ -350,7 +349,7 @@ void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree *ntreeFromID(struct ID *id); -void ntreeMakeLocal(struct bNodeTree *ntree, bool id_in_mainlist); +void ntreeMakeLocal(struct Main *bmain, struct bNodeTree *ntree, bool id_in_mainlist, const bool force_local); struct bNode *ntreeFindType(const struct bNodeTree *ntree, int type); bool ntreeHasType(const struct bNodeTree *ntree, int type); bool ntreeHasTree(const struct bNodeTree *ntree, const struct bNodeTree *lookup); diff --git a/source/blender/blenkernel/BKE_object.h b/source/blender/blenkernel/BKE_object.h index c591ec2a0aa..509524a7ce0 100644 --- a/source/blender/blenkernel/BKE_object.h +++ b/source/blender/blenkernel/BKE_object.h @@ -65,7 +65,6 @@ void BKE_object_free_curve_cache(struct Object *ob); void BKE_object_update_base_layer(struct Scene *scene, struct Object *ob); void BKE_object_free(struct Object *ob); -void BKE_object_free_ex(struct Object *ob, bool do_id_user); void BKE_object_free_derived_caches(struct Object *ob); void BKE_object_free_caches(struct Object *object); @@ -79,7 +78,6 @@ void BKE_object_free_modifiers(struct Object *ob); void BKE_object_make_proxy(struct Object *ob, struct Object *target, struct Object *gob); void BKE_object_copy_proxy_drivers(struct Object *ob, struct Object *target); -void BKE_object_unlink(struct Main *bmain, struct Object *ob); bool BKE_object_exists_check(struct Object *obtest); bool BKE_object_is_in_editmode(struct Object *ob); bool BKE_object_is_in_editmode_vgroup(struct Object *ob); @@ -108,8 +106,8 @@ struct Object *BKE_object_lod_meshob_get(struct Object *ob, struct Scene *scene) struct Object *BKE_object_lod_matob_get(struct Object *ob, struct Scene *scene); struct Object *BKE_object_copy_ex(struct Main *bmain, struct Object *ob, bool copy_caches); -struct Object *BKE_object_copy(struct Object *ob); -void BKE_object_make_local(struct Object *ob); +struct Object *BKE_object_copy(struct Main *bmain, struct Object *ob); +void BKE_object_make_local(struct Main *bmain, struct Object *ob, const bool force_local); bool BKE_object_is_libdata(struct Object *ob); bool BKE_object_obdata_is_libdata(struct Object *ob); @@ -208,8 +206,6 @@ void BKE_object_eval_uber_data(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); -void BKE_object_eval_proxy_backlink(struct EvaluationContext *eval_ctx, struct Object *ob); - void BKE_object_handle_data_update(struct EvaluationContext *eval_ctx, struct Scene *scene, struct Object *ob); diff --git a/source/blender/blenkernel/BKE_particle.h b/source/blender/blenkernel/BKE_particle.h index aef752679ee..dd7068c6d37 100644 --- a/source/blender/blenkernel/BKE_particle.h +++ b/source/blender/blenkernel/BKE_particle.h @@ -149,7 +149,8 @@ typedef struct ParticleThreadContext { struct ParticleData *tpars; /* path caching */ - int editupdate, between, segments, extra_segments; + bool editupdate; + int between, segments, extra_segments; int totchild, totparent, parent_pass; float cfra; @@ -294,7 +295,7 @@ void psys_set_current_num(Object *ob, int index); struct LatticeDeformData *psys_create_lattice_deform_data(struct ParticleSimulationData *sim); bool psys_in_edit_mode(struct Scene *scene, struct ParticleSystem *psys); -bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys); +bool psys_check_enabled(struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); bool psys_check_edited(struct ParticleSystem *psys); void psys_check_group_weights(struct ParticleSettings *part); @@ -323,16 +324,16 @@ struct ParticleSystemModifierData *psys_get_modifier(struct Object *ob, struct P struct ModifierData *object_add_particle_system(struct Scene *scene, struct Object *ob, const char *name); void object_remove_particle_system(struct Scene *scene, struct Object *ob); struct ParticleSettings *psys_new_settings(const char *name, struct Main *main); -struct ParticleSettings *BKE_particlesettings_copy(struct ParticleSettings *part); -void BKE_particlesettings_make_local(struct ParticleSettings *part); +struct ParticleSettings *BKE_particlesettings_copy(struct Main *bmain, struct ParticleSettings *part); +void BKE_particlesettings_make_local(struct Main *bmain, struct ParticleSettings *part, const bool force_local); void psys_reset(struct ParticleSystem *psys, int mode); -void psys_find_parents(struct ParticleSimulationData *sim); +void psys_find_parents(struct ParticleSimulationData *sim, const bool use_render_params); -void psys_cache_paths(struct ParticleSimulationData *sim, float cfra); -void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra); -void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, int editupdate); +void psys_cache_paths(struct ParticleSimulationData *sim, float cfra, const bool use_render_params); +void psys_cache_edit_paths(struct Scene *scene, struct Object *ob, struct PTCacheEdit *edit, float cfra, const bool use_render_params); +void psys_cache_child_paths(struct ParticleSimulationData *sim, float cfra, const bool editupdate, const bool use_render_params); int do_guides(struct ParticleSettings *part, struct EffectorContext *effectors, ParticleKey *state, int pa_num, float time); void precalc_guides(struct ParticleSimulationData *sim, struct EffectorContext *effectors); float psys_get_timestep(struct ParticleSimulationData *sim); @@ -380,7 +381,7 @@ void psys_check_boid_data(struct ParticleSystem *psys); void psys_get_birth_coords(struct ParticleSimulationData *sim, struct ParticleData *pa, struct ParticleKey *state, float dtime, float cfra); -void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys); +void particle_system_update(struct Scene *scene, struct Object *ob, struct ParticleSystem *psys, const bool use_render_params); /* Callback format for performing operations on ID-pointers for particle systems */ typedef void (*ParticleSystemIDFunc)(struct ParticleSystem *psys, struct ID **idpoin, void *userdata, int cd_flag); diff --git a/source/blender/blenkernel/BKE_sca.h b/source/blender/blenkernel/BKE_sca.h index fa448aa97b8..1743a4431fd 100644 --- a/source/blender/blenkernel/BKE_sca.h +++ b/source/blender/blenkernel/BKE_sca.h @@ -67,7 +67,6 @@ void clear_sca_new_poins_ob(struct Object *ob); void clear_sca_new_poins(void); void set_sca_new_poins_ob(struct Object *ob); void set_sca_new_poins(void); -void sca_remove_ob_poin(struct Object *obt, struct Object *ob); void sca_move_sensor(struct bSensor *sens_to_move, struct Object *ob, int move_up); void sca_move_controller(struct bController *cont_to_move, struct Object *ob, int move_up); diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 12bfc07e958..03af0b7d6c9 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -98,12 +98,13 @@ void BKE_scene_base_flag_from_objects(struct Scene *scene); void BKE_scene_set_background(struct Main *bmain, struct Scene *sce); struct Scene *BKE_scene_set_name(struct Main *bmain, const char *name); -struct Scene *BKE_scene_copy(struct Scene *sce, int type); +struct Scene *BKE_scene_copy(struct Main *bmain, struct Scene *sce, int type); void BKE_scene_groups_relink(struct Scene *sce); -void BKE_scene_unlink(struct Main *bmain, struct Scene *sce, struct Scene *newsce); struct Object *BKE_scene_camera_find(struct Scene *sc); +#ifdef DURIAN_CAMERA_SWITCH struct Object *BKE_scene_camera_switch_find(struct Scene *scene); // DURIAN_CAMERA_SWITCH +#endif int BKE_scene_camera_switch_update(struct Scene *scene); char *BKE_scene_find_marker_name(struct Scene *scene, int frame); diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index d05df3470b5..14e978b23f2 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -99,6 +99,9 @@ typedef struct SpaceType { /* return context data */ int (*context)(const struct bContext *, const char *, struct bContextDataResult *); + /* Used when we want to replace an ID by another (or NULL). */ + void (*id_remap)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *); + /* region type definitions */ ListBase regiontypes; @@ -274,8 +277,8 @@ void BKE_spacedata_freelist(ListBase *lb); void BKE_spacedata_copylist(ListBase *lb1, ListBase *lb2); void BKE_spacedata_draw_locks(int set); -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)); -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void BKE_spacedata_callback_id_remap_set(void (*func)(struct ScrArea *, struct SpaceLink *, struct ID *, struct ID *)); +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id); /* area/regions */ struct ARegion *BKE_area_region_copy(struct SpaceType *st, struct ARegion *ar); diff --git a/source/blender/blenkernel/BKE_sound.h b/source/blender/blenkernel/BKE_sound.h index 67db2537c8f..18d9fe061a8 100644 --- a/source/blender/blenkernel/BKE_sound.h +++ b/source/blender/blenkernel/BKE_sound.h @@ -72,8 +72,6 @@ struct bSound *BKE_sound_new_buffer(struct Main *bmain, struct bSound *source); struct bSound *BKE_sound_new_limiter(struct Main *bmain, struct bSound *source, float start, float end); #endif -void BKE_sound_delete(struct Main *bmain, struct bSound *sound); - void BKE_sound_cache(struct bSound *sound); void BKE_sound_delete_cache(struct bSound *sound); diff --git a/source/blender/blenkernel/BKE_speaker.h b/source/blender/blenkernel/BKE_speaker.h index 5f30df1d6e3..fb730d95b92 100644 --- a/source/blender/blenkernel/BKE_speaker.h +++ b/source/blender/blenkernel/BKE_speaker.h @@ -33,8 +33,8 @@ struct Speaker; void BKE_speaker_init(struct Speaker *spk); void *BKE_speaker_add(struct Main *bmain, const char *name); -struct Speaker *BKE_speaker_copy(struct Speaker *spk); -void BKE_speaker_make_local(struct Speaker *spk); +struct Speaker *BKE_speaker_copy(struct Main *bmain, struct Speaker *spk); +void BKE_speaker_make_local(struct Main *bmain, struct Speaker *spk, const bool force_local); void BKE_speaker_free(struct Speaker *spk); #endif diff --git a/source/blender/blenkernel/BKE_text.h b/source/blender/blenkernel/BKE_text.h index b14593f5a56..858feeeab10 100644 --- a/source/blender/blenkernel/BKE_text.h +++ b/source/blender/blenkernel/BKE_text.h @@ -53,7 +53,6 @@ struct Text *BKE_text_load_ex(struct Main *bmain, const char *file, const cha const bool is_internal); struct Text *BKE_text_load (struct Main *bmain, const char *file, const char *relpath); struct Text *BKE_text_copy (struct Main *bmain, struct Text *ta); -void BKE_text_unlink (struct Main *bmain, struct Text *text); void BKE_text_clear (struct Text *text); void BKE_text_write (struct Text *text, const char *str); int BKE_text_file_modified_check(struct Text *text); diff --git a/source/blender/blenkernel/BKE_texture.h b/source/blender/blenkernel/BKE_texture.h index 904c130616f..2fef79f3897 100644 --- a/source/blender/blenkernel/BKE_texture.h +++ b/source/blender/blenkernel/BKE_texture.h @@ -71,10 +71,10 @@ void colorband_update_sort(struct ColorBand *coba); void BKE_texture_free(struct Tex *tex); void BKE_texture_default(struct Tex *tex); -struct Tex *BKE_texture_copy(struct Tex *tex); +struct Tex *BKE_texture_copy(struct Main *bmain, struct Tex *tex); struct Tex *BKE_texture_add(struct Main *bmain, const char *name); struct Tex *BKE_texture_localize(struct Tex *tex); -void BKE_texture_make_local(struct Tex *tex); +void BKE_texture_make_local(struct Main *bmain, struct Tex *tex, const bool force_local); void BKE_texture_type_set(struct Tex *tex, int type); void BKE_texture_mtex_default(struct MTex *mtex); diff --git a/source/blender/blenkernel/BKE_world.h b/source/blender/blenkernel/BKE_world.h index 8d7ab230919..8b8dac4ab22 100644 --- a/source/blender/blenkernel/BKE_world.h +++ b/source/blender/blenkernel/BKE_world.h @@ -37,12 +37,11 @@ struct Main; struct World; void BKE_world_free(struct World *sc); -void BKE_world_free_ex(struct World *sc, bool do_id_user); void BKE_world_init(struct World *wrld); struct World *add_world(struct Main *bmian, const char *name); -struct World *BKE_world_copy(struct World *wrld); +struct World *BKE_world_copy(struct Main *bmain, struct World *wrld); struct World *localize_world(struct World *wrld); -void BKE_world_make_local(struct World *wrld); +void BKE_world_make_local(struct Main *bmain, struct World *wrld, const bool force_local); #endif diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index f32172c2806..51eeb79c414 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -50,9 +50,6 @@ set(INC ../../../intern/smoke/extern ../../../intern/atomic ../../../intern/libmv - - # XXX - BAD LEVEL CALL WM_api.h - ../windowmanager ) set(INC_SYS @@ -124,6 +121,7 @@ set(SRC intern/library.c intern/library_idmap.c intern/library_query.c + intern/library_remap.c intern/linestyle.c intern/mask.c intern/mask_evaluate.c @@ -248,6 +246,7 @@ set(SRC BKE_library.h BKE_library_idmap.h BKE_library_query.h + BKE_library_remap.h BKE_linestyle.h BKE_main.h BKE_mask.h diff --git a/source/blender/blenkernel/intern/CCGSubSurf_intern.h b/source/blender/blenkernel/intern/CCGSubSurf_intern.h index 7ec9f329444..0cdf3acf075 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_intern.h +++ b/source/blender/blenkernel/intern/CCGSubSurf_intern.h @@ -86,7 +86,7 @@ void ccg_ehashIterator_next(EHashIterator *ehi); int ccg_ehashIterator_isStopped(EHashIterator *ehi); /** - * Standard allocator implementarion. + * Standard allocator implementation. */ CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void); diff --git a/source/blender/blenkernel/intern/CCGSubSurf_util.c b/source/blender/blenkernel/intern/CCGSubSurf_util.c index 9af69115559..c7ef528c02f 100644 --- a/source/blender/blenkernel/intern/CCGSubSurf_util.c +++ b/source/blender/blenkernel/intern/CCGSubSurf_util.c @@ -184,7 +184,7 @@ int ccg_ehashIterator_isStopped(EHashIterator *ehi) } /** - * Standard allocator implementarion. + * Standard allocator implementation. */ static void *_stdAllocator_alloc(CCGAllocatorHDL UNUSED(a), int numBytes) diff --git a/source/blender/blenkernel/intern/DerivedMesh.c b/source/blender/blenkernel/intern/DerivedMesh.c index 76473948625..70ce07a0dcb 100644 --- a/source/blender/blenkernel/intern/DerivedMesh.c +++ b/source/blender/blenkernel/intern/DerivedMesh.c @@ -1436,10 +1436,12 @@ static void calc_weightpaint_vert_array( Object *ob, DerivedMesh *dm, int const draw_flag, DMWeightColorInfo *dm_wcinfo, unsigned char (*r_wtcol_v)[4]) { - MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); - int numVerts = dm->getNumVerts(dm); + BMEditMesh *em = (dm->type == DM_TYPE_EDITBMESH) ? BKE_editmesh_from_object(ob) : NULL; + const int numVerts = dm->getNumVerts(dm); - if (dv && (ob->actdef != 0)) { + if ((ob->actdef != 0) && + (CustomData_has_layer(em ? &em->bm->vdata : &dm->vertData, CD_MDEFORMVERT))) + { unsigned char (*wc)[4] = r_wtcol_v; unsigned int i; @@ -1458,8 +1460,30 @@ static void calc_weightpaint_vert_array( } } - for (i = numVerts; i != 0; i--, wc++, dv++) { - calc_weightpaint_vert_color((unsigned char *)wc, dv, dm_wcinfo, defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + /* editmesh won't have deform verts unless modifiers require it, + * avoid having to create an array of deform-verts only for drawing + * by reading from the bmesh directly. */ + if (em) { + BMIter iter; + BMVert *eve; + const int cd_dvert_offset = CustomData_get_offset(&em->bm->vdata, CD_MDEFORMVERT); + BLI_assert(cd_dvert_offset != -1); + + BM_ITER_MESH_INDEX (eve, &iter, em->bm, BM_VERTS_OF_MESH, i) { + const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(eve, cd_dvert_offset); + calc_weightpaint_vert_color( + (unsigned char *)wc, dv, dm_wcinfo, + defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + wc++; + } + } + else { + const MDeformVert *dv = DM_get_vert_data_layer(dm, CD_MDEFORMVERT); + for (i = numVerts; i != 0; i--, wc++, dv++) { + calc_weightpaint_vert_color( + (unsigned char *)wc, dv, dm_wcinfo, + defbase_tot, defbase_act, defbase_sel, defbase_sel_tot, draw_flag); + } } if (defbase_sel) { @@ -2346,7 +2370,7 @@ static void editbmesh_calc_modifiers( modifiers_clearErrors(ob); if (r_cage && cageIndex == -1) { - *r_cage = getEditDerivedBMesh(em, ob, NULL); + *r_cage = getEditDerivedBMesh(em, ob, dataMask, NULL); } md = modifiers_getVirtualModifierList(ob, &virtualModifierData); @@ -2512,7 +2536,7 @@ static void editbmesh_calc_modifiers( } else { *r_cage = getEditDerivedBMesh( - em, ob, + em, ob, mask, deformedVerts ? MEM_dupallocN(deformedVerts) : NULL); } } @@ -2548,7 +2572,7 @@ static void editbmesh_calc_modifiers( } else { /* this is just a copy of the editmesh, no need to calc normals */ - *r_final = getEditDerivedBMesh(em, ob, deformedVerts); + *r_final = getEditDerivedBMesh(em, ob, dataMask, deformedVerts); deformedVerts = NULL; /* In this case, we should never have weight-modifying modifiers in stack... */ @@ -2911,9 +2935,9 @@ DerivedMesh *editbmesh_get_derived_cage(Scene *scene, Object *obedit, BMEditMesh return em->derivedCage; } -DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em) +DerivedMesh *editbmesh_get_derived_base(Object *obedit, BMEditMesh *em, CustomDataMask data_mask) { - return getEditDerivedBMesh(em, obedit, NULL); + return getEditDerivedBMesh(em, obedit, data_mask, NULL); } /***/ diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c index df9b9683687..fa49797126d 100644 --- a/source/blender/blenkernel/intern/action.c +++ b/source/blender/blenkernel/intern/action.c @@ -59,6 +59,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_object.h" @@ -92,94 +94,57 @@ bAction *add_empty_action(Main *bmain, const char name[]) /* .................................. */ -/* temp data for BKE_action_make_local */ -typedef struct tMakeLocalActionContext { - bAction *act; /* original action */ - bAction *act_new; /* new action */ - - bool is_lib; /* some action users were libraries */ - bool is_local; /* some action users were not libraries */ -} tMakeLocalActionContext; - -/* helper function for BKE_action_make_local() - local/lib init step */ -static void make_localact_init_cb(ID *id, AnimData *adt, void *mlac_ptr) +// does copy_fcurve... +void BKE_action_make_local(Main *bmain, bAction *act, const bool force_local) { - tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; - - if (adt->action == mlac->act) { - if (id->lib) mlac->is_lib = true; - else mlac->is_local = true; - } -} + bool is_local = false, is_lib = false; -/* helper function for BKE_action_make_local() - change references */ -static void make_localact_apply_cb(ID *id, AnimData *adt, void *mlac_ptr) -{ - tMakeLocalActionContext *mlac = (tMakeLocalActionContext *)mlac_ptr; - - if (adt->action == mlac->act) { - if (id->lib == NULL) { - adt->action = mlac->act_new; - - id_us_plus(&mlac->act_new->id); - id_us_min(&mlac->act->id); - } - } -} + /* - only lib users: do nothing (unless force_local is set) + * - only local users: set flag + * - mixed: make copy + */ -// does copy_fcurve... -void BKE_action_make_local(bAction *act) -{ - tMakeLocalActionContext mlac = {act, NULL, false, false}; - Main *bmain = G.main; - - if (act->id.lib == NULL) + if (!ID_IS_LINKED_DATABLOCK(act)) { return; - - /* XXX: double-check this; it used to be just single-user check, but that was when fake-users were still default */ - if ((act->id.flag & LIB_FAKEUSER) && (act->id.us <= 1)) { - id_clear_lib_data(bmain, &act->id); - return; - } - - BKE_animdata_main_cb(bmain, make_localact_init_cb, &mlac); - - if (mlac.is_local && mlac.is_lib == false) { - id_clear_lib_data(bmain, &act->id); } - else if (mlac.is_local && mlac.is_lib) { - mlac.act_new = BKE_action_copy(act); - mlac.act_new->id.us = 0; - BKE_id_lib_local_paths(bmain, act->id.lib, &mlac.act_new->id); + BKE_library_ID_test_usages(bmain, act, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &act->id); + BKE_id_expand_local(&act->id); + } + else { + bAction *act_new = BKE_action_copy(bmain, act); + + act_new->id.us = 0; - BKE_animdata_main_cb(bmain, make_localact_apply_cb, &mlac); + BKE_libblock_remap(bmain, act, act_new, ID_REMAP_SKIP_INDIRECT_USAGE); + } } } /* .................................. */ +/** Free (or release) any data used by this action (does not free the action itself). */ void BKE_action_free(bAction *act) -{ - /* sanity check */ - if (act == NULL) - return; - +{ + /* No animdata here. */ + /* Free F-Curves */ free_fcurves(&act->curves); /* Free groups */ - if (act->groups.first) - BLI_freelistN(&act->groups); + BLI_freelistN(&act->groups); /* Free pose-references (aka local markers) */ - if (act->markers.first) - BLI_freelistN(&act->markers); + BLI_freelistN(&act->markers); } /* .................................. */ -bAction *BKE_action_copy(bAction *src) +bAction *BKE_action_copy(Main *bmain, bAction *src) { bAction *dst = NULL; bActionGroup *dgrp, *sgrp; @@ -187,7 +152,7 @@ bAction *BKE_action_copy(bAction *src) if (src == NULL) return NULL; - dst = BKE_libblock_copy(&src->id); + dst = BKE_libblock_copy(bmain, &src->id); /* duplicate the lists of groups and markers */ BLI_duplicatelist(&dst->groups, &src->groups); @@ -216,8 +181,9 @@ bAction *BKE_action_copy(bAction *src) } } - if (src->id.lib) { - BKE_id_lib_local_paths(G.main, src->id.lib, &dst->id); + if (ID_IS_LINKED_DATABLOCK(src)) { + BKE_id_expand_local(&dst->id); + BKE_id_lib_local_paths(bmain, src->id.lib, &dst->id); } return dst; diff --git a/source/blender/blenkernel/intern/anim.c b/source/blender/blenkernel/intern/anim.c index dff696863e9..7d3d12ac112 100644 --- a/source/blender/blenkernel/intern/anim.c +++ b/source/blender/blenkernel/intern/anim.c @@ -340,11 +340,11 @@ static void motionpaths_calc_update_scene(Scene *scene) } } #else // original, 'always correct' version - /* do all updates - * - if this is too slow, resort to using a more efficient way - * that doesn't force complete update, but for now, this is the - * most accurate way! - */ + /* do all updates + * - if this is too slow, resort to using a more efficient way + * that doesn't force complete update, but for now, this is the + * most accurate way! + */ BKE_scene_update_for_newframe(G.main->eval_ctx, G.main, scene, scene->lay); /* XXX this is the best way we can get anything moving */ #endif } diff --git a/source/blender/blenkernel/intern/anim_sys.c b/source/blender/blenkernel/intern/anim_sys.c index 99aae6239e8..d04b950c043 100644 --- a/source/blender/blenkernel/intern/anim_sys.c +++ b/source/blender/blenkernel/intern/anim_sys.c @@ -79,15 +79,11 @@ /* Getter/Setter -------------------------------------------- */ /* Check if ID can have AnimData */ -bool id_type_can_have_animdata(ID *id) +bool id_type_can_have_animdata(const short id_type) { - /* sanity check */ - if (id == NULL) - return false; - /* Only some ID-blocks have this info for now */ /* TODO: finish adding this for the other blocktypes */ - switch (GS(id->name)) { + switch (id_type) { /* has AnimData */ case ID_OB: case ID_ME: case ID_MB: case ID_CU: case ID_AR: case ID_LT: @@ -101,9 +97,7 @@ bool id_type_can_have_animdata(ID *id) case ID_MC: case ID_MSK: case ID_GD: - { return true; - } /* no AnimData */ default: @@ -111,6 +105,14 @@ bool id_type_can_have_animdata(ID *id) } } +bool id_can_have_animdata(const ID *id) +{ + /* sanity check */ + if (id == NULL) + return false; + + return id_type_can_have_animdata(GS(id->name)); +} /* Get AnimData from the given ID-block. In order for this to work, we assume that * the AnimData pointer is stored immediately after the given ID-block in the struct, @@ -122,7 +124,7 @@ AnimData *BKE_animdata_from_id(ID *id) * types that do to be of type IdAdtTemplate, and extract the * AnimData that way */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; return iat->adt; } @@ -140,7 +142,7 @@ AnimData *BKE_animdata_add_id(ID *id) * types that do to be of type IdAdtTemplate, and add the AnimData * to it using the template */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; /* check if there's already AnimData, in which case, don't add */ @@ -216,23 +218,25 @@ bool BKE_animdata_set_action(ReportList *reports, ID *id, bAction *act) /* Freeing -------------------------------------------- */ /* Free AnimData used by the nominated ID-block, and clear ID-block's AnimData pointer */ -void BKE_animdata_free(ID *id) +void BKE_animdata_free(ID *id, const bool do_id_user) { /* Only some ID-blocks have this info for now, so we cast the * types that do to be of type IdAdtTemplate */ - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; AnimData *adt = iat->adt; /* check if there's any AnimData to start with */ if (adt) { - /* unlink action (don't free, as it's in its own list) */ - if (adt->action) - id_us_min(&adt->action->id); - /* same goes for the temporarily displaced action */ - if (adt->tmpact) - id_us_min(&adt->tmpact->id); + if (do_id_user) { + /* unlink action (don't free, as it's in its own list) */ + if (adt->action) + id_us_min(&adt->action->id); + /* same goes for the temporarily displaced action */ + if (adt->tmpact) + id_us_min(&adt->tmpact->id); + } /* free nla data */ free_nladata(&adt->nla_tracks); @@ -264,8 +268,8 @@ AnimData *BKE_animdata_copy(AnimData *adt, const bool do_action) /* make a copy of action - at worst, user has to delete copies... */ if (do_action) { - dadt->action = BKE_action_copy(adt->action); - dadt->tmpact = BKE_action_copy(adt->tmpact); + dadt->action = BKE_action_copy(G.main, adt->action); + dadt->tmpact = BKE_action_copy(G.main, adt->tmpact); } else { id_us_plus((ID *)dadt->action); @@ -292,7 +296,7 @@ bool BKE_animdata_copy_id(ID *id_to, ID *id_from, const bool do_action) if ((id_to && id_from) && (GS(id_to->name) != GS(id_from->name))) return false; - BKE_animdata_free(id_to); + BKE_animdata_free(id_to, true); adt = BKE_animdata_from_id(id_from); if (adt) { @@ -309,11 +313,11 @@ void BKE_animdata_copy_id_action(ID *id) if (adt) { if (adt->action) { id_us_min((ID *)adt->action); - adt->action = BKE_action_copy(adt->action); + adt->action = BKE_action_copy(G.main, adt->action); } if (adt->tmpact) { id_us_min((ID *)adt->tmpact); - adt->tmpact = BKE_action_copy(adt->tmpact); + adt->tmpact = BKE_action_copy(G.main, adt->tmpact); } } } @@ -337,8 +341,8 @@ void BKE_animdata_merge_copy(ID *dst_id, ID *src_id, eAnimData_MergeCopy_Modes a /* handle actions... */ if (action_mode == ADT_MERGECOPY_SRC_COPY) { /* make a copy of the actions */ - dst->action = BKE_action_copy(src->action); - dst->tmpact = BKE_action_copy(src->tmpact); + dst->action = BKE_action_copy(G.main, src->action); + dst->tmpact = BKE_action_copy(G.main, src->tmpact); } else if (action_mode == ADT_MERGECOPY_SRC_REF) { /* make a reference to it */ @@ -396,8 +400,8 @@ static void make_local_strips(ListBase *strips) NlaStrip *strip; for (strip = strips->first; strip; strip = strip->next) { - if (strip->act) BKE_action_make_local(strip->act); - if (strip->remap && strip->remap->target) BKE_action_make_local(strip->remap->target); + if (strip->act) BKE_action_make_local(G.main, strip->act, false); + if (strip->remap && strip->remap->target) BKE_action_make_local(G.main, strip->remap->target, false); make_local_strips(&strip->strips); } @@ -409,10 +413,10 @@ void BKE_animdata_make_local(AnimData *adt) NlaTrack *nlt; /* Actions - Active and Temp */ - if (adt->action) BKE_action_make_local(adt->action); - if (adt->tmpact) BKE_action_make_local(adt->tmpact); + if (adt->action) BKE_action_make_local(G.main, adt->action, false); + if (adt->tmpact) BKE_action_make_local(G.main, adt->tmpact, false); /* Remaps */ - if (adt->remap && adt->remap->target) BKE_action_make_local(adt->remap->target); + if (adt->remap && adt->remap->target) BKE_action_make_local(G.main, adt->remap->target, false); /* Drivers */ /* TODO: need to remap the ID-targets too? */ @@ -1047,7 +1051,7 @@ void BKE_animdata_fix_paths_remove(ID *id, const char *prefix) */ NlaTrack *nlt; - if (id_type_can_have_animdata(id)) { + if (id_can_have_animdata(id)) { IdAdtTemplate *iat = (IdAdtTemplate *)id; AnimData *adt = iat->adt; diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 04b4733fd44..53e28177bdf 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -67,6 +67,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" @@ -120,73 +122,54 @@ void BKE_armature_bonelist_free(ListBase *lb) BLI_freelistN(lb); } +/** Free (or release) any data used by this armature (does not free the armature itself). */ void BKE_armature_free(bArmature *arm) { - if (arm) { - BKE_armature_bonelist_free(&arm->bonebase); + BKE_animdata_free(&arm->id, false); - /* free editmode data */ - if (arm->edbo) { - BLI_freelistN(arm->edbo); + BKE_armature_bonelist_free(&arm->bonebase); - MEM_freeN(arm->edbo); - arm->edbo = NULL; - } + /* free editmode data */ + if (arm->edbo) { + BLI_freelistN(arm->edbo); - /* free sketch */ - if (arm->sketch) { - freeSketch(arm->sketch); - arm->sketch = NULL; - } + MEM_freeN(arm->edbo); + arm->edbo = NULL; + } - /* free animation data */ - if (arm->adt) { - BKE_animdata_free(&arm->id); - arm->adt = NULL; - } + /* free sketch */ + if (arm->sketch) { + freeSketch(arm->sketch); + arm->sketch = NULL; } } -void BKE_armature_make_local(bArmature *arm) +void BKE_armature_make_local(Main *bmain, bArmature *arm, const bool force_local) { - Main *bmain = G.main; bool is_local = false, is_lib = false; - Object *ob; - if (arm->id.lib == NULL) - return; - if (arm->id.us == 1) { - id_clear_lib_data(bmain, &arm->id); + /* - only lib users: do nothing (unless force_local is set) + * - only local users: set flag + * - mixed: make copy + */ + + if (!ID_IS_LINKED_DATABLOCK(arm)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == arm) { - if (ob->id.lib) - is_lib = true; - else - is_local = true; - } - } + BKE_library_ID_test_usages(bmain, arm, &is_local, &is_lib); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &arm->id); - } - else if (is_local && is_lib) { - bArmature *arm_new = BKE_armature_copy(arm); - arm_new->id.us = 0; + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &arm->id); + BKE_id_expand_local(&arm->id); + } + else { + bArmature *arm_new = BKE_armature_copy(bmain, arm); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, arm->id.lib, &arm_new->id); + arm_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == arm) { - if (ob->id.lib == NULL) { - ob->data = arm_new; - id_us_plus(&arm_new->id); - id_us_min(&arm->id); - } - } + BKE_libblock_remap(bmain, arm, arm_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -213,13 +196,13 @@ static void copy_bonechildren(Bone *newBone, Bone *oldBone, Bone *actBone, Bone } } -bArmature *BKE_armature_copy(bArmature *arm) +bArmature *BKE_armature_copy(Main *bmain, bArmature *arm) { bArmature *newArm; Bone *oldBone, *newBone; Bone *newActBone = NULL; - newArm = BKE_libblock_copy(&arm->id); + newArm = BKE_libblock_copy(bmain, &arm->id); BLI_duplicatelist(&newArm->bonebase, &arm->bonebase); /* Duplicate the childrens' lists */ @@ -236,8 +219,9 @@ bArmature *BKE_armature_copy(bArmature *arm) newArm->act_edbone = NULL; newArm->sketch = NULL; - if (arm->id.lib) { - BKE_id_lib_local_paths(G.main, arm->id.lib, &newArm->id); + if (ID_IS_LINKED_DATABLOCK(arm)) { + BKE_id_expand_local(&newArm->id); + BKE_id_lib_local_paths(bmain, arm->id.lib, &newArm->id); } return newArm; @@ -640,6 +624,7 @@ void b_bone_spline_setup(bPoseChannel *pchan, int rest, Mat4 result_array[MAX_BB { const float circle_factor = length * (cubic_tangent_factor_circle_v3(h1, h2) / 0.75f); + const float hlength1 = bone->ease1 * circle_factor; const float hlength2 = bone->ease2 * circle_factor; diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c index 826bb12a912..aebd564ca58 100644 --- a/source/blender/blenkernel/intern/armature_update.c +++ b/source/blender/blenkernel/intern/armature_update.c @@ -224,7 +224,7 @@ static void splineik_init_tree_from_pchan(Scene *scene, Object *UNUSED(ob), bPos } /* make a new Spline-IK chain, and store it in the IK chains */ - /* TODO: we should check if there is already an IK chain on this, since that would take presidence... */ + /* TODO: we should check if there is already an IK chain on this, since that would take precedence... */ { /* make new tree */ tSplineIK_Tree *tree = MEM_callocN(sizeof(tSplineIK_Tree), "SplineIK Tree"); @@ -696,7 +696,7 @@ void BKE_pose_eval_flush(EvaluationContext *UNUSED(eval_ctx), void BKE_pose_eval_proxy_copy(EvaluationContext *UNUSED(eval_ctx), Object *ob) { - BLI_assert(ob->id.lib != NULL && ob->proxy_from != NULL); + BLI_assert(ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL); DEBUG_PRINT("%s on %s\n", __func__, ob->id.name); if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", diff --git a/source/blender/blenkernel/intern/blender.c b/source/blender/blenkernel/intern/blender.c index 25136763386..2298819b2f4 100644 --- a/source/blender/blenkernel/intern/blender.c +++ b/source/blender/blenkernel/intern/blender.c @@ -229,3 +229,56 @@ int BKE_blender_test_break(void) return (G.is_break == true); } + +/** \name Blender's AtExit + * + * \note Don't use MEM_mallocN so functions can be registered at any time. + * \{ */ + +struct AtExitData { + struct AtExitData *next; + + void (*func)(void *user_data); + void *user_data; +} *g_atexit = NULL; + +void BKE_blender_atexit_register(void (*func)(void *user_data), void *user_data) +{ + struct AtExitData *ae = malloc(sizeof(*ae)); + ae->next = g_atexit; + ae->func = func; + ae->user_data = user_data; + g_atexit = ae; +} + +void BKE_blender_atexit_unregister(void (*func)(void *user_data), const void *user_data) +{ + struct AtExitData *ae = g_atexit; + struct AtExitData **ae_p = &g_atexit; + + while (ae) { + if ((ae->func == func) && (ae->user_data == user_data)) { + *ae_p = ae->next; + free(ae); + return; + } + ae_p = &ae; + ae = ae->next; + } +} + +void BKE_blender_atexit(void) +{ + struct AtExitData *ae = g_atexit, *ae_next; + while (ae) { + ae_next = ae->next; + + ae->func(ae->user_data); + + free(ae); + ae = ae_next; + } + g_atexit = NULL; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/blender_undo.c b/source/blender/blenkernel/intern/blender_undo.c index ca0a1b91cea..d64bf7ecf43 100644 --- a/source/blender/blenkernel/intern/blender_undo.c +++ b/source/blender/blenkernel/intern/blender_undo.c @@ -66,9 +66,6 @@ #include "BLO_readfile.h" #include "BLO_writefile.h" -#include "WM_api.h" // XXXXX BAD, very BAD dependency (bad level call) - remove asap, elubie - - /* -------------------------------------------------------------------- */ /** \name Global Undo @@ -87,6 +84,15 @@ typedef struct UndoElem { static ListBase undobase = {NULL, NULL}; static UndoElem *curundo = NULL; +/** + * Avoid bad-level call to #WM_jobs_kill_all_except() + */ +static void (*undo_wm_job_kill_callback)(struct bContext *C) = NULL; + +void BKE_undo_callback_wm_kill_jobs_set(void (*callback)(struct bContext *C)) +{ + undo_wm_job_kill_callback = callback; +} static int read_undosave(bContext *C, UndoElem *uel) { @@ -94,7 +100,7 @@ static int read_undosave(bContext *C, UndoElem *uel) int success = 0, fileflags; /* This is needed so undoing/redoing doesn't crash with threaded previews going */ - WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); + undo_wm_job_kill_callback(C); BLI_strncpy(mainstr, G.main->name, sizeof(mainstr)); /* temporal store */ diff --git a/source/blender/blenkernel/intern/bpath.c b/source/blender/blenkernel/intern/bpath.c index 76544e5ed42..a708c59fa97 100644 --- a/source/blender/blenkernel/intern/bpath.c +++ b/source/blender/blenkernel/intern/bpath.c @@ -424,7 +424,7 @@ void BKE_bpath_traverse_id(Main *bmain, ID *id, BPathVisitor visit_cb, const int { const char *absbase = (flag & BKE_BPATH_TRAVERSE_ABS) ? ID_BLEND_PATH(bmain, id) : NULL; - if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && id->lib) { + if ((flag & BKE_BPATH_TRAVERSE_SKIP_LIBRARY) && ID_IS_LINKED_DATABLOCK(id)) { return; } diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index da7863096e3..3d9cabdc15d 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -38,6 +38,8 @@ #include "BKE_colortools.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_paint.h" #include "BKE_texture.h" @@ -170,11 +172,11 @@ struct Brush *BKE_brush_first_search(struct Main *bmain, short ob_mode) return NULL; } -Brush *BKE_brush_copy(Brush *brush) +Brush *BKE_brush_copy(Main *bmain, Brush *brush) { Brush *brushn; - brushn = BKE_libblock_copy(&brush->id); + brushn = BKE_libblock_copy(bmain, &brush->id); if (brush->mtex.tex) id_us_plus((ID *)brush->mtex.tex); @@ -195,103 +197,62 @@ Brush *BKE_brush_copy(Brush *brush) /* enable fake user by default */ id_fake_user_set(&brush->id); - if (brush->id.lib) { - BKE_id_lib_local_paths(G.main, brush->id.lib, &brushn->id); + if (ID_IS_LINKED_DATABLOCK(brush)) { + BKE_id_expand_local(&brushn->id); + BKE_id_lib_local_paths(bmain, brush->id.lib, &brushn->id); } return brushn; } -/* not brush itself */ +/** Free (or release) any data used by this brush (does not free the brush itself). */ void BKE_brush_free(Brush *brush) { - id_us_min((ID *)brush->mtex.tex); - id_us_min((ID *)brush->mask_mtex.tex); - id_us_min((ID *)brush->paint_curve); - - if (brush->icon_imbuf) + if (brush->icon_imbuf) { IMB_freeImBuf(brush->icon_imbuf); - - BKE_previewimg_free(&(brush->preview)); + } curvemapping_free(brush->curve); - if (brush->gradient) - MEM_freeN(brush->gradient); -} - -/** - * \note Currently users don't remove brushes from the UI (as is done for scene, text... etc) - * This is only used by RNA, which can remove brushes. - */ -void BKE_brush_unlink(Main *bmain, Brush *brush) -{ - Brush *brush_iter; - - for (brush_iter = bmain->brush.first; brush_iter; brush_iter = brush_iter->id.next) { - if (brush_iter->toggle_brush == brush) { - brush_iter->toggle_brush = NULL; - } - } -} + MEM_SAFE_FREE(brush->gradient); -static void extern_local_brush(Brush *brush) -{ - id_lib_extern((ID *)brush->mtex.tex); - id_lib_extern((ID *)brush->mask_mtex.tex); - id_lib_extern((ID *)brush->clone.image); - id_lib_extern((ID *)brush->toggle_brush); - id_lib_extern((ID *)brush->paint_curve); + BKE_previewimg_free(&(brush->preview)); } -void BKE_brush_make_local(Brush *brush) +void BKE_brush_make_local(Main *bmain, Brush *brush, const bool force_local) { + bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - Main *bmain = G.main; - Scene *scene; - bool is_local = false, is_lib = false; - - if (brush->id.lib == NULL) return; + if (!ID_IS_LINKED_DATABLOCK(brush)) { + return; + } if (brush->clone.image) { - /* special case: ima always local immediately. Clone image should only - * have one user anyway. */ - id_clear_lib_data(bmain, &brush->clone.image->id); - extern_local_brush(brush); + /* Special case: ima always local immediately. Clone image should only have one user anyway. */ + id_make_local(bmain, &brush->clone.image->id, false, false); } - for (scene = bmain->scene.first; scene && ELEM(0, is_lib, is_local); scene = scene->id.next) { - if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) { - if (scene->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, brush, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &brush->id); + BKE_id_expand_local(&brush->id); + + /* enable fake user by default */ + id_fake_user_set(&brush->id); } - } + else { + Brush *brush_new = BKE_brush_copy(bmain, brush); /* Ensures FAKE_USER is set */ - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &brush->id); - extern_local_brush(brush); + brush_new->id.us = 0; - /* enable fake user by default */ - id_fake_user_set(&brush->id); - } - else if (is_local && is_lib) { - Brush *brush_new = BKE_brush_copy(brush); /* Ensures FAKE_USER is set */ - id_us_min(&brush_new->id); /* Remove user added by standard BKE_libblock_copy(). */ - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, brush->id.lib, &brush_new->id); - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - if (BKE_paint_brush(&scene->toolsettings->imapaint.paint) == brush) { - if (scene->id.lib == NULL) { - BKE_paint_brush_set(&scene->toolsettings->imapaint.paint, brush_new); - } - } + BKE_libblock_remap(bmain, brush, brush_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -488,6 +449,7 @@ void BKE_brush_curve_preset(Brush *b, int preset) curvemapping_changed(b->curve, false); } +/* XXX Unused function. */ int BKE_brush_texture_set_nr(Brush *brush, int nr) { ID *idtest, *id = NULL; @@ -496,7 +458,7 @@ int BKE_brush_texture_set_nr(Brush *brush, int nr) idtest = (ID *)BLI_findlink(&G.main->tex, nr - 1); if (idtest == NULL) { /* new tex */ - if (id) idtest = (ID *)BKE_texture_copy((Tex *)id); + if (id) idtest = (ID *)BKE_texture_copy(G.main, (Tex *)id); else idtest = (ID *)BKE_texture_add(G.main, "Tex"); id_us_min(idtest); } @@ -835,9 +797,7 @@ void BKE_brush_color_set(struct Scene *scene, struct Brush *brush, const float c void BKE_brush_size_set(Scene *scene, Brush *brush, int size) { UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; - - size = (int)((float)size / U.pixelsize); - + /* make sure range is sane */ CLAMP(size, 1, MAX_BRUSH_PIXEL_RADIUS); diff --git a/source/blender/blenkernel/intern/bvhutils.c b/source/blender/blenkernel/intern/bvhutils.c index 7821946eb6e..264d87b86f3 100644 --- a/source/blender/blenkernel/intern/bvhutils.c +++ b/source/blender/blenkernel/intern/bvhutils.c @@ -565,7 +565,7 @@ BVHTree *bvhtree_from_mesh_verts( /** * Builds a bvh tree where nodes are the given vertices (note: does not copy given mverts!). * \param vert_allocated if true, vert freeing will be done when freeing data. - * \param mask if not null, true elements give which vert to add to BVH tree. + * \param verts_mask if not null, true elements give which vert to add to BVH tree. * \param verts_num_active if >= 0, number of active verts to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_verts_ex( @@ -590,6 +590,77 @@ BVHTree *bvhtree_from_mesh_verts_ex( /** \name Edge Builder * \{ */ +static BVHTree *bvhtree_from_editmesh_edges_create_tree( + float epsilon, int tree_type, int axis, + BMEditMesh *em, const int edges_num, + const BLI_bitmap *edges_mask, int edges_num_active) +{ + BVHTree *tree = NULL; + int i; + BM_mesh_elem_table_ensure(em->bm, BM_EDGE); + if (edges_mask) { + BLI_assert(IN_RANGE_INCL(edges_num_active, 0, edges_num)); + } + else { + edges_num_active = edges_num; + } + + tree = BLI_bvhtree_new(edges_num_active, epsilon, tree_type, axis); + + if (tree) { + BMIter iter; + BMEdge *eed; + BM_ITER_MESH_INDEX (eed, &iter, em->bm, BM_EDGES_OF_MESH, i) { + if (edges_mask && !BLI_BITMAP_TEST_BOOL(edges_mask, i)) { + continue; + } + float co[2][3]; + copy_v3_v3(co[0], eed->v1->co); + copy_v3_v3(co[1], eed->v2->co); + + BLI_bvhtree_insert(tree, i, co[0], 2); + } + BLI_assert(BLI_bvhtree_get_size(tree) == edges_num_active); + BLI_bvhtree_balance(tree); + } + + return tree; +} + +/* Builds a bvh tree where nodes are the edges of the given em */ +BVHTree *bvhtree_from_editmesh_edges_ex( + BVHTreeFromEditMesh *data, BMEditMesh *em, + const BLI_bitmap *edges_mask, int edges_num_active, + float epsilon, int tree_type, int axis) +{ + int edge_num = em->bm->totedge; + + BVHTree *tree = bvhtree_from_editmesh_edges_create_tree( + epsilon, tree_type, axis, + em, edge_num, edges_mask, edges_num_active); + + if (tree) { + memset(data, 0, sizeof(*data)); + data->tree = tree; + data->em = em; + data->nearest_callback = NULL; /* TODO */ + data->raycast_callback = NULL; /* TODO */ + /* TODO: not urgent however since users currently define own callbacks */ + data->nearest_to_ray_callback = NULL; + } + + return tree; +} +BVHTree *bvhtree_from_editmesh_edges( + BVHTreeFromEditMesh *data, BMEditMesh *em, + float epsilon, int tree_type, int axis) +{ + return bvhtree_from_editmesh_edges_ex( + data, em, + NULL, -1, + epsilon, tree_type, axis); +} + /* Builds a bvh tree where nodes are the edges of the given dm */ BVHTree *bvhtree_from_mesh_edges( BVHTreeFromMesh *data, DerivedMesh *dm, @@ -804,7 +875,7 @@ BVHTree *bvhtree_from_mesh_faces( * Builds a bvh tree where nodes are the given tessellated faces (note: does not copy given mfaces!). * \param vert_allocated if true, vert freeing will be done when freeing data. * \param face_allocated if true, face freeing will be done when freeing data. - * \param mask if not null, true elements give which faces to add to BVH tree. + * \param faces_mask: if not null, true elements give which faces to add to BVH tree. * \param numFaces_active if >= 0, number of active faces to add to BVH tree (else will be computed from mask). */ BVHTree *bvhtree_from_mesh_faces_ex( @@ -968,17 +1039,37 @@ static void bvhtree_from_mesh_looptri_setup_data( BVHTree *bvhtree_from_editmesh_looptri_ex( BVHTreeFromEditMesh *data, BMEditMesh *em, const BLI_bitmap *looptri_mask, int looptri_num_active, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvhCache) { /* BMESH specific check that we have tessfaces, - * we _could_ tessellate here but rather not - campbell - * - * this assert checks we have tessfaces, - * if not caller should use DM_ensure_tessface() */ + * we _could_ tessellate here but rather not - campbell */ - BVHTree *tree = bvhtree_from_editmesh_looptri_create_tree( - epsilon, tree_type, axis, - em, em->tottri, looptri_mask, looptri_num_active); + BVHTree *tree; + if (bvhCache) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_READ); + tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); + BLI_rw_mutex_unlock(&cache_rwlock); + if (tree == NULL) { + BLI_rw_mutex_lock(&cache_rwlock, THREAD_LOCK_WRITE); + tree = bvhcache_find(*bvhCache, BVHTREE_FROM_EM_LOOPTRI); + if (tree == NULL) { + tree = bvhtree_from_editmesh_looptri_create_tree( + epsilon, tree_type, axis, + em, em->tottri, looptri_mask, looptri_num_active); + if (tree) { + /* Save on cache for later use */ + /* printf("BVHTree built and saved on cache\n"); */ + bvhcache_insert(bvhCache, tree, BVHTREE_FROM_EM_LOOPTRI); + } + } + BLI_rw_mutex_unlock(&cache_rwlock); + } + } + else { + tree = bvhtree_from_editmesh_looptri_create_tree( + epsilon, tree_type, axis, + em, em->tottri, looptri_mask, looptri_num_active); + } if (tree) { data->tree = tree; @@ -987,17 +1078,18 @@ BVHTree *bvhtree_from_editmesh_looptri_ex( data->nearest_to_ray_callback = NULL; data->sphere_radius = 0.0f; data->em = em; + data->cached = bvhCache != NULL; } return tree; } BVHTree *bvhtree_from_editmesh_looptri( BVHTreeFromEditMesh *data, BMEditMesh *em, - float epsilon, int tree_type, int axis) + float epsilon, int tree_type, int axis, BVHCache **bvhCache) { return bvhtree_from_editmesh_looptri_ex( data, em, NULL, -1, - epsilon, tree_type, axis); + epsilon, tree_type, axis, bvhCache); } /** @@ -1045,6 +1137,9 @@ BVHTree *bvhtree_from_mesh_looptri( tree = bvhcache_find(dm->bvhCache, BVHTREE_FROM_LOOPTRI); if (tree == NULL) { int looptri_num = dm->getNumLoopTri(dm); + + /* this assert checks we have looptris, + * if not caller should use DM_ensure_looptri() */ BLI_assert(!(looptri_num == 0 && dm->getNumPolys(dm) != 0)); tree = bvhtree_from_mesh_looptri_create_tree( @@ -1102,7 +1197,9 @@ BVHTree *bvhtree_from_mesh_looptri_ex( void free_bvhtree_from_editmesh(struct BVHTreeFromEditMesh *data) { if (data->tree) { - BLI_bvhtree_free(data->tree); + if (!data->cached) { + BLI_bvhtree_free(data->tree); + } memset(data, 0, sizeof(*data)); } } diff --git a/source/blender/blenkernel/intern/camera.c b/source/blender/blenkernel/intern/camera.c index 96bac2c2f41..cd085816b4d 100644 --- a/source/blender/blenkernel/intern/camera.c +++ b/source/blender/blenkernel/intern/camera.c @@ -49,6 +49,8 @@ #include "BKE_object.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -91,71 +93,54 @@ void *BKE_camera_add(Main *bmain, const char *name) return cam; } -Camera *BKE_camera_copy(Camera *cam) +Camera *BKE_camera_copy(Main *bmain, Camera *cam) { Camera *camn; - camn = BKE_libblock_copy(&cam->id); + camn = BKE_libblock_copy(bmain, &cam->id); - id_lib_extern((ID *)camn->dof_ob); - - if (cam->id.lib) { - BKE_id_lib_local_paths(G.main, cam->id.lib, &camn->id); + if (ID_IS_LINKED_DATABLOCK(cam)) { + BKE_id_expand_local(&camn->id); + BKE_id_lib_local_paths(bmain, cam->id.lib, &camn->id); } return camn; } -void BKE_camera_make_local(Camera *cam) +void BKE_camera_make_local(Main *bmain, Camera *cam, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (cam->id.lib == NULL) return; - if (cam->id.us == 1) { - id_clear_lib_data(bmain, &cam->id); + + if (!ID_IS_LINKED_DATABLOCK(cam)) { return; } - - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == cam) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &cam->id); - } - else if (is_local && is_lib) { - Camera *cam_new = BKE_camera_copy(cam); - cam_new->id.us = 0; + BKE_library_ID_test_usages(bmain, cam, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &cam->id); + BKE_id_expand_local(&cam->id); + } + else { + Camera *cam_new = BKE_camera_copy(bmain, cam); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, cam->id.lib, &cam_new->id); + cam_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == cam) { - if (ob->id.lib == NULL) { - ob->data = cam_new; - id_us_plus(&cam_new->id); - id_us_min(&cam->id); - } - } + BKE_libblock_remap(bmain, cam, cam_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } +/** Free (or release) any data used by this camera (does not free the camera itself). */ void BKE_camera_free(Camera *ca) { - BKE_animdata_free((ID *)ca); + BKE_animdata_free((ID *)ca, false); } /******************************** Camera Usage *******************************/ diff --git a/source/blender/blenkernel/intern/cdderivedmesh.c b/source/blender/blenkernel/intern/cdderivedmesh.c index 267f7a65e00..159d5b82a6c 100644 --- a/source/blender/blenkernel/intern/cdderivedmesh.c +++ b/source/blender/blenkernel/intern/cdderivedmesh.c @@ -61,8 +61,6 @@ #include "GPU_shader.h" #include "GPU_basic_shader.h" -#include "WM_api.h" - #include <string.h> #include <limits.h> #include <math.h> @@ -699,10 +697,10 @@ static void cdDM_drawMappedFaces( } if ((orig != ORIGINDEX_NONE) && !is_hidden) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); } else if (orig != ORIGINDEX_NONE) - WM_framebuffer_index_get(orig + 1, &selcol); + GPU_select_index_get(orig + 1, &selcol); for (j = 0; j < mpoly->totloop; j++) fi_map[start_element++] = selcol; diff --git a/source/blender/blenkernel/intern/colortools.c b/source/blender/blenkernel/intern/colortools.c index c1f1f0128f5..53a74024c51 100644 --- a/source/blender/blenkernel/intern/colortools.c +++ b/source/blender/blenkernel/intern/colortools.c @@ -982,6 +982,7 @@ static void save_sample_line(Scopes *scopes, const int idx, const float fx, cons /* waveform */ switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: + case SCOPES_WAVEFRM_RGB_PARADE: scopes->waveform_1[idx + 0] = fx; scopes->waveform_1[idx + 1] = rgb[0]; scopes->waveform_2[idx + 0] = fx; @@ -1265,6 +1266,8 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * switch (scopes->wavefrm_mode) { case SCOPES_WAVEFRM_RGB: + /* fall-through */ + case SCOPES_WAVEFRM_RGB_PARADE: ycc_mode = -1; break; case SCOPES_WAVEFRM_LUMA: @@ -1322,7 +1325,7 @@ void scopes_update(Scopes *scopes, ImBuf *ibuf, const ColorManagedViewSettings * .cm_processor = cm_processor, .display_buffer = display_buffer, .ycc_mode = ycc_mode, .bin_lum = bin_lum, .bin_r = bin_r, .bin_g = bin_g, .bin_b = bin_b, .bin_a = bin_a, }; - ScopesUpdateDataChunk data_chunk = {0}; + ScopesUpdateDataChunk data_chunk = {{0}}; INIT_MINMAX(data_chunk.min, data_chunk.max); BLI_task_parallel_range_finalize(0, ibuf->y, &data, &data_chunk, sizeof(data_chunk), diff --git a/source/blender/blenkernel/intern/constraint.c b/source/blender/blenkernel/intern/constraint.c index a591d536b43..4c9ddd495e3 100644 --- a/source/blender/blenkernel/intern/constraint.c +++ b/source/blender/blenkernel/intern/constraint.c @@ -2195,7 +2195,7 @@ static void actcon_get_tarmat(bConstraint *con, bConstraintOb *cob, bConstraintT } else if (cob->type == CONSTRAINT_OBTYPE_BONE) { Object workob; - bPose pose = {0}; + bPose pose = {{0}}; bPoseChannel *pchan, *tchan; /* make a copy of the bone of interest in the temp pose before evaluating action, so that it can get set @@ -4649,7 +4649,7 @@ void BKE_constraints_id_loop(ListBase *conlist, ConstraintIDFunc func, void *use /* helper for BKE_constraints_copy(), to be used for making sure that ID's are valid */ static void con_extern_cb(bConstraint *UNUSED(con), ID **idpoin, bool UNUSED(is_reference), void *UNUSED(userData)) { - if (*idpoin && (*idpoin)->lib) + if (*idpoin && ID_IS_LINKED_DATABLOCK(*idpoin)) id_lib_extern(*idpoin); } diff --git a/source/blender/blenkernel/intern/crazyspace.c b/source/blender/blenkernel/intern/crazyspace.c index c8de0786697..56df8e51eba 100644 --- a/source/blender/blenkernel/intern/crazyspace.c +++ b/source/blender/blenkernel/intern/crazyspace.c @@ -39,6 +39,7 @@ #include "DNA_meshdata_types.h" #include "BLI_utildefines.h" +#include "BLI_linklist.h" #include "BLI_math.h" #include "BKE_crazyspace.h" @@ -275,7 +276,13 @@ int BKE_crazyspace_get_first_deform_matrices_editbmesh(Scene *scene, Object *ob, if (mti->type == eModifierTypeType_OnlyDeform && mti->deformMatricesEM) { if (!defmats) { - dm = getEditDerivedBMesh(em, ob, NULL); + const int required_mode = eModifierMode_Realtime | eModifierMode_Editmode; + CustomDataMask data_mask = CD_MASK_BAREMESH; + CDMaskLink *datamasks = modifiers_calcDataMasks(scene, ob, md, data_mask, required_mode, NULL, 0); + data_mask = datamasks->mask; + BLI_linklist_free((LinkNode *)datamasks, NULL); + + dm = getEditDerivedBMesh(em, ob, data_mask, NULL); deformedVerts = editbmesh_get_vertex_cos(em, &numVerts); defmats = MEM_mallocN(sizeof(*defmats) * numVerts, "defmats"); diff --git a/source/blender/blenkernel/intern/curve.c b/source/blender/blenkernel/intern/curve.c index 8afb451f768..693e7eb0c80 100644 --- a/source/blender/blenkernel/intern/curve.c +++ b/source/blender/blenkernel/intern/curve.c @@ -58,6 +58,8 @@ #include "BKE_global.h" #include "BKE_key.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_object.h" #include "BKE_material.h" @@ -69,36 +71,6 @@ static int cu_isectLL(const float v1[3], const float v2[3], const float v3[3], c short cox, short coy, float *lambda, float *mu, float vec[3]); -void BKE_curve_unlink(Curve *cu) -{ - int a; - - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a]) - id_us_min(&cu->mat[a]->id); - cu->mat[a] = NULL; - } - if (cu->vfont) - id_us_min(&cu->vfont->id); - cu->vfont = NULL; - - if (cu->vfontb) - id_us_min(&cu->vfontb->id); - cu->vfontb = NULL; - - if (cu->vfonti) - id_us_min(&cu->vfonti->id); - cu->vfonti = NULL; - - if (cu->vfontbi) - id_us_min(&cu->vfontbi->id); - cu->vfontbi = NULL; - - if (cu->key) - id_us_min(&cu->key->id); - cu->key = NULL; -} - /* frees editcurve entirely */ void BKE_curve_editfont_free(Curve *cu) { @@ -136,26 +108,21 @@ void BKE_curve_editNurb_free(Curve *cu) } } -/* don't free curve itself */ +/** Free (or release) any data used by this curve (does not free the curve itself). */ void BKE_curve_free(Curve *cu) { + BKE_animdata_free((ID *)cu, false); + BKE_nurbList_free(&cu->nurb); BKE_curve_editfont_free(cu); BKE_curve_editNurb_free(cu); - BKE_curve_unlink(cu); - BKE_animdata_free((ID *)cu); - - if (cu->mat) - MEM_freeN(cu->mat); - if (cu->str) - MEM_freeN(cu->str); - if (cu->strinfo) - MEM_freeN(cu->strinfo); - if (cu->bb) - MEM_freeN(cu->bb); - if (cu->tb) - MEM_freeN(cu->tb); + + MEM_SAFE_FREE(cu->mat); + MEM_SAFE_FREE(cu->str); + MEM_SAFE_FREE(cu->strinfo); + MEM_SAFE_FREE(cu->bb); + MEM_SAFE_FREE(cu->tb); } void BKE_curve_init(Curve *cu) @@ -207,12 +174,13 @@ Curve *BKE_curve_add(Main *bmain, const char *name, int type) return cu; } -Curve *BKE_curve_copy(Curve *cu) +Curve *BKE_curve_copy(Main *bmain, Curve *cu) { Curve *cun; int a; - cun = BKE_libblock_copy(&cu->id); + cun = BKE_libblock_copy(bmain, &cu->id); + BLI_listbase_clear(&cun->nurb); BKE_nurbList_duplicate(&(cun->nurb), &(cu->nurb)); @@ -226,86 +194,53 @@ Curve *BKE_curve_copy(Curve *cu) cun->tb = MEM_dupallocN(cu->tb); cun->bb = MEM_dupallocN(cu->bb); - cun->key = BKE_key_copy(cu->key); - if (cun->key) cun->key->from = (ID *)cun; + if (cu->key) { + cun->key = BKE_key_copy(bmain, cu->key); + cun->key->from = (ID *)cun; + } cun->editnurb = NULL; cun->editfont = NULL; -#if 0 // XXX old animation system - /* single user ipo too */ - if (cun->ipo) cun->ipo = copy_ipo(cun->ipo); -#endif // XXX old animation system - id_us_plus((ID *)cun->vfont); id_us_plus((ID *)cun->vfontb); id_us_plus((ID *)cun->vfonti); id_us_plus((ID *)cun->vfontbi); - if (cu->id.lib) { - BKE_id_lib_local_paths(G.main, cu->id.lib, &cun->id); + if (ID_IS_LINKED_DATABLOCK(cu)) { + BKE_id_expand_local(&cun->id); + BKE_id_lib_local_paths(bmain, cu->id.lib, &cun->id); } return cun; } -static void extern_local_curve(Curve *cu) -{ - id_lib_extern((ID *)cu->vfont); - id_lib_extern((ID *)cu->vfontb); - id_lib_extern((ID *)cu->vfonti); - id_lib_extern((ID *)cu->vfontbi); - - if (cu->mat) { - extern_local_matarar(cu->mat, cu->totcol); - } -} - -void BKE_curve_make_local(Curve *cu) +void BKE_curve_make_local(Main *bmain, Curve *cu, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - when there are only lib users: don't do + /* - only lib users: do nothing (unless force_local is set) * - when there are only local users: set flag * - mixed: do a copy */ - if (cu->id.lib == NULL) - return; - - if (cu->id.us == 1) { - id_clear_lib_data(bmain, &cu->id); - extern_local_curve(cu); + if (!ID_IS_LINKED_DATABLOCK(cu)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == cu) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } + BKE_library_ID_test_usages(bmain, cu, &is_local, &is_lib); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &cu->id); - extern_local_curve(cu); - } - else if (is_local && is_lib) { - Curve *cu_new = BKE_curve_copy(cu); - cu_new->id.us = 0; + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &cu->id); + BKE_id_expand_local(&cu->id); + } + else { + Curve *cu_new = BKE_curve_copy(bmain, cu); - BKE_id_lib_local_paths(bmain, cu->id.lib, &cu_new->id); + cu_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == cu) { - if (ob->id.lib == NULL) { - ob->data = cu_new; - id_us_plus(&cu_new->id); - id_us_min(&cu->id); - } - } + BKE_libblock_remap(bmain, cu, cu_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -1419,6 +1354,71 @@ void BKE_nurb_makeCurve(Nurb *nu, float *coord_array, float *tilt_array, float * MEM_freeN(basisu); } +/** + * Calculate the length for arrays filled in by #BKE_curve_calc_coords_axis. + */ +unsigned int BKE_curve_calc_coords_axis_len( + const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint) +{ + const unsigned int segments = bezt_array_len - (is_cyclic ? 0 : 1); + const unsigned int points_len = (segments * resolu) + (is_cyclic ? (use_cyclic_duplicate_endpoint) : 1); + return points_len; +} + +/** + * Calculate an array for the entire curve (cyclic or non-cyclic). + * \note Call for each axis. + * + * \param use_cyclic_duplicate_endpoint: Duplicate values at the beginning & end of the array. + */ +void BKE_curve_calc_coords_axis( + const BezTriple *bezt_array, const unsigned int bezt_array_len, const unsigned int resolu, + const bool is_cyclic, const bool use_cyclic_duplicate_endpoint, + /* array params */ + const unsigned int axis, const unsigned int stride, + float *r_points) +{ + const unsigned int points_len = BKE_curve_calc_coords_axis_len( + bezt_array_len, resolu, is_cyclic, use_cyclic_duplicate_endpoint); + float *r_points_offset = r_points; + + const unsigned int resolu_stride = resolu * stride; + const unsigned int bezt_array_last = bezt_array_len - 1; + + for (unsigned int i = 0; i < bezt_array_last; i++) { + const BezTriple *bezt_curr = &bezt_array[i]; + const BezTriple *bezt_next = &bezt_array[i + 1]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + } + + if (is_cyclic) { + const BezTriple *bezt_curr = &bezt_array[bezt_array_last]; + const BezTriple *bezt_next = &bezt_array[0]; + BKE_curve_forward_diff_bezier( + bezt_curr->vec[1][axis], bezt_curr->vec[2][axis], + bezt_next->vec[0][axis], bezt_next->vec[1][axis], + r_points_offset, (int)resolu, stride); + r_points_offset = POINTER_OFFSET(r_points_offset, resolu_stride); + if (use_cyclic_duplicate_endpoint) { + *r_points_offset = *r_points; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + } + else { + float *r_points_last = POINTER_OFFSET(r_points, bezt_array_last * resolu_stride); + *r_points_last = bezt_array[bezt_array_last].vec[1][axis]; + r_points_offset = POINTER_OFFSET(r_points_offset, stride); + } + + BLI_assert(POINTER_OFFSET(r_points, points_len * stride) == r_points_offset); + UNUSED_VARS_NDEBUG(points_len); +} + /* forward differencing method for bezier curve */ void BKE_curve_forward_diff_bezier(float q0, float q1, float q2, float q3, float *p, int it, int stride) { diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c index f37b4c83061..7a3071227e6 100644 --- a/source/blender/blenkernel/intern/depsgraph.c +++ b/source/blender/blenkernel/intern/depsgraph.c @@ -772,7 +772,7 @@ static void build_dag_object(DagForest *dag, DagNode *scenenode, Main *bmain, Sc dag_add_relation(dag, node, node, DAG_RL_OB_DATA, "Particle-Object Relation"); - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) { @@ -2287,7 +2287,7 @@ static void dag_object_time_update_flags(Main *bmain, Scene *scene, Object *ob) ParticleSystem *psys = ob->particlesystem.first; for (; psys; psys = psys->next) { - if (psys_check_enabled(ob, psys)) { + if (psys_check_enabled(ob, psys, G.is_rendering)) { ob->recalc |= OB_RECALC_DATA; break; } diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index 98cbe47c7f9..49db75a0474 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -71,7 +71,7 @@ void BKE_displist_elem_free(DispList *dl) if (dl->verts) MEM_freeN(dl->verts); if (dl->nors) MEM_freeN(dl->nors); if (dl->index) MEM_freeN(dl->index); - if (dl->bevelSplitFlag) MEM_freeN(dl->bevelSplitFlag); + if (dl->bevel_split) MEM_freeN(dl->bevel_split); MEM_freeN(dl); } } @@ -144,8 +144,9 @@ void BKE_displist_copy(ListBase *lbn, ListBase *lb) dln->nors = MEM_dupallocN(dl->nors); dln->index = MEM_dupallocN(dl->index); - if (dl->bevelSplitFlag) - dln->bevelSplitFlag = MEM_dupallocN(dl->bevelSplitFlag); + if (dl->bevel_split) { + dln->bevel_split = MEM_dupallocN(dl->bevel_split); + } dl = dl->next; } @@ -1629,7 +1630,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba if (dlb->type == DL_POLY) { dl->flag |= DL_CYCL_U; } - if ((bl->poly >= 0) && (steps != 2)) { + if ((bl->poly >= 0) && (steps > 2)) { dl->flag |= DL_CYCL_V; } @@ -1642,8 +1643,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba /* CU_2D conflicts with R_NOPUNOFLIP */ dl->rt = nu->flag & ~CU_2D; - dl->bevelSplitFlag = MEM_callocN(sizeof(*dl->bevelSplitFlag) * ((steps + 0x1F) >> 5), - "bevelSplitFlag"); + dl->bevel_split = BLI_BITMAP_NEW(steps, "bevel_split"); /* for each point of poly make a bevel piece */ bevp_first = bl->bevpoints; @@ -1683,7 +1683,7 @@ static void do_makeDispListCurveTypes(Scene *scene, Object *ob, ListBase *dispba } if (bevp->split_tag) { - dl->bevelSplitFlag[a >> 5] |= 1 << (a & 0x1F); + BLI_BITMAP_ENABLE(dl->bevel_split, a); } /* rotate bevel piece and write in data */ diff --git a/source/blender/blenkernel/intern/dynamicpaint.c b/source/blender/blenkernel/intern/dynamicpaint.c index 1df4effebf1..7f54c81542b 100644 --- a/source/blender/blenkernel/intern/dynamicpaint.c +++ b/source/blender/blenkernel/intern/dynamicpaint.c @@ -1826,14 +1826,14 @@ static DerivedMesh *dynamicPaint_Modifier_apply( DynamicPaintModifierApplyData data = {.surface = surface, .fcolor = fcolor}; BLI_task_parallel_range(0, sData->total_points, &data, dynamic_paint_apply_surface_vpaint_blend_cb, - sData->total_points > 1000); + sData->total_points > 1000); /* paint layer */ MLoopCol *mloopcol = CustomData_get_layer_named(&result->loopData, CD_MLOOPCOL, surface->output_name); /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol && dynamicPaint_outputLayerExists(surface, ob, 0)) { mloopcol = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); + &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name); } /* wet layer */ @@ -1841,7 +1841,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply( /* if output layer is lost from a constructive modifier, re-add it */ if (!mloopcol_wet && dynamicPaint_outputLayerExists(surface, ob, 1)) { mloopcol_wet = CustomData_add_layer_named( - &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); + &result->loopData, CD_MLOOPCOL, CD_CALLOC, NULL, totloop, surface->output_name2); } /* Save preview results to weight layer to be able to share same drawing methods */ @@ -1850,7 +1850,7 @@ static DerivedMesh *dynamicPaint_Modifier_apply( mloopcol_preview = CustomData_get_layer(&result->loopData, CD_PREVIEW_MLOOPCOL); if (!mloopcol_preview) { mloopcol_preview = CustomData_add_layer( - &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); + &result->loopData, CD_PREVIEW_MLOOPCOL, CD_CALLOC, NULL, totloop); } } @@ -2249,7 +2249,7 @@ static void dynamic_paint_create_uv_surface_neighbor_cb(void *userdata, const in /* tri index */ /* There is a low possibility of actually having a neighbor point which tri is * already set from another neighbor in a separate thread here. - * Cheking for both tri_index and neighbour_pixel above reduces that probability + * Checking for both tri_index and neighbour_pixel above reduces that probability * but it remains possible. * That atomic op (and its memory fence) ensures tPoint->neighbour_pixel is set * to non--1 *before* its tri_index is set (i.e. that it cannot be used a neighbour). @@ -2367,15 +2367,15 @@ static int dynamic_paint_find_neighbour_pixel( edge1_index = 0; edge2_index = 1; dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv); /* Dist to second edge */ t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[1]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv); if (t_dist_squared < dist_squared) { e1_index = cPoint->v2; e2_index = cPoint->v3; @@ -2386,9 +2386,9 @@ static int dynamic_paint_find_neighbour_pixel( /* Dist to third edge */ t_dist_squared = dist_squared_to_line_segment_v2( - pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv); + pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[2]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[0]].uv); if (t_dist_squared < dist_squared) { e1_index = cPoint->v3; e2_index = cPoint->v1; @@ -2439,9 +2439,9 @@ static int dynamic_paint_find_neighbour_pixel( //printf("connected UV : %f,%f & %f,%f - %f,%f & %f,%f\n", s_uv1[0], s_uv1[1], s_uv2[0], s_uv2[1], t_uv1[0], t_uv1[1], t_uv2[0], t_uv2[1]); if (((s_uv1[0] == t_uv1[0] && s_uv1[1] == t_uv1[1]) && - (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) || - ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && - (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]))) + (s_uv2[0] == t_uv2[0] && s_uv2[1] == t_uv2[1])) || + ((s_uv2[0] == t_uv1[0] && s_uv2[1] == t_uv1[1]) && + (s_uv1[0] == t_uv2[0] && s_uv1[1] == t_uv2[1]))) { return ((px + neighX[n_index]) + w * (py + neighY[n_index])); } @@ -2451,15 +2451,15 @@ static int dynamic_paint_find_neighbour_pixel( * on this other face UV */ lambda = closest_to_line_v2( - closest_point, pixel, - mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv, - mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv); + closest_point, pixel, + mloopuv[mlooptri[cPoint->tri_index].tri[edge1_index]].uv, + mloopuv[mlooptri[cPoint->tri_index].tri[edge2_index]].uv); CLAMP(lambda, 0.0f, 1.0f); sub_v2_v2v2( - dir_vec, - mloopuv[mlooptri[target_tri].tri[target_uv2]].uv, - mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); + dir_vec, + mloopuv[mlooptri[target_tri].tri[target_uv2]].uv, + mloopuv[mlooptri[target_tri].tri[target_uv1]].uv); mul_v2_fl(dir_vec, lambda); @@ -2678,8 +2678,8 @@ int dynamicPaint_createUVSurface(Scene *scene, DynamicPaintSurface *surface, flo ImgSeqFormatData *f_data = MEM_callocN(sizeof(*f_data), "ImgSeqFormatData"); if (f_data) { f_data->uv_p = MEM_callocN(active_points * sizeof(*f_data->uv_p), "PaintUVPoint"); - f_data->barycentricWeights = MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), - "PaintUVPoint"); + f_data->barycentricWeights = + MEM_callocN(active_points * aa_samples * sizeof(*f_data->barycentricWeights), "PaintUVPoint"); if (!f_data->uv_p || !f_data->barycentricWeights) error = 1; @@ -2881,7 +2881,7 @@ void dynamicPaint_outputSurfaceImage(DynamicPaintSurface *surface, char *filenam } DynamicPaintOutputSurfaceImageData data = {.surface = surface, .ibuf = ibuf}; - switch(surface->type) { + switch (surface->type) { case MOD_DPAINT_SURFACE_T_PAINT: switch (output_layer) { case 0: @@ -3830,7 +3830,7 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, const float brush_radius = brush->paint_distance * surface->radius_scale; int numOfVerts; int ii; - Bounds3D mesh_bb = {0}; + Bounds3D mesh_bb = {{0}}; VolumeGrid *grid = bData->grid; dm = CDDM_copy(brush->dm); @@ -3883,12 +3883,12 @@ static int dynamicPaint_paintMesh(DynamicPaintSurface *surface, /* loop through cell points and process brush */ DynamicPaintPaintData data = { - .surface = surface, + .surface = surface, .brush = brush, .brushOb = brushOb, .bMats = bMats, .scene = scene, .timescale = timescale, .c_index = c_index, - .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, - .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, - .treeData = &treeData + .dm = dm, .mvert = mvert, .mloop = mloop, .mlooptri = mlooptri, + .brush_radius = brush_radius, .avg_brushNor = avg_brushNor, .brushVelocity = brushVelocity, + .treeData = &treeData }; BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, dynamic_paint_paint_mesh_cell_point_cb_ex, @@ -4100,7 +4100,7 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, const float range = solidradius + smooth; - Bounds3D part_bb = {0}; + Bounds3D part_bb = {{0}}; if (psys->totpart < 1) return 1; @@ -4170,10 +4170,10 @@ static int dynamicPaint_paintParticles(DynamicPaintSurface *surface, /* loop through cell points */ DynamicPaintPaintData data = { - .surface = surface, + .surface = surface, .brush = brush, .psys = psys, .solidradius = solidradius, .timescale = timescale, .c_index = c_index, - .treeData = tree, + .treeData = tree, }; BLI_task_parallel_range_ex(0, grid->s_num[c_index], &data, NULL, 0, dynamic_paint_paint_particle_cell_point_cb_ex, @@ -4313,16 +4313,16 @@ static int dynamicPaint_paintSinglePoint( * Loop through every surface point */ DynamicPaintPaintData data = { - .surface = surface, - .brush = brush, .brushOb = brushOb, .bMats = bMats, - .scene = scene, .timescale = timescale, - .mvert = mvert, - .brush_radius = brush_radius, .brushVelocity = &brushVel, + .surface = surface, + .brush = brush, .brushOb = brushOb, .bMats = bMats, + .scene = scene, .timescale = timescale, + .mvert = mvert, + .brush_radius = brush_radius, .brushVelocity = &brushVel, .pointCoord = pointCoord, }; BLI_task_parallel_range_ex(0, sData->total_points, &data, NULL, 0, - dynamic_paint_paint_single_point_cb_ex, - sData->total_points > 1000, true); + dynamic_paint_paint_single_point_cb_ex, + sData->total_points > 1000, true); return 1; } @@ -4754,83 +4754,83 @@ static void dynamic_paint_effect_drip_cb(void *userdata, const int index) { const DynamicPaintEffectData *data = userdata; - const DynamicPaintSurface *surface = data->surface; - const PaintSurfaceData *sData = surface->data; - BakeAdjPoint *bNeighs = sData->bData->bNeighs; - PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; - const PaintPoint *prevPoint = data->prevPoint; - const PaintPoint *pPoint_prev = &prevPoint[index]; - const float *force = data->force; - const float eff_scale = data->eff_scale; + const DynamicPaintSurface *surface = data->surface; + const PaintSurfaceData *sData = surface->data; + BakeAdjPoint *bNeighs = sData->bData->bNeighs; + PaintPoint *pPoint = &((PaintPoint *)sData->type_data)[index]; + const PaintPoint *prevPoint = data->prevPoint; + const PaintPoint *pPoint_prev = &prevPoint[index]; + const float *force = data->force; + const float eff_scale = data->eff_scale; - const int *n_target = sData->adj_data->n_target; + const int *n_target = sData->adj_data->n_target; - uint8_t *point_locks = data->point_locks; + uint8_t *point_locks = data->point_locks; - int closest_id[2]; - float closest_d[2]; + int closest_id[2]; + float closest_d[2]; - /* adjust drip speed depending on wetness */ - float w_factor = pPoint_prev->wetness - 0.025f; - if (w_factor <= 0) - return; - CLAMP(w_factor, 0.0f, 1.0f); + /* adjust drip speed depending on wetness */ + float w_factor = pPoint_prev->wetness - 0.025f; + if (w_factor <= 0) + return; + CLAMP(w_factor, 0.0f, 1.0f); - /* get force affect points */ - surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id); + /* get force affect points */ + surface_determineForceTargetPoints(sData, index, &force[index * 4], closest_d, closest_id); - /* Apply movement towards those two points */ - for (int i = 0; i < 2; i++) { - const int n_idx = closest_id[i]; - if (n_idx != -1 && closest_d[i] > 0.0f) { - const float dir_dot = closest_d[i]; + /* Apply movement towards those two points */ + for (int i = 0; i < 2; i++) { + const int n_idx = closest_id[i]; + if (n_idx != -1 && closest_d[i] > 0.0f) { + const float dir_dot = closest_d[i]; - /* just skip if angle is too extreme */ - if (dir_dot <= 0.0f) - continue; + /* just skip if angle is too extreme */ + if (dir_dot <= 0.0f) + continue; - float dir_factor, a_factor; - const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist; + float dir_factor, a_factor; + const float speed_scale = eff_scale * force[index * 4 + 3] / bNeighs[n_idx].dist; - const unsigned int n_trgt = (unsigned int)n_target[n_idx]; + const unsigned int n_trgt = (unsigned int)n_target[n_idx]; - /* Sort of spinlock, but only for given ePoint. - * Since the odds a same ePoint is modified at the same time by several threads is very low, this is - * much more eficient than a global spin lock. */ - const unsigned int pointlock_idx = n_trgt / 8; - const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ - while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask); + /* Sort of spinlock, but only for given ePoint. + * Since the odds a same ePoint is modified at the same time by several threads is very low, this is + * much more efficient than a global spin lock. */ + const unsigned int pointlock_idx = n_trgt / 8; + const uint8_t pointlock_bitmask = 1 << (n_trgt & 7); /* 7 == 0b111 */ + while (atomic_fetch_and_or_uint8(&point_locks[pointlock_idx], pointlock_bitmask) & pointlock_bitmask); - PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt]; - const float e_wet = ePoint->wetness; + PaintPoint *ePoint = &((PaintPoint *)sData->type_data)[n_trgt]; + const float e_wet = ePoint->wetness; - dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor); + dir_factor = min_ff(0.5f, dir_dot * min_ff(speed_scale, 1.0f) * w_factor); - /* mix new wetness */ - ePoint->wetness += dir_factor; - CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); + /* mix new wetness */ + ePoint->wetness += dir_factor; + CLAMP(ePoint->wetness, 0.0f, MAX_WETNESS); - /* mix new color */ - a_factor = dir_factor / pPoint_prev->wetness; - CLAMP(a_factor, 0.0f, 1.0f); - mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor); - /* dripping is supposed to preserve alpha level */ - if (pPoint_prev->e_color[3] > ePoint->e_color[3]) { - ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3]; - CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]); - } + /* mix new color */ + a_factor = dir_factor / pPoint_prev->wetness; + CLAMP(a_factor, 0.0f, 1.0f); + mixColors(ePoint->e_color, ePoint->e_color[3], pPoint_prev->e_color, pPoint_prev->e_color[3], a_factor); + /* dripping is supposed to preserve alpha level */ + if (pPoint_prev->e_color[3] > ePoint->e_color[3]) { + ePoint->e_color[3] += a_factor * pPoint_prev->e_color[3]; + CLAMP_MAX(ePoint->e_color[3], pPoint_prev->e_color[3]); + } - /* decrease paint wetness on current point */ - pPoint->wetness -= (ePoint->wetness - e_wet); - CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); + /* decrease paint wetness on current point */ + pPoint->wetness -= (ePoint->wetness - e_wet); + CLAMP(pPoint->wetness, 0.0f, MAX_WETNESS); #ifndef NDEBUG uint8_t ret = atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask); - BLI_assert(ret & pointlock_bitmask); + BLI_assert(ret & pointlock_bitmask); #else atomic_fetch_and_and_uint8(&point_locks[pointlock_idx], ~pointlock_bitmask); #endif - } + } } } @@ -4891,7 +4891,7 @@ static void dynamicPaint_doEffectStep( memcpy(prevPoint, sData->type_data, sData->total_points * sizeof(struct PaintPoint)); DynamicPaintEffectData data = { - .surface = surface, .prevPoint = prevPoint, + .surface = surface, .prevPoint = prevPoint, .eff_scale = eff_scale, .force = force, .point_locks = point_locks, }; @@ -5107,7 +5107,7 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index) if (pPoint->color[3]) { for (i = 0; i < 3; i++) { pPoint->color[i] = (f_color[i] * f_color[3] - pPoint->e_color[i] * pPoint->e_color[3]) / - (pPoint->color[3] * (1.0f - pPoint->e_color[3])); + (pPoint->color[3] * (1.0f - pPoint->e_color[3])); } } } @@ -5128,17 +5128,17 @@ static void dynamic_paint_surface_pre_step_cb(void *userdata, const int index) if (surface->flags & MOD_DPAINT_DISSOLVE) { value_dissolve(&pPoint->color[3], surface->diss_speed, timescale, - (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); + (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); CLAMP_MIN(pPoint->color[3], 0.0f); value_dissolve(&pPoint->e_color[3], surface->diss_speed, timescale, - (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); + (surface->flags & MOD_DPAINT_DISSOLVE_LOG) != 0); CLAMP_MIN(pPoint->e_color[3], 0.0f); } } /* dissolve for float types */ else if (surface->flags & MOD_DPAINT_DISSOLVE && - (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) + (surface->type == MOD_DPAINT_SURFACE_T_DISPLACE || surface->type == MOD_DPAINT_SURFACE_T_WEIGHT)) { float *point = &((float *)sData->type_data)[index]; /* log or linear */ @@ -5387,7 +5387,7 @@ static int dynamicPaint_generateBakeData(DynamicPaintSurface *surface, const Sce */ DynamicPaintGenerateBakeData data = { .surface = surface, .ob = ob, - .mvert = mvert, .canvas_verts = canvas_verts, + .mvert = mvert, .canvas_verts = canvas_verts, .do_velocity_data = do_velocity_data, .new_bdata = new_bdata, }; BLI_task_parallel_range( @@ -5502,7 +5502,7 @@ static int dynamicPaint_doStep(Scene *scene, Object *ob, DynamicPaintSurface *su if (brush->collision == MOD_DPAINT_COL_PSYS) { if (brush->psys && brush->psys->part && ELEM(brush->psys->part->type, PART_EMITTER, PART_FLUID) && - psys_check_enabled(brushObj, brush->psys)) + psys_check_enabled(brushObj, brush->psys, G.is_rendering)) { /* Paint a particle system */ BKE_animsys_evaluate_animdata(scene, &brush->psys->part->id, brush->psys->part->adt, diff --git a/source/blender/blenkernel/intern/editderivedmesh.c b/source/blender/blenkernel/intern/editderivedmesh.c index c1013342bd9..1aba76baa2c 100644 --- a/source/blender/blenkernel/intern/editderivedmesh.c +++ b/source/blender/blenkernel/intern/editderivedmesh.c @@ -2226,16 +2226,17 @@ static CustomData *bmDm_getPolyDataLayout(DerivedMesh *dm) return &bmdm->em->bm->pdata; } - +/** + * \note This may be called per-draw, + * avoid allocating large arrays where possible and keep this a thin wrapper for #BMesh. + */ DerivedMesh *getEditDerivedBMesh( - BMEditMesh *em, - Object *UNUSED(ob), + BMEditMesh *em, struct Object *UNUSED(ob), + CustomDataMask data_mask, float (*vertexCos)[3]) { EditDerivedBMesh *bmdm = MEM_callocN(sizeof(*bmdm), __func__); BMesh *bm = em->bm; - const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); - const int cd_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); bmdm->em = em; @@ -2304,6 +2305,9 @@ DerivedMesh *getEditDerivedBMesh( bmdm->vertexCos = (const float (*)[3])vertexCos; bmdm->dm.deformedOnly = (vertexCos != NULL); + const int cd_dvert_offset = (data_mask & CD_MASK_MDEFORMVERT) ? + CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT) : -1; + if (cd_dvert_offset != -1) { BMIter iter; BMVert *eve; @@ -2317,6 +2321,9 @@ DerivedMesh *getEditDerivedBMesh( } } + const int cd_skin_offset = (data_mask & CD_MASK_MVERT_SKIN) ? + CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN) : -1; + if (cd_skin_offset != -1) { BMIter iter; BMVert *eve; diff --git a/source/blender/blenkernel/intern/effect.c b/source/blender/blenkernel/intern/effect.c index a5c4be364d2..7bebf224e34 100644 --- a/source/blender/blenkernel/intern/effect.c +++ b/source/blender/blenkernel/intern/effect.c @@ -142,9 +142,6 @@ void free_partdeflect(PartDeflect *pd) if (!pd) return; - if (pd->tex) - id_us_min(&pd->tex->id); - if (pd->rng) BLI_rng_free(pd->rng); @@ -181,7 +178,7 @@ static void add_particles_to_effectors(EffectorContext *effctx, Scene *scene, Ef { ParticleSettings *part= psys->part; - if ( !psys_check_enabled(ob, psys) ) + if ( !psys_check_enabled(ob, psys, G.is_rendering) ) return; if ( psys == psys_src && (part->flag & PART_SELF_EFFECT) == 0) diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index 98757407e89..5e1f8814ed6 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -95,10 +95,9 @@ void BKE_vfont_free_data(struct VFont *vfont) } } +/** Free (or release) any data used by this font (does not free the font itself). */ void BKE_vfont_free(struct VFont *vf) { - if (vf == NULL) return; - BKE_vfont_free_data(vf); if (vf->packedfile) { @@ -628,6 +627,8 @@ bool BKE_vfont_to_curve_ex(Main *bmain, Object *ob, int mode, ListBase *r_nubase bool use_textbox; VChar *che; struct CharTrans *chartransdata = NULL, *ct; + /* Text at the beginning of the last used text-box (use for y-axis alignment). */ + int i_textbox = 0; struct TempLineInfo *lineinfo; float *f, xof, yof, xtrax, linedist; float twidth, maxlen = 0; @@ -830,6 +831,7 @@ makebreak: (cu->totbox > (curbox + 1)) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { + i_textbox = i + 1; maxlen = 0; curbox++; @@ -908,10 +910,10 @@ makebreak: /* linedata is now: width of line */ - if (cu->spacemode != CU_LEFT) { + if (cu->spacemode != CU_ALIGN_X_LEFT) { ct = chartransdata; - if (cu->spacemode == CU_RIGHT) { + if (cu->spacemode == CU_ALIGN_X_RIGHT) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -923,7 +925,7 @@ makebreak: ct++; } } - else if (cu->spacemode == CU_MIDDLE) { + else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -935,7 +937,7 @@ makebreak: ct++; } } - else if ((cu->spacemode == CU_FLUSH) && use_textbox) { + else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) { struct TempLineInfo *li; for (i = 0, li = lineinfo; i < lnr; i++, li++) { @@ -956,7 +958,7 @@ makebreak: ct++; } } - else if ((cu->spacemode == CU_JUSTIFY) && use_textbox) { + else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) { float curofs = 0.0f; for (i = 0; i <= slen; i++) { for (j = i; @@ -983,6 +985,60 @@ makebreak: } } + /* top-baseline is default, in this case, do nothing */ + if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) { + if (tb_scale.h != 0.0f) { + /* top and top-baseline are the same when text-boxes are used */ + if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) { + /* all previous textboxes are 'full', only align the last used text-box */ + float yoff; + int lines; + struct CharTrans *ct_last, *ct_textbox; + + ct_last = chartransdata + slen - 1; + ct_textbox = chartransdata + i_textbox; + + lines = ct_last->linenr - ct_textbox->linenr + 1; + if (mem[slen - 1] == '\n') { + lines++; + } + + if (cu->align_y == CU_ALIGN_Y_BOTTOM) { + yoff = (lines * linedist) - tb_scale.h; + } + else if (cu->align_y == CU_ALIGN_Y_CENTER) { + yoff = 0.5f * ((lines * linedist) - tb_scale.h); + } + + ct = ct_textbox; + for (i = i_textbox - 1; i < slen; i++) { + ct->yof += yoff; + ct++; + } + } + } + else { + /* non text-box case handled separately */ + ct = chartransdata; + float yoff; + + if (cu->align_y == CU_ALIGN_Y_TOP) { + yoff = -linedist; + } + else if (cu->align_y == CU_ALIGN_Y_BOTTOM) { + yoff = (lnr - 1.0f) * linedist; + } + else if (cu->align_y == CU_ALIGN_Y_CENTER) { + yoff = (lnr - 2.0f) * linedist * 0.5f; + } + + for (i = 0; i <= slen; i++) { + ct->yof += yoff; + ct++; + } + } + } + MEM_freeN(lineinfo); /* TEXT ON CURVE */ @@ -1021,13 +1077,13 @@ makebreak: /* path longer than text: spacemode involves */ distfac = 1.0f / distfac; - if (cu->spacemode == CU_RIGHT) { + if (cu->spacemode == CU_ALIGN_X_RIGHT) { timeofs = 1.0f - distfac; } - else if (cu->spacemode == CU_MIDDLE) { + else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { timeofs = (1.0f - distfac) / 2.0f; } - else if (cu->spacemode == CU_FLUSH) { + else if (cu->spacemode == CU_ALIGN_X_FLUSH) { distfac = 1.0f; } } diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index f3eb5430bce..ac4f566dc62 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -49,6 +49,7 @@ #include "BKE_global.h" #include "BKE_gpencil.h" #include "BKE_library.h" +#include "BKE_main.h" /* ************************************************** */ @@ -113,16 +114,13 @@ void free_gpencil_layers(ListBase *list) } /* Free all of GPencil datablock's related data, but not the block itself */ +/** Free (or release) any data used by this grease pencil (does not free the gpencil itself). */ void BKE_gpencil_free(bGPdata *gpd) { + BKE_animdata_free(&gpd->id, false); + /* free layers */ free_gpencil_layers(&gpd->layers); - - /* free animation data */ - if (gpd->adt) { - BKE_animdata_free(&gpd->id); - gpd->adt = NULL; - } } /* -------- Container Creation ---------- */ @@ -361,7 +359,7 @@ bGPDlayer *gpencil_layer_duplicate(bGPDlayer *src) } /* make a copy of a given gpencil datablock */ -bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy) +bGPdata *gpencil_data_duplicate(Main *bmain, bGPdata *src, bool internal_copy) { bGPDlayer *gpl, *gpld; bGPdata *dst; @@ -377,7 +375,7 @@ bGPdata *gpencil_data_duplicate(bGPdata *src, bool internal_copy) } else { /* make a copy when others use this */ - dst = BKE_libblock_copy(&src->id); + dst = BKE_libblock_copy(bmain, &src->id); } /* copy layers */ diff --git a/source/blender/blenkernel/intern/group.c b/source/blender/blenkernel/intern/group.c index a44eb1df9fe..11bbd91e9c9 100644 --- a/source/blender/blenkernel/intern/group.c +++ b/source/blender/blenkernel/intern/group.c @@ -60,79 +60,19 @@ static void free_group_object(GroupObject *go) MEM_freeN(go); } - +/** Free (or release) any data used by this group (does not free the group itself). */ void BKE_group_free(Group *group) { /* don't free group itself */ GroupObject *go; - BKE_previewimg_free(&group->preview); + /* No animdata here. */ while ((go = BLI_pophead(&group->gobject))) { free_group_object(go); } -} -void BKE_group_unlink(Main *bmain, Group *group) -{ - Material *ma; - Object *ob; - Scene *sce; - SceneRenderLayer *srl; - ParticleSystem *psys; - - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (ma = bmain->mat.first; ma; ma = ma->id.next) { - if (ma->group == group) - ma->group = NULL; - } - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - Base *base = sce->base.first; - - /* ensure objects are not in this group */ - for (; base; base = base->next) { - if (BKE_group_object_unlink(group, base->object, sce, base) && - BKE_group_object_find(NULL, base->object) == NULL) - { - base->object->flag &= ~OB_FROMGROUP; - base->flag &= ~OB_FROMGROUP; - } - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - FreestyleLineSet *lineset; - - if (srl->light_override == group) - srl->light_override = NULL; - for (lineset = srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { - if (lineset->group == group) - lineset->group = NULL; - } - } - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - - if (ob->dup_group == group) { - ob->dup_group = NULL; - } - - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys->part->dup_group == group) - psys->part->dup_group = NULL; -#if 0 /* not used anymore, only keps for readfile.c, no need to account for this */ - if (psys->part->eff_group == group) - psys->part->eff_group = NULL; -#endif - } - } - - /* group stays in library, but no members */ - BKE_group_free(group); - group->id.us = 0; + BKE_previewimg_free(&group->preview); } Group *BKE_group_add(Main *bmain, const char *name) @@ -147,18 +87,19 @@ Group *BKE_group_add(Main *bmain, const char *name) return group; } -Group *BKE_group_copy(Group *group) +Group *BKE_group_copy(Main *bmain, Group *group) { Group *groupn; - groupn = BKE_libblock_copy(&group->id); + groupn = BKE_libblock_copy(bmain, &group->id); BLI_duplicatelist(&groupn->gobject, &group->gobject); /* Do not copy group's preview (same behavior as for objects). */ groupn->preview = NULL; - if (group->id.lib) { - BKE_id_lib_local_paths(G.main, group->id.lib, &groupn->id); + if (ID_IS_LINKED_DATABLOCK(group)) { + BKE_id_expand_local(&groupn->id); + BKE_id_lib_local_paths(bmain, group->id.lib, &groupn->id); } return groupn; diff --git a/source/blender/blenkernel/intern/icons.c b/source/blender/blenkernel/intern/icons.c index f3e86b44459..63055dc0646 100644 --- a/source/blender/blenkernel/intern/icons.c +++ b/source/blender/blenkernel/intern/icons.c @@ -423,10 +423,26 @@ void BKE_icon_changed(int id) } } -int BKE_icon_id_ensure(struct ID *id) +static int icon_id_ensure_create_icon(struct ID *id) { Icon *new_icon = NULL; + new_icon = MEM_mallocN(sizeof(Icon), __func__); + + new_icon->obj = id; + new_icon->type = GS(id->name); + + /* next two lines make sure image gets created */ + new_icon->drawinfo = NULL; + new_icon->drawinfo_free = NULL; + + BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); + + return id->icon_id; +} + +int BKE_icon_id_ensure(struct ID *id) +{ if (!id || G.background) return 0; @@ -440,32 +456,39 @@ int BKE_icon_id_ensure(struct ID *id) return 0; } - new_icon = MEM_mallocN(sizeof(Icon), __func__); - - new_icon->obj = id; - new_icon->type = GS(id->name); - - /* next two lines make sure image gets created */ - new_icon->drawinfo = NULL; - new_icon->drawinfo_free = NULL; + /* Ensure we synchronize ID icon_id with its previewimage if it has one. */ + PreviewImage **p_prv = BKE_previewimg_id_get_p(id); + if (p_prv && *p_prv) { + BLI_assert(ELEM((*p_prv)->icon_id, 0, id->icon_id)); + (*p_prv)->icon_id = id->icon_id; + } - BLI_ghash_insert(gIcons, SET_INT_IN_POINTER(id->icon_id), new_icon); - - return id->icon_id; + return icon_id_ensure_create_icon(id); } /** * Return icon id of given preview, or create new icon if not found. */ -int BKE_icon_preview_ensure(PreviewImage *preview) +int BKE_icon_preview_ensure(ID *id, PreviewImage *preview) { Icon *new_icon = NULL; if (!preview || G.background) return 0; - if (preview->icon_id) + if (id) { + BLI_assert(BKE_previewimg_id_ensure(id) == preview); + } + + if (preview->icon_id) { + BLI_assert(!id || !id->icon_id || id->icon_id == preview->icon_id); return preview->icon_id; + } + + if (id && id->icon_id) { + preview->icon_id = id->icon_id; + return preview->icon_id; + } preview->icon_id = get_next_free_id(); @@ -474,6 +497,12 @@ int BKE_icon_preview_ensure(PreviewImage *preview) return 0; } + /* Ensure we synchronize ID icon_id with its previewimage if available, and generate suitable 'ID' icon. */ + if (id) { + id->icon_id = preview->icon_id; + return icon_id_ensure_create_icon(id); + } + new_icon = MEM_mallocN(sizeof(Icon), __func__); new_icon->obj = preview; diff --git a/source/blender/blenkernel/intern/idcode.c b/source/blender/blenkernel/intern/idcode.c index 899ed548783..90b3713e47c 100644 --- a/source/blender/blenkernel/intern/idcode.c +++ b/source/blender/blenkernel/intern/idcode.c @@ -124,7 +124,7 @@ static IDType *idtype_from_code(short idcode) /** * Return if the ID code is a valid ID code. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when invalid. */ bool BKE_idcode_is_valid(short idcode) @@ -135,7 +135,7 @@ bool BKE_idcode_is_valid(short idcode) /** * Return non-zero when an ID type is linkable. * - * \param code The code to check. + * \param idcode: The code to check. * \return Boolean, 0 when non linkable. */ bool BKE_idcode_is_linkable(short idcode) @@ -148,7 +148,7 @@ bool BKE_idcode_is_linkable(short idcode) /** * Convert an idcode into a name. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -261,7 +261,7 @@ short BKE_idcode_from_idfilter(const int idfilter) /** * Convert an idcode into a name (plural). * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the name of * the code. */ @@ -275,7 +275,7 @@ const char *BKE_idcode_to_name_plural(short idcode) /** * Convert an idcode into its translations' context. * - * \param code The code to convert. + * \param idcode: The code to convert. * \return A static string representing the i18n context of the code. */ const char *BKE_idcode_to_translation_context(short idcode) diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index ecebc7336a2..50ab365563a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -72,6 +72,8 @@ #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_packedFile.h" #include "BKE_report.h" @@ -95,8 +97,6 @@ #include "DNA_screen_types.h" #include "DNA_view3d_types.h" -#include "WM_api.h" - static SpinLock image_spin; /* prototypes */ @@ -324,20 +324,16 @@ void BKE_image_free_buffers(Image *ima) ima->ok = IMA_OK; } -/* called by library too, do not free ima itself */ +/** Free (or release) any data used by this image (does not free the image itself). */ void BKE_image_free(Image *ima) { int a; + /* Also frees animdata. */ BKE_image_free_buffers(ima); image_free_packedfiles(ima); - BKE_icon_id_delete(&ima->id); - ima->id.icon_id = 0; - - BKE_previewimg_free(&ima->preview); - for (a = 0; a < IMA_MAX_RENDER_SLOT; a++) { if (ima->renders[a]) { RE_FreeRenderResult(ima->renders[a]); @@ -346,7 +342,10 @@ void BKE_image_free(Image *ima) } BKE_image_free_views(ima); - MEM_freeN(ima->stereo3d_format); + MEM_SAFE_FREE(ima->stereo3d_format); + + BKE_icon_id_delete(&ima->id); + BKE_previewimg_free(&ima->preview); } /* only image block itself */ @@ -460,173 +459,42 @@ Image *BKE_image_copy(Main *bmain, Image *ima) nima->stereo3d_format = MEM_dupallocN(ima->stereo3d_format); BLI_duplicatelist(&nima->views, &ima->views); - if (ima->id.lib) { + nima->preview = BKE_previewimg_copy(ima->preview); + + if (ID_IS_LINKED_DATABLOCK(ima)) { + BKE_id_expand_local(&nima->id); BKE_id_lib_local_paths(bmain, ima->id.lib, &nima->id); } return nima; } -static void extern_local_image(Image *UNUSED(ima)) -{ - /* Nothing to do: images don't link to other IDs. This function exists to - * match id_make_local pattern. */ -} - -void BKE_image_make_local(struct Image *ima) +void BKE_image_make_local(Main *bmain, Image *ima, const bool force_local) { - Main *bmain = G.main; - Tex *tex; - Brush *brush; - Mesh *me; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (ima->id.lib == NULL) return; - - /* Can't take short cut here: must check meshes at least because of bogus - * texface ID refs. - z0r */ -#if 0 - if (ima->id.us == 1) { - id_clear_lib_data(bmain, &ima->id); - extern_local_image(ima); + if (!ID_IS_LINKED_DATABLOCK(ima)) { return; } -#endif - for (tex = bmain->tex.first; tex; tex = tex->id.next) { - if (tex->ima == ima) { - if (tex->id.lib) is_lib = true; - else is_local = true; - } - } - for (brush = bmain->brush.first; brush; brush = brush->id.next) { - if (brush->clone.image == ima) { - if (brush->id.lib) is_lib = true; - else is_local = true; - } - } - for (me = bmain->mesh.first; me; me = me->id.next) { - if (me->mtface) { - MTFace *tface; - int a, i; + BKE_library_ID_test_usages(bmain, ima, &is_local, &is_lib); - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) { - if (tface->tpage == ima) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - } + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &ima->id); + BKE_id_expand_local(&ima->id); } + else { + Image *ima_new = BKE_image_copy(bmain, ima); - if (me->mtpoly) { - MTexPoly *mtpoly; - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - mtpoly = (MTexPoly *)me->pdata.layers[i].data; + ima_new->id.us = 0; - for (a = 0; a < me->totpoly; a++, mtpoly++) { - if (mtpoly->tpage == ima) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - } - } - - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &ima->id); - extern_local_image(ima); - } - else if (is_local && is_lib) { - Image *ima_new = BKE_image_copy(bmain, ima); - - ima_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ima->id.lib, &ima_new->id); - - tex = bmain->tex.first; - while (tex) { - if (tex->id.lib == NULL) { - if (tex->ima == ima) { - tex->ima = ima_new; - id_us_plus(&ima_new->id); - id_us_min(&ima->id); - } - } - tex = tex->id.next; - } - brush = bmain->brush.first; - while (brush) { - if (brush->id.lib == NULL) { - if (brush->clone.image == ima) { - brush->clone.image = ima_new; - id_us_plus(&ima_new->id); - id_us_min(&ima->id); - } - } - brush = brush->id.next; - } - /* Transfer references in texfaces. Texfaces don't add to image ID - * user count *unless* there are no other users. See - * readfile.c:lib_link_mtface. */ - me = bmain->mesh.first; - while (me) { - if (me->mtface) { - MTFace *tface; - int a, i; - - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) { - if (tface->tpage == ima) { - tface->tpage = ima_new; - id_us_ensure_real((ID *)ima_new); - id_lib_extern((ID *)ima_new); - } - } - } - } - } - - if (me->mtpoly) { - MTexPoly *mtpoly; - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - mtpoly = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, mtpoly++) { - if (mtpoly->tpage == ima) { - mtpoly->tpage = ima_new; - id_us_ensure_real((ID *)ima_new); - id_lib_extern((ID *)ima_new); - } - } - } - } - } - - me = me->id.next; + BKE_libblock_remap(bmain, ima, ima_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -1215,43 +1083,55 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options) { memset(r_options, 0, sizeof(*r_options)); - if (imtype == R_IMF_IMTYPE_TARGA) + if (imtype == R_IMF_IMTYPE_TARGA) { return IMB_FTYPE_TGA; + } else if (imtype == R_IMF_IMTYPE_RAWTGA) { r_options->flag = RAWTGA; return IMB_FTYPE_TGA; } - else if (imtype == R_IMF_IMTYPE_IRIS) + else if (imtype == R_IMF_IMTYPE_IRIS) { return IMB_FTYPE_IMAGIC; + } #ifdef WITH_HDR - else if (imtype == R_IMF_IMTYPE_RADHDR) + else if (imtype == R_IMF_IMTYPE_RADHDR) { return IMB_FTYPE_RADHDR; + } #endif else if (imtype == R_IMF_IMTYPE_PNG) { r_options->quality = 15; return IMB_FTYPE_PNG; } #ifdef WITH_DDS - else if (imtype == R_IMF_IMTYPE_DDS) + else if (imtype == R_IMF_IMTYPE_DDS) { return IMB_FTYPE_DDS; + } #endif - else if (imtype == R_IMF_IMTYPE_BMP) + else if (imtype == R_IMF_IMTYPE_BMP) { return IMB_FTYPE_BMP; + } #ifdef WITH_TIFF - else if (imtype == R_IMF_IMTYPE_TIFF) + else if (imtype == R_IMF_IMTYPE_TIFF) { return IMB_FTYPE_TIF; + } #endif - else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) + else if (imtype == R_IMF_IMTYPE_OPENEXR || imtype == R_IMF_IMTYPE_MULTILAYER) { return IMB_FTYPE_OPENEXR; + } #ifdef WITH_CINEON - else if (imtype == R_IMF_IMTYPE_CINEON) + else if (imtype == R_IMF_IMTYPE_CINEON) { return IMB_FTYPE_CINEON; - else if (imtype == R_IMF_IMTYPE_DPX) + } + else if (imtype == R_IMF_IMTYPE_DPX) { return IMB_FTYPE_DPX; + } #endif #ifdef WITH_OPENJPEG - else if (imtype == R_IMF_IMTYPE_JP2) + else if (imtype == R_IMF_IMTYPE_JP2) { + r_options->flag |= JP2_JP2; + r_options->quality = 90; return IMB_FTYPE_JP2; + } #endif else { r_options->quality = 90; @@ -1261,46 +1141,60 @@ int BKE_image_imtype_to_ftype(const char imtype, ImbFormatOptions *r_options) char BKE_image_ftype_to_imtype(const int ftype, const ImbFormatOptions *options) { - if (ftype == 0) + if (ftype == 0) { return R_IMF_IMTYPE_TARGA; - else if (ftype == IMB_FTYPE_IMAGIC) + } + else if (ftype == IMB_FTYPE_IMAGIC) { return R_IMF_IMTYPE_IRIS; + } #ifdef WITH_HDR - else if (ftype == IMB_FTYPE_RADHDR) + else if (ftype == IMB_FTYPE_RADHDR) { return R_IMF_IMTYPE_RADHDR; + } #endif - else if (ftype == IMB_FTYPE_PNG) + else if (ftype == IMB_FTYPE_PNG) { return R_IMF_IMTYPE_PNG; + } #ifdef WITH_DDS - else if (ftype == IMB_FTYPE_DDS) + else if (ftype == IMB_FTYPE_DDS) { return R_IMF_IMTYPE_DDS; + } #endif - else if (ftype == IMB_FTYPE_BMP) + else if (ftype == IMB_FTYPE_BMP) { return R_IMF_IMTYPE_BMP; + } #ifdef WITH_TIFF - else if (ftype == IMB_FTYPE_TIF) + else if (ftype == IMB_FTYPE_TIF) { return R_IMF_IMTYPE_TIFF; + } #endif - else if (ftype == IMB_FTYPE_OPENEXR) + else if (ftype == IMB_FTYPE_OPENEXR) { return R_IMF_IMTYPE_OPENEXR; + } #ifdef WITH_CINEON - else if (ftype == IMB_FTYPE_CINEON) + else if (ftype == IMB_FTYPE_CINEON) { return R_IMF_IMTYPE_CINEON; - else if (ftype == IMB_FTYPE_DPX) + } + else if (ftype == IMB_FTYPE_DPX) { return R_IMF_IMTYPE_DPX; + } #endif else if (ftype == IMB_FTYPE_TGA) { - if (options && (options->flag & RAWTGA)) + if (options && (options->flag & RAWTGA)) { return R_IMF_IMTYPE_RAWTGA; - else + } + else { return R_IMF_IMTYPE_TARGA; + } } #ifdef WITH_OPENJPEG - else if (ftype == IMB_FTYPE_JP2) + else if (ftype == IMB_FTYPE_JP2) { return R_IMF_IMTYPE_JP2; + } #endif - else + else { return R_IMF_IMTYPE_JPEG90; + } } diff --git a/source/blender/blenkernel/intern/key.c b/source/blender/blenkernel/intern/key.c index 362f41335d2..a524f927cad 100644 --- a/source/blender/blenkernel/intern/key.c +++ b/source/blender/blenkernel/intern/key.c @@ -58,6 +58,7 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" #include "BKE_scene.h" @@ -74,11 +75,13 @@ #define IPO_BEZTRIPLE 100 #define IPO_BPOINT 101 + +/** Free (or release) any data used by this shapekey (does not free the key itself). */ void BKE_key_free(Key *key) { KeyBlock *kb; - - BKE_animdata_free((ID *)key); + + BKE_animdata_free((ID *)key, false); while ((kb = BLI_pophead(&key->block))) { if (kb->data) @@ -147,14 +150,12 @@ Key *BKE_key_add(ID *id) /* common function */ return key; } -Key *BKE_key_copy(Key *key) +Key *BKE_key_copy(Main *bmain, Key *key) { Key *keyn; KeyBlock *kbn, *kb; - if (key == NULL) return NULL; - - keyn = BKE_libblock_copy(&key->id); + keyn = BKE_libblock_copy(bmain, &key->id); BLI_duplicatelist(&keyn->block, &key->block); @@ -169,22 +170,19 @@ Key *BKE_key_copy(Key *key) kb = kb->next; } - if (key->id.lib) { - BKE_id_lib_local_paths(G.main, key->id.lib, &keyn->id); + if (ID_IS_LINKED_DATABLOCK(key)) { + BKE_id_expand_local(&keyn->id); + BKE_id_lib_local_paths(bmain, key->id.lib, &keyn->id); } return keyn; } - Key *BKE_key_copy_nolib(Key *key) { Key *keyn; KeyBlock *kbn, *kb; - if (key == NULL) - return NULL; - keyn = MEM_dupallocN(key); keyn->adt = NULL; @@ -205,19 +203,6 @@ Key *BKE_key_copy_nolib(Key *key) return keyn; } -void BKE_key_make_local(Key *key) -{ - - /* - only lib users: do nothing - * - only local users: set flag - * - mixed: make copy - */ - if (key == NULL) return; - - key->id.lib = NULL; - new_id(NULL, &key->id, NULL); -} - /* Sort shape keys and Ipo curves after a change. This assumes that at most * one key was moved, which is a valid assumption for the places it's * currently being called. diff --git a/source/blender/blenkernel/intern/lamp.c b/source/blender/blenkernel/intern/lamp.c index 49a573489ef..c224b5ca0a7 100644 --- a/source/blender/blenkernel/intern/lamp.c +++ b/source/blender/blenkernel/intern/lamp.c @@ -50,6 +50,8 @@ #include "BKE_global.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" @@ -114,12 +116,12 @@ Lamp *BKE_lamp_add(Main *bmain, const char *name) return la; } -Lamp *BKE_lamp_copy(Lamp *la) +Lamp *BKE_lamp_copy(Main *bmain, Lamp *la) { Lamp *lan; int a; - lan = BKE_libblock_copy(&la->id); + lan = BKE_libblock_copy(bmain, &la->id); for (a = 0; a < MAX_MTEX; a++) { if (lan->mtex[a]) { @@ -132,13 +134,13 @@ Lamp *BKE_lamp_copy(Lamp *la) lan->curfalloff = curvemapping_copy(la->curfalloff); if (la->nodetree) - lan->nodetree = ntreeCopyTree(la->nodetree); + lan->nodetree = ntreeCopyTree(bmain, la->nodetree); - if (la->preview) - lan->preview = BKE_previewimg_copy(la->preview); - - if (la->id.lib) { - BKE_id_lib_local_paths(G.main, la->id.lib, &lan->id); + lan->preview = BKE_previewimg_copy(la->preview); + + if (ID_IS_LINKED_DATABLOCK(la)) { + BKE_id_expand_local(&lan->id); + BKE_id_lib_local_paths(bmain, la->id.lib, &lan->id); } return lan; @@ -166,57 +168,36 @@ Lamp *localize_lamp(Lamp *la) lan->nodetree = ntreeLocalize(la->nodetree); lan->preview = NULL; - + return lan; } -void BKE_lamp_make_local(Lamp *la) +void BKE_lamp_make_local(Main *bmain, Lamp *la, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (la->id.lib == NULL) return; - if (la->id.us == 1) { - id_clear_lib_data(bmain, &la->id); + if (!ID_IS_LINKED_DATABLOCK(la)) { return; } - - ob = bmain->object.first; - while (ob) { - if (ob->data == la) { - if (ob->id.lib) is_lib = true; - else is_local = true; + + BKE_library_ID_test_usages(bmain, la, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &la->id); + BKE_id_expand_local(&la->id); } - ob = ob->id.next; - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &la->id); - } - else if (is_local && is_lib) { - Lamp *la_new = BKE_lamp_copy(la); - la_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, la->id.lib, &la_new->id); - - ob = bmain->object.first; - while (ob) { - if (ob->data == la) { - - if (ob->id.lib == NULL) { - ob->data = la_new; - id_us_plus(&la_new->id); - id_us_min(&la->id); - } - } - ob = ob->id.next; + else { + Lamp *la_new = BKE_lamp_copy(bmain, la); + + la_new->id.us = 0; + + BKE_libblock_remap(bmain, la, la_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -234,7 +215,7 @@ void BKE_lamp_free(Lamp *la) MEM_freeN(mtex); } - BKE_animdata_free((ID *)la); + BKE_animdata_free((ID *)la, false); curvemapping_free(la->curfalloff); diff --git a/source/blender/blenkernel/intern/lattice.c b/source/blender/blenkernel/intern/lattice.c index b350e932281..c2675fabe3b 100644 --- a/source/blender/blenkernel/intern/lattice.c +++ b/source/blender/blenkernel/intern/lattice.c @@ -59,6 +59,8 @@ #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_object.h" @@ -275,15 +277,17 @@ Lattice *BKE_lattice_add(Main *bmain, const char *name) return lt; } -Lattice *BKE_lattice_copy(Lattice *lt) +Lattice *BKE_lattice_copy(Main *bmain, Lattice *lt) { Lattice *ltn; - ltn = BKE_libblock_copy(<->id); + ltn = BKE_libblock_copy(bmain, <->id); ltn->def = MEM_dupallocN(lt->def); - ltn->key = BKE_key_copy(ltn->key); - if (ltn->key) ltn->key->from = (ID *)ltn; + if (lt->key) { + ltn->key = BKE_key_copy(bmain, ltn->key); + ltn->key->from = (ID *)ltn; + } if (lt->dvert) { int tot = lt->pntsu * lt->pntsv * lt->pntsw; @@ -293,77 +297,65 @@ Lattice *BKE_lattice_copy(Lattice *lt) ltn->editlatt = NULL; - if (lt->id.lib) { - BKE_id_lib_local_paths(G.main, lt->id.lib, <n->id); + if (ID_IS_LINKED_DATABLOCK(lt)) { + BKE_id_expand_local(<n->id); + BKE_id_lib_local_paths(bmain, lt->id.lib, <n->id); } return ltn; } +/** Free (or release) any data used by this lattice (does not free the lattice itself). */ void BKE_lattice_free(Lattice *lt) { - if (lt->def) MEM_freeN(lt->def); - if (lt->dvert) BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + BKE_animdata_free(<->id, false); + + MEM_SAFE_FREE(lt->def); + if (lt->dvert) { + BKE_defvert_array_free(lt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + lt->dvert = NULL; + } if (lt->editlatt) { Lattice *editlt = lt->editlatt->latt; - if (editlt->def) MEM_freeN(editlt->def); - if (editlt->dvert) BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); + if (editlt->def) + MEM_freeN(editlt->def); + if (editlt->dvert) + BKE_defvert_array_free(editlt->dvert, lt->pntsu * lt->pntsv * lt->pntsw); MEM_freeN(editlt); MEM_freeN(lt->editlatt); - } - - /* free animation data */ - if (lt->adt) { - BKE_animdata_free(<->id); - lt->adt = NULL; + lt->editlatt = NULL; } } -void BKE_lattice_make_local(Lattice *lt) +void BKE_lattice_make_local(Main *bmain, Lattice *lt, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (lt->id.lib == NULL) return; - if (lt->id.us == 1) { - id_clear_lib_data(bmain, <->id); + + if (!ID_IS_LINKED_DATABLOCK(lt)) { return; } - - for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) { - if (ob->data == lt) { - if (ob->id.lib) is_lib = true; - else is_local = true; + + BKE_library_ID_test_usages(bmain, lt, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, <->id); + BKE_id_expand_local(<->id); } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, <->id); - } - else if (is_local && is_lib) { - Lattice *lt_new = BKE_lattice_copy(lt); - lt_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, lt->id.lib, <_new->id); - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->data == lt) { - if (ob->id.lib == NULL) { - ob->data = lt_new; - id_us_plus(<_new->id); - id_us_min(<->id); - } - } + else { + Lattice *lt_new = BKE_lattice_copy(bmain, lt); + + lt_new->id.us = 0; + + BKE_libblock_remap(bmain, lt, lt_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c index 961b45df4e6..2e066528f56 100644 --- a/source/blender/blenkernel/intern/library.c +++ b/source/blender/blenkernel/intern/library.c @@ -84,7 +84,6 @@ #include "BKE_context.h" #include "BKE_curve.h" #include "BKE_depsgraph.h" -#include "BKE_fcurve.h" #include "BKE_font.h" #include "BKE_global.h" #include "BKE_group.h" @@ -92,7 +91,6 @@ #include "BKE_idcode.h" #include "BKE_idprop.h" #include "BKE_image.h" -#include "BKE_ipo.h" #include "BKE_key.h" #include "BKE_lamp.h" #include "BKE_lattice.h" @@ -103,16 +101,12 @@ #include "BKE_material.h" #include "BKE_main.h" #include "BKE_mball.h" -#include "BKE_movieclip.h" #include "BKE_mask.h" #include "BKE_node.h" #include "BKE_object.h" -#include "BKE_paint.h" #include "BKE_particle.h" #include "BKE_packedFile.h" #include "BKE_speaker.h" -#include "BKE_sound.h" -#include "BKE_screen.h" #include "BKE_scene.h" #include "BKE_text.h" #include "BKE_texture.h" @@ -125,10 +119,6 @@ #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" -#ifdef WITH_PYTHON -#include "BPY_extern.h" -#endif - /* GS reads the memory pointed at in a specific ordering. * only use this definition, makes little and big endian systems * work fine, in conjunction with MAKE_ID */ @@ -152,7 +142,7 @@ void BKE_id_lib_local_paths(Main *bmain, Library *lib, ID *id) void id_lib_extern(ID *id) { - if (id) { + if (id && ID_IS_LINKED_DATABLOCK(id)) { BLI_assert(BKE_idcode_is_linkable(GS(id->name))); if (id->tag & LIB_TAG_INDIRECT) { id->tag -= LIB_TAG_INDIRECT; @@ -182,7 +172,6 @@ void id_us_ensure_real(ID *id) } } -/* Unused currently... */ void id_us_clear_real(ID *id) { if (id && (id->tag & LIB_TAG_EXTRAUSER)) { @@ -232,9 +221,7 @@ void id_us_min(ID *id) if (id->us <= limit) { printf("ID user decrement error: %s (from '%s'): %d <= %d\n", id->name, id->lib ? id->lib->filepath : "[Main]", id->us, limit); - /* We cannot assert here, because of how we 'delete' datablocks currently (setting their usercount to zero), - * this is weak but it's how it works for now. */ - /* BLI_assert(0); */ + BLI_assert(0); id->us = limit; } else { @@ -264,9 +251,27 @@ void id_fake_user_clear(ID *id) } } +static int id_expand_local_callback( + void *UNUSED(user_data), struct ID *UNUSED(id_self), struct ID **id_pointer, int UNUSED(cd_flag)) +{ + if (*id_pointer) { + id_lib_extern(*id_pointer); + } + + return IDWALK_RET_NOP; +} + +/** + * Expand ID usages of given id as 'extern' (and no more indirect) linked data. Used by ID copy/make_local functions. + */ +void BKE_id_expand_local(ID *id) +{ + BKE_library_foreach_ID_link(id, id_expand_local_callback, NULL, 0); +} + /* calls the appropriate make_local method for the block, unless test. Returns true * if the block can be made local. */ -bool id_make_local(ID *id, bool test) +bool id_make_local(Main *bmain, ID *id, const bool test, const bool force_local) { if (id->tag & LIB_TAG_INDIRECT) return false; @@ -277,54 +282,44 @@ bool id_make_local(ID *id, bool test) case ID_LI: return false; /* can't be linked */ case ID_OB: - if (!test) BKE_object_make_local((Object *)id); + if (!test) BKE_object_make_local(bmain, (Object *)id, force_local); return true; case ID_ME: - if (!test) { - BKE_mesh_make_local((Mesh *)id); - BKE_key_make_local(((Mesh *)id)->key); - } + if (!test) BKE_mesh_make_local(bmain, (Mesh *)id, force_local); return true; case ID_CU: - if (!test) { - BKE_curve_make_local((Curve *)id); - BKE_key_make_local(((Curve *)id)->key); - } + if (!test) BKE_curve_make_local(bmain, (Curve *)id, force_local); return true; case ID_MB: - if (!test) BKE_mball_make_local((MetaBall *)id); + if (!test) BKE_mball_make_local(bmain, (MetaBall *)id, force_local); return true; case ID_MA: - if (!test) BKE_material_make_local((Material *)id); + if (!test) BKE_material_make_local(bmain, (Material *)id, force_local); return true; case ID_TE: - if (!test) BKE_texture_make_local((Tex *)id); + if (!test) BKE_texture_make_local(bmain, (Tex *)id, force_local); return true; case ID_IM: - if (!test) BKE_image_make_local((Image *)id); + if (!test) BKE_image_make_local(bmain, (Image *)id, force_local); return true; case ID_LT: - if (!test) { - BKE_lattice_make_local((Lattice *)id); - BKE_key_make_local(((Lattice *)id)->key); - } + if (!test) BKE_lattice_make_local(bmain, (Lattice *)id, force_local); return true; case ID_LA: - if (!test) BKE_lamp_make_local((Lamp *)id); + if (!test) BKE_lamp_make_local(bmain, (Lamp *)id, force_local); return true; case ID_CA: - if (!test) BKE_camera_make_local((Camera *)id); + if (!test) BKE_camera_make_local(bmain, (Camera *)id, force_local); return true; case ID_SPK: - if (!test) BKE_speaker_make_local((Speaker *)id); + if (!test) BKE_speaker_make_local(bmain, (Speaker *)id, force_local); return true; case ID_IP: return false; /* deprecated */ case ID_KE: - if (!test) BKE_key_make_local((Key *)id); - return true; + return false; /* can't be linked */ case ID_WO: - if (!test) BKE_world_make_local((World *)id); + if (!test) BKE_world_make_local(bmain, (World *)id, force_local); return true; case ID_SCR: return false; /* can't be linked */ @@ -337,19 +332,19 @@ bool id_make_local(ID *id, bool test) case ID_GR: return false; /* not implemented */ case ID_AR: - if (!test) BKE_armature_make_local((bArmature *)id); + if (!test) BKE_armature_make_local(bmain, (bArmature *)id, force_local); return true; case ID_AC: - if (!test) BKE_action_make_local((bAction *)id); + if (!test) BKE_action_make_local(bmain, (bAction *)id, force_local); return true; case ID_NT: - if (!test) ntreeMakeLocal((bNodeTree *)id, true); + if (!test) ntreeMakeLocal(bmain, (bNodeTree *)id, true, force_local); return true; case ID_BR: - if (!test) BKE_brush_make_local((Brush *)id); + if (!test) BKE_brush_make_local(bmain, (Brush *)id, force_local); return true; case ID_PA: - if (!test) BKE_particlesettings_make_local((ParticleSettings *)id); + if (!test) BKE_particlesettings_make_local(bmain, (ParticleSettings *)id, force_local); return true; case ID_WM: return false; /* can't be linked */ @@ -366,9 +361,11 @@ bool id_make_local(ID *id, bool test) * Invokes the appropriate copy method for the block and returns the result in * newid, unless test. Returns true if the block can be copied. */ -bool id_copy(ID *id, ID **newid, bool test) +bool id_copy(Main *bmain, ID *id, ID **newid, bool test) { - if (!test) *newid = NULL; + if (!test) { + *newid = NULL; + } /* conventions: * - make shallow copy, only this ID block @@ -379,120 +376,89 @@ bool id_copy(ID *id, ID **newid, bool test) case ID_LI: return false; /* can't be copied from here */ case ID_OB: - if (!test) *newid = (ID *)BKE_object_copy((Object *)id); + if (!test) *newid = (ID *)BKE_object_copy(bmain, (Object *)id); return true; case ID_ME: - if (!test) *newid = (ID *)BKE_mesh_copy((Mesh *)id); + if (!test) *newid = (ID *)BKE_mesh_copy(bmain, (Mesh *)id); return true; case ID_CU: - if (!test) *newid = (ID *)BKE_curve_copy((Curve *)id); + if (!test) *newid = (ID *)BKE_curve_copy(bmain, (Curve *)id); return true; case ID_MB: - if (!test) *newid = (ID *)BKE_mball_copy((MetaBall *)id); + if (!test) *newid = (ID *)BKE_mball_copy(bmain, (MetaBall *)id); return true; case ID_MA: - if (!test) *newid = (ID *)BKE_material_copy((Material *)id); + if (!test) *newid = (ID *)BKE_material_copy(bmain, (Material *)id); return true; case ID_TE: - if (!test) *newid = (ID *)BKE_texture_copy((Tex *)id); + if (!test) *newid = (ID *)BKE_texture_copy(bmain, (Tex *)id); return true; case ID_IM: - if (!test) *newid = (ID *)BKE_image_copy(G.main, (Image *)id); + if (!test) *newid = (ID *)BKE_image_copy(bmain, (Image *)id); return true; case ID_LT: - if (!test) *newid = (ID *)BKE_lattice_copy((Lattice *)id); + if (!test) *newid = (ID *)BKE_lattice_copy(bmain, (Lattice *)id); return true; case ID_LA: - if (!test) *newid = (ID *)BKE_lamp_copy((Lamp *)id); + if (!test) *newid = (ID *)BKE_lamp_copy(bmain, (Lamp *)id); return true; case ID_SPK: - if (!test) *newid = (ID *)BKE_speaker_copy((Speaker *)id); + if (!test) *newid = (ID *)BKE_speaker_copy(bmain, (Speaker *)id); return true; case ID_CA: - if (!test) *newid = (ID *)BKE_camera_copy((Camera *)id); + if (!test) *newid = (ID *)BKE_camera_copy(bmain, (Camera *)id); return true; case ID_IP: return false; /* deprecated */ case ID_KE: - if (!test) *newid = (ID *)BKE_key_copy((Key *)id); + if (!test) *newid = (ID *)BKE_key_copy(bmain, (Key *)id); return true; case ID_WO: - if (!test) *newid = (ID *)BKE_world_copy((World *)id); + if (!test) *newid = (ID *)BKE_world_copy(bmain, (World *)id); return true; case ID_SCR: return false; /* can't be copied from here */ case ID_VF: return false; /* not implemented */ case ID_TXT: - if (!test) *newid = (ID *)BKE_text_copy(G.main, (Text *)id); + if (!test) *newid = (ID *)BKE_text_copy(bmain, (Text *)id); return true; case ID_SO: return false; /* not implemented */ case ID_GR: - if (!test) *newid = (ID *)BKE_group_copy((Group *)id); + if (!test) *newid = (ID *)BKE_group_copy(bmain, (Group *)id); return true; case ID_AR: - if (!test) *newid = (ID *)BKE_armature_copy((bArmature *)id); + if (!test) *newid = (ID *)BKE_armature_copy(bmain, (bArmature *)id); return true; case ID_AC: - if (!test) *newid = (ID *)BKE_action_copy((bAction *)id); + if (!test) *newid = (ID *)BKE_action_copy(bmain, (bAction *)id); return true; case ID_NT: - if (!test) *newid = (ID *)ntreeCopyTree((bNodeTree *)id); + if (!test) *newid = (ID *)ntreeCopyTree(bmain, (bNodeTree *)id); return true; case ID_BR: - if (!test) *newid = (ID *)BKE_brush_copy((Brush *)id); + if (!test) *newid = (ID *)BKE_brush_copy(bmain, (Brush *)id); return true; case ID_PA: - if (!test) *newid = (ID *)BKE_particlesettings_copy((ParticleSettings *)id); + if (!test) *newid = (ID *)BKE_particlesettings_copy(bmain, (ParticleSettings *)id); return true; case ID_WM: return false; /* can't be copied from here */ case ID_GD: - if (!test) *newid = (ID *)gpencil_data_duplicate((bGPdata *)id, false); + if (!test) *newid = (ID *)gpencil_data_duplicate(bmain, (bGPdata *)id, false); return true; case ID_MSK: - if (!test) *newid = (ID *)BKE_mask_copy((Mask *)id); + if (!test) *newid = (ID *)BKE_mask_copy(bmain, (Mask *)id); return true; case ID_LS: - if (!test) *newid = (ID *)BKE_linestyle_copy(G.main, (FreestyleLineStyle *)id); + if (!test) *newid = (ID *)BKE_linestyle_copy(bmain, (FreestyleLineStyle *)id); return true; } return false; } -bool id_unlink(ID *id, int test) -{ - Main *mainlib = G.main; - short type = GS(id->name); - - switch (type) { - case ID_TXT: - if (test) return true; - BKE_text_unlink(mainlib, (Text *)id); - break; - case ID_GR: - if (test) return true; - BKE_group_unlink(mainlib, (Group *)id); - break; - case ID_OB: - if (test) return true; - BKE_object_unlink(mainlib, (Object *)id); - break; - } - - if (id->us == 0) { - if (test) return true; - - BKE_libblock_free(mainlib, id); - - return true; - } - - return false; -} - bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) { ID *newid = NULL; @@ -501,7 +467,7 @@ bool id_single_user(bContext *C, ID *id, PointerRNA *ptr, PropertyRNA *prop) if (id) { /* if property isn't editable, we're going to have an extra block hanging around until we save */ if (RNA_property_editable(ptr, prop)) { - if (id_copy(id, &newid, false) && newid) { + if (id_copy(CTX_data_main(C), id, &newid, false) && newid) { /* copy animation actions too */ BKE_animdata_copy_id_action(id); /* us is 1 by convention, but RNA_property_pointer_set @@ -674,7 +640,7 @@ void BKE_main_lib_objects_recalc_all(Main *bmain) /* flag for full recalc */ for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); } } @@ -1029,7 +995,7 @@ void BKE_libblock_copy_data(ID *id, const ID *id_from, const bool do_action) } /* used everywhere in blenkernel */ -void *BKE_libblock_copy_ex(Main *bmain, ID *id) +void *BKE_libblock_copy(Main *bmain, ID *id) { ID *idn; size_t idn_len; @@ -1081,11 +1047,6 @@ void *BKE_libblock_copy_nolib(ID *id, const bool do_action) return idn; } -void *BKE_libblock_copy(ID *id) -{ - return BKE_libblock_copy_ex(G.main, id); -} - static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **id_pointer, const int cd_flag) { ID *id = *id_pointer; @@ -1105,240 +1066,18 @@ static int id_relink_looper(void *UNUSED(user_data), ID *UNUSED(self_id), ID **i void BKE_libblock_relink(ID *id) { - if (id->lib) + if (ID_IS_LINKED_DATABLOCK(id)) return; BKE_library_foreach_ID_link(id, id_relink_looper, NULL, 0); } -static void BKE_library_free(Library *lib) +void BKE_library_free(Library *lib) { if (lib->packedfile) freePackedFile(lib->packedfile); } -static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; - -void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) -{ - free_windowmanager_cb = func; -} - -static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; - -void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) -{ - free_notifier_reference_cb = func; -} - -static BKE_library_free_editor_id_reference_cb free_editor_id_reference_cb = NULL; - -void BKE_library_callback_free_editor_id_reference_set(BKE_library_free_editor_id_reference_cb func) -{ - free_editor_id_reference_cb = func; -} - -static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) -{ - ChannelDriver *driver; - FCurve *fcu; - - /* find the driver this belongs to and update it */ - for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { - driver = fcu->driver; - - if (driver) { - DriverVar *dvar; - for (dvar = driver->variables.first; dvar; dvar = dvar->next) { - DRIVER_TARGETS_USED_LOOPER(dvar) - { - if (dtar->id == userdata) - dtar->id = NULL; - } - DRIVER_TARGETS_LOOPER_END - } - } - } -} - -void BKE_libblock_free_data(Main *bmain, ID *id) -{ - if (id->properties) { - IDP_FreeProperty(id->properties); - MEM_freeN(id->properties); - } - - /* this ID may be a driver target! */ - BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); -} - -/* used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c */ -void BKE_libblock_free_ex(Main *bmain, void *idv, bool do_id_user) -{ - ID *id = idv; - short type = GS(id->name); - ListBase *lb = which_libbase(bmain, type); - - DAG_id_type_tag(bmain, type); - -#ifdef WITH_PYTHON - BPY_id_release(id); -#endif - - switch (type) { /* GetShort from util.h */ - case ID_SCE: - BKE_scene_free((Scene *)id); - break; - case ID_LI: - BKE_library_free((Library *)id); - break; - case ID_OB: - BKE_object_free_ex((Object *)id, do_id_user); - break; - case ID_ME: - BKE_mesh_free((Mesh *)id, 1); - break; - case ID_CU: - BKE_curve_free((Curve *)id); - break; - case ID_MB: - BKE_mball_free((MetaBall *)id); - break; - case ID_MA: - BKE_material_free((Material *)id); - break; - case ID_TE: - BKE_texture_free((Tex *)id); - break; - case ID_IM: - BKE_image_free((Image *)id); - break; - case ID_LT: - BKE_lattice_free((Lattice *)id); - break; - case ID_LA: - BKE_lamp_free((Lamp *)id); - break; - case ID_CA: - BKE_camera_free((Camera *) id); - break; - case ID_IP: - BKE_ipo_free((Ipo *)id); - break; - case ID_KE: - BKE_key_free((Key *)id); - break; - case ID_WO: - BKE_world_free((World *)id); - break; - case ID_SCR: - BKE_screen_free((bScreen *)id); - break; - case ID_VF: - BKE_vfont_free((VFont *)id); - break; - case ID_TXT: - BKE_text_free((Text *)id); - break; - case ID_SPK: - BKE_speaker_free((Speaker *)id); - break; - case ID_SO: - BKE_sound_free((bSound *)id); - break; - case ID_GR: - BKE_group_free((Group *)id); - break; - case ID_AR: - BKE_armature_free((bArmature *)id); - break; - case ID_AC: - BKE_action_free((bAction *)id); - break; - case ID_NT: - ntreeFreeTree_ex((bNodeTree *)id, do_id_user); - break; - case ID_BR: - BKE_brush_free((Brush *)id); - break; - case ID_PA: - BKE_particlesettings_free((ParticleSettings *)id); - break; - case ID_WM: - if (free_windowmanager_cb) - free_windowmanager_cb(NULL, (wmWindowManager *)id); - break; - case ID_GD: - BKE_gpencil_free((bGPdata *)id); - break; - case ID_MC: - BKE_movieclip_free((MovieClip *)id); - break; - case ID_MSK: - BKE_mask_free(bmain, (Mask *)id); - break; - case ID_LS: - BKE_linestyle_free((FreestyleLineStyle *)id); - break; - case ID_PAL: - BKE_palette_free((Palette *)id); - break; - case ID_PC: - BKE_paint_curve_free((PaintCurve *)id); - break; - } - - /* avoid notifying on removed data */ - BKE_main_lock(bmain); - - if (free_notifier_reference_cb) { - free_notifier_reference_cb(id); - } - - if (free_editor_id_reference_cb) { - free_editor_id_reference_cb(id); - } - - BLI_remlink(lb, id); - - BKE_libblock_free_data(bmain, id); - BKE_main_unlock(bmain); - - MEM_freeN(id); -} - -void BKE_libblock_free(Main *bmain, void *idv) -{ - BKE_libblock_free_ex(bmain, idv, true); -} - -void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ -{ - ID *id = idv; - - id_us_min(id); - - /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. - * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, - * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets - * fully unlinked. - * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. - */ - if ((GS(id->name) == ID_OB) && (id->us == 1)) { - id_us_clear_real(id); - } - - if (id->us == 0) { - switch (GS(id->name)) { - case ID_OB: - BKE_object_unlink(bmain, (Object *)id); - break; - } - - BKE_libblock_free(bmain, id); - } -} - Main *BKE_main_new(void) { Main *bmain = MEM_callocN(sizeof(Main), "new main"); @@ -1541,7 +1280,7 @@ static ID *is_dupid(ListBase *lb, ID *id, const char *name) for (idtest = lb->first; idtest; idtest = idtest->next) { /* if idtest is not a lib */ - if (id != idtest && idtest->lib == NULL) { + if (id != idtest && !ID_IS_LINKED_DATABLOCK(idtest)) { /* do not test alphabetic! */ /* optimized */ if (idtest->name[2] == name[0]) { @@ -1601,7 +1340,7 @@ static bool check_for_dupid(ListBase *lb, ID *id, char *name) for (idtest = lb->first; idtest; idtest = idtest->next) { int nrtest; if ( (id != idtest) && - (idtest->lib == NULL) && + !ID_IS_LINKED_DATABLOCK(idtest) && (*name == *(idtest->name + 2)) && STREQLEN(name, idtest->name + 2, left_len) && (BLI_split_name_num(leftest, &nrtest, idtest->name + 2, '.') == left_len) @@ -1683,7 +1422,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname) char name[MAX_ID_NAME - 2]; /* if library, don't rename */ - if (id->lib) + if (ID_IS_LINKED_DATABLOCK(id)) return false; /* if no libdata given, look up based on ID */ @@ -1731,6 +1470,7 @@ bool new_id(ListBase *lb, ID *id, const char *tname) void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist) { bNodeTree *ntree = NULL; + Key *key = NULL; BKE_id_lib_local_paths(bmain, id->lib, id); @@ -1741,13 +1481,14 @@ void id_clear_lib_data_ex(Main *bmain, ID *id, bool id_in_mainlist) if (id_in_mainlist) new_id(which_libbase(bmain, GS(id->name)), id, NULL); - /* internal bNodeTree blocks inside ID types below - * also stores id->lib, make sure this stays in sync. - */ - ntree = ntreeFromID(id); + /* Internal bNodeTree blocks inside datablocks also stores id->lib, make sure this stays in sync. */ + if ((ntree = ntreeFromID(id))) { + id_clear_lib_data_ex(bmain, &ntree->id, false); /* Datablocks' nodetree is never in Main. */ + } - if (ntree) { - ntreeMakeLocal(ntree, false); + /* Same goes for shapekeys. */ + if ((key = BKE_key_from_id(id))) { + id_clear_lib_data_ex(bmain, &key->id, id_in_mainlist); /* sigh, why are keys in Main? */ } if (GS(id->name) == ID_OB) { @@ -1788,7 +1529,7 @@ static void lib_indirect_test_id(ID *id, const Library *lib) #define LIBTAG(a) \ if (a && a->id.lib) { a->id.tag &= ~LIB_TAG_INDIRECT; a->id.tag |= LIB_TAG_EXTERN; } (void)0 - if (id->lib) { + if (ID_IS_LINKED_DATABLOCK(id)) { /* datablocks that were indirectly related are now direct links * without this, appending data that has a link to other data will fail to write */ if (lib && id->lib->parent == lib) { @@ -1861,14 +1602,8 @@ void BKE_library_make_local(Main *bmain, const Library *lib, const bool untagged { if (lib == NULL || id->lib == lib) { if (id->lib) { - /* for Make Local > All we should be calling id_make_local, - * but doing that breaks append (see #36003 and #36006), we - * we should make it work with all datablocks and id.us==0 */ - id_clear_lib_data(bmain, id); /* sets 'id->tag' */ - - /* why sort alphabetically here but not in - * id_clear_lib_data() ? - campbell */ - id_sort_by_name(lbarray[a], id); + /* In this specific case, we do want to make ID local even if it has no local usage yet... */ + id_make_local(bmain, id, false, true); } else { id->tag &= ~(LIB_TAG_EXTERN | LIB_TAG_INDIRECT | LIB_TAG_NEW); diff --git a/source/blender/blenkernel/intern/library_idmap.c b/source/blender/blenkernel/intern/library_idmap.c index 66025c04332..daf097b9f0b 100644 --- a/source/blender/blenkernel/intern/library_idmap.c +++ b/source/blender/blenkernel/intern/library_idmap.c @@ -33,7 +33,7 @@ #include "BKE_library.h" #include "BKE_library_idmap.h" /* own include */ -/** \file blender/blenkernel/intern/library_map.c +/** \file blender/blenkernel/intern/library_idmap.c * \ingroup bke * * Utility functions for faster ID lookups. diff --git a/source/blender/blenkernel/intern/library_query.c b/source/blender/blenkernel/intern/library_query.c index d29d2191602..04132114d2e 100644 --- a/source/blender/blenkernel/intern/library_query.c +++ b/source/blender/blenkernel/intern/library_query.c @@ -29,6 +29,7 @@ #include <stdlib.h> +#include "MEM_guardedalloc.h" #include "DNA_actuator_types.h" #include "DNA_anim_types.h" @@ -44,6 +45,7 @@ #include "DNA_linestyle_types.h" #include "DNA_material_types.h" #include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" #include "DNA_meta_types.h" #include "DNA_movieclip_types.h" #include "DNA_mask_types.h" @@ -61,6 +63,7 @@ #include "DNA_world_types.h" #include "BLI_utildefines.h" +#include "BLI_listbase.h" #include "BLI_ghash.h" #include "BLI_linklist_stack.h" @@ -69,6 +72,7 @@ #include "BKE_fcurve.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_particle.h" #include "BKE_rigidbody.h" @@ -84,7 +88,7 @@ if (!((_data)->status & IDWALK_STOP)) { \ const int _flag = (_data)->flag; \ ID *old_id = *(id_pp); \ - const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag); \ + const int callback_return = (_data)->callback((_data)->user_data, (_data)->self_id, id_pp, cb_flag | (_data)->cd_flag); \ if (_flag & IDWALK_READONLY) { \ BLI_assert(*(id_pp) == old_id); \ } \ @@ -125,6 +129,7 @@ enum { typedef struct LibraryForeachIDData { ID *self_id; int flag; + int cd_flag; LibraryIDLinkCallback callback; void *user_data; int status; @@ -198,9 +203,24 @@ static void library_foreach_actuatorsObjectLooper( FOREACH_FINALIZE_VOID; } +static void library_foreach_nla_strip(LibraryForeachIDData *data, NlaStrip *strip) +{ + NlaStrip *substrip; + + FOREACH_CALLBACK_INVOKE(data, strip->act, IDWALK_USER); + + for (substrip = strip->strips.first; substrip; substrip = substrip->next) { + library_foreach_nla_strip(data, substrip); + } + + FOREACH_FINALIZE_VOID; +} + static void library_foreach_animationData(LibraryForeachIDData *data, AnimData *adt) { FCurve *fcu; + NlaTrack *nla_track; + NlaStrip *nla_strip; for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { ChannelDriver *driver = fcu->driver; @@ -216,6 +236,15 @@ static void library_foreach_animationData(LibraryForeachIDData *data, AnimData * } } + FOREACH_CALLBACK_INVOKE(data, adt->action, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, adt->tmpact, IDWALK_USER); + + for (nla_track = adt->nla_tracks.first; nla_track; nla_track = nla_track->next) { + for (nla_strip = nla_track->strips.first; nla_strip; nla_strip = nla_strip->next) { + library_foreach_nla_strip(data, nla_strip); + } + } + FOREACH_FINALIZE_VOID; } @@ -227,6 +256,14 @@ static void library_foreach_mtex(LibraryForeachIDData *data, MTex *mtex) FOREACH_FINALIZE_VOID; } +static void library_foreach_paint(LibraryForeachIDData *data, Paint *paint) +{ + FOREACH_CALLBACK_INVOKE(data, paint->brush, IDWALK_USER); + FOREACH_CALLBACK_INVOKE(data, paint->palette, IDWALK_USER); + + FOREACH_FINALIZE_VOID; +} + /** * Loop over all of the ID's this datablock links to. @@ -261,6 +298,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u do { data.self_id = id; + data.cd_flag = ID_IS_LINKED_DATABLOCK(id) ? IDWALK_INDIRECT_USAGE : 0; AnimData *adt = BKE_animdata_from_id(id); if (adt) { @@ -268,6 +306,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } switch (GS(id->name)) { + case ID_LI: + { + Library *lib = (Library *) id; + CALLBACK_INVOKE(lib->parent, IDWALK_NOP); + break; + } case ID_SCE: { Scene *scene = (Scene *) id; @@ -278,8 +322,11 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(scene->camera, IDWALK_NOP); CALLBACK_INVOKE(scene->world, IDWALK_USER); CALLBACK_INVOKE(scene->set, IDWALK_NOP); - CALLBACK_INVOKE(scene->clip, IDWALK_NOP); - CALLBACK_INVOKE(scene->nodetree, IDWALK_NOP); + CALLBACK_INVOKE(scene->clip, IDWALK_USER); + if (scene->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)scene->nodetree, callback, user_data, flag); + } /* DO NOT handle scene->basact here, it's doubling with the loop over whole scene->base later, * since basact is just a pointer to one of those items. */ CALLBACK_INVOKE(scene->obedit, IDWALK_NOP); @@ -318,6 +365,9 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(seq->clip, IDWALK_USER); CALLBACK_INVOKE(seq->mask, IDWALK_USER); CALLBACK_INVOKE(seq->sound, IDWALK_USER); + for (SequenceModifierData *smd = seq->modifiers.first; smd; smd = smd->next) { + CALLBACK_INVOKE(smd->mask_id, IDWALK_USER); + } } SEQ_END } @@ -330,28 +380,28 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u if (toolsett) { CALLBACK_INVOKE(toolsett->skgen_template, IDWALK_NOP); + CALLBACK_INVOKE(toolsett->particle.scene, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.object, IDWALK_NOP); CALLBACK_INVOKE(toolsett->particle.shape_object, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_NOP); + + library_foreach_paint(&data, &toolsett->imapaint.paint); + CALLBACK_INVOKE(toolsett->imapaint.stencil, IDWALK_USER); + CALLBACK_INVOKE(toolsett->imapaint.clone, IDWALK_USER); + CALLBACK_INVOKE(toolsett->imapaint.canvas, IDWALK_USER); + if (toolsett->vpaint) { - CALLBACK_INVOKE(toolsett->vpaint->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->vpaint->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->vpaint->paint); } if (toolsett->wpaint) { - CALLBACK_INVOKE(toolsett->wpaint->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->wpaint->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->wpaint->paint); } if (toolsett->sculpt) { - CALLBACK_INVOKE(toolsett->sculpt->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->sculpt->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->sculpt->paint); CALLBACK_INVOKE(toolsett->sculpt->gravity_object, IDWALK_NOP); } if (toolsett->uvsculpt) { - CALLBACK_INVOKE(toolsett->uvsculpt->paint.brush, IDWALK_NOP); - CALLBACK_INVOKE(toolsett->uvsculpt->paint.palette, IDWALK_NOP); + library_foreach_paint(&data, &toolsett->uvsculpt->paint); } } @@ -369,7 +419,12 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u Object *object = (Object *) id; ParticleSystem *psys; + /* Object is special, proxies make things hard... */ + const int data_cd_flag = data.cd_flag; + const int proxy_cd_flag = (object->proxy || object->proxy_group) ? IDWALK_INDIRECT_USAGE : 0; + /* object data special case */ + data.cd_flag |= proxy_cd_flag; if (object->type == OB_EMPTY) { /* empty can have NULL or Image */ CALLBACK_INVOKE_ID(object->data, IDWALK_USER); @@ -380,6 +435,7 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE_ID(object->data, IDWALK_USER | IDWALK_NEVER_NULL); } } + data.cd_flag = data_cd_flag; CALLBACK_INVOKE(object->parent, IDWALK_NOP); CALLBACK_INVOKE(object->track, IDWALK_NOP); @@ -388,9 +444,13 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(object->proxy_group, IDWALK_NOP); CALLBACK_INVOKE(object->proxy_from, IDWALK_NOP); CALLBACK_INVOKE(object->poselib, IDWALK_USER); + + data.cd_flag |= proxy_cd_flag; for (i = 0; i < object->totcol; i++) { CALLBACK_INVOKE(object->mat[i], IDWALK_USER); } + data.cd_flag = data_cd_flag; + CALLBACK_INVOKE(object->gpd, IDWALK_USER); CALLBACK_INVOKE(object->dup_group, IDWALK_USER); @@ -398,13 +458,17 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(object->pd->tex, IDWALK_USER); CALLBACK_INVOKE(object->pd->f_source, IDWALK_NOP); } + /* Note that ob->effect is deprecated, so no need to handle it here. */ if (object->pose) { bPoseChannel *pchan; + + data.cd_flag |= proxy_cd_flag; for (pchan = object->pose->chanbase.first; pchan; pchan = pchan->next) { CALLBACK_INVOKE(pchan->custom, IDWALK_USER); BKE_constraints_id_loop(&pchan->constraints, library_foreach_constraintObjectLooper, &data); } + data.cd_flag = data_cd_flag; } if (object->rigidbody_constraint) { @@ -426,6 +490,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u BKE_particlesystem_id_loop(psys, library_foreach_particlesystemsObjectLooper, &data); } + if (object->soft && object->soft->effector_weights) { + CALLBACK_INVOKE(object->soft->effector_weights->group, IDWALK_NOP); + } + BKE_sca_sensors_id_loop(&object->sensors, library_foreach_sensorsObjectLooper, &data); BKE_sca_controllers_id_loop(&object->controllers, library_foreach_controllersObjectLooper, &data); BKE_sca_actuators_id_loop(&object->actuators, library_foreach_actuatorsObjectLooper, &data); @@ -440,6 +508,31 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u for (i = 0; i < mesh->totcol; i++) { CALLBACK_INVOKE(mesh->mat[i], IDWALK_USER); } + + /* XXX Really not happy with this - probably texface should rather use some kind of + * 'texture slots' and just set indices in each poly/face item - would also save some memory. + * Maybe a nice TODO for blender2.8? */ + if (mesh->mtface || mesh->mtpoly) { + for (i = 0; i < mesh->pdata.totlayer; i++) { + if (mesh->pdata.layers[i].type == CD_MTEXPOLY) { + MTexPoly *txface = (MTexPoly *)mesh->pdata.layers[i].data; + + for (int j = 0; j < mesh->totpoly; j++, txface++) { + CALLBACK_INVOKE(txface->tpage, IDWALK_USER_ONE); + } + } + } + + for (i = 0; i < mesh->fdata.totlayer; i++) { + if (mesh->fdata.layers[i].type == CD_MTFACE) { + MTFace *tface = (MTFace *)mesh->fdata.layers[i].data; + + for (int j = 0; j < mesh->totface; j++, tface++) { + CALLBACK_INVOKE(tface->tpage, IDWALK_USER_ONE); + } + } + } + } break; } @@ -477,7 +570,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, material->mtex[i]); } } - CALLBACK_INVOKE(material->nodetree, IDWALK_NOP); + if (material->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)material->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(material->group, IDWALK_USER); break; } @@ -485,7 +581,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u case ID_TE: { Tex *texture = (Tex *) id; - CALLBACK_INVOKE(texture->nodetree, IDWALK_NOP); + if (texture->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)texture->nodetree, callback, user_data, flag); + } CALLBACK_INVOKE(texture->ima, IDWALK_USER); if (texture->env) { CALLBACK_INVOKE(texture->env->object, IDWALK_NOP); @@ -515,7 +614,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, lamp->mtex[i]); } } - CALLBACK_INVOKE(lamp->nodetree, IDWALK_NOP); + if (lamp->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)lamp->nodetree, callback, user_data, flag); + } break; } @@ -548,7 +650,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, world->mtex[i]); } } - CALLBACK_INVOKE(world->nodetree, IDWALK_NOP); + if (world->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)world->nodetree, callback, user_data, flag); + } break; } @@ -608,6 +713,15 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u CALLBACK_INVOKE(psett->effector_weights->group, IDWALK_NOP); } + if (psett->pd) { + CALLBACK_INVOKE(psett->pd->tex, IDWALK_USER); + CALLBACK_INVOKE(psett->pd->f_source, IDWALK_NOP); + } + if (psett->pd2) { + CALLBACK_INVOKE(psett->pd2->tex, IDWALK_USER); + CALLBACK_INVOKE(psett->pd2->f_source, IDWALK_NOP); + } + if (psett->boids) { BoidState *state; BoidRule *rule; @@ -625,7 +739,6 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u } } } - break; } @@ -634,16 +747,23 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u MovieClip *clip = (MovieClip *) id; MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; + MovieTrackingTrack *track; + MovieTrackingPlaneTrack *plane_track; CALLBACK_INVOKE(clip->gpd, IDWALK_USER); - for (object = tracking->objects.first; object; object = object->next) { - ListBase *tracksbase = BKE_tracking_object_get_tracks(tracking, object); - MovieTrackingTrack *track; - for (track = tracksbase->first; track; track = track->next) { + for (track = tracking->tracks.first; track; track = track->next) { + CALLBACK_INVOKE(track->gpd, IDWALK_USER); + } + for (object = tracking->objects.first; object; object = object->next) { + for (track = object->tracks.first; track; track = track->next) { CALLBACK_INVOKE(track->gpd, IDWALK_USER); } } + + for (plane_track = tracking->plane_tracks.first; plane_track; plane_track = plane_track->next) { + CALLBACK_INVOKE(plane_track->image, IDWALK_USER); + } break; } @@ -673,7 +793,10 @@ void BKE_library_foreach_ID_link(ID *id, LibraryIDLinkCallback callback, void *u library_foreach_mtex(&data, linestyle->mtex[i]); } } - CALLBACK_INVOKE(linestyle->nodetree, IDWALK_NOP); + if (linestyle->nodetree) { + /* nodetree **are owned by IDs**, treat them as mere sub-data and not real ID! */ + BKE_library_foreach_ID_link((ID *)linestyle->nodetree, callback, user_data, flag); + } for (lsm = linestyle->color_modifiers.first; lsm; lsm = lsm->next) { if (lsm->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { @@ -731,6 +854,83 @@ void BKE_library_update_ID_link_user(ID *id_dst, ID *id_src, const int cd_flag) } } +/** + * Say whether given \a id_type_owner can use (in any way) a datablock of \a id_type_used. + * + * This is a 'simplified' abstract version of #BKE_library_foreach_ID_link() above, quite useful to reduce + * useless iterations in some cases. + */ +bool BKE_library_idtype_can_use_idtype(const short id_type_owner, const short id_type_used) +{ + if (id_type_used == ID_AC) { + return id_type_can_have_animdata(id_type_owner); + } + + switch (id_type_owner) { + case ID_LI: + return ELEM(id_type_used, ID_LI); + case ID_SCE: + return (ELEM(id_type_used, ID_OB, ID_WO, ID_SCE, ID_MC, ID_MA, ID_GR, ID_TXT, + ID_LS, ID_MSK, ID_SO, ID_GD, ID_BR, ID_PAL, ID_IM, ID_NT) || + BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_OB: + /* Could be the following, but simpler to just always say 'yes' here. */ +#if 0 + return ELEM(id_type_used, ID_ME, ID_CU, ID_MB, ID_LT, ID_SPK, ID_AR, ID_LA, ID_CA, /* obdata */ + ID_OB, ID_MA, ID_GD, ID_GR, ID_TE, ID_PA, ID_TXT, ID_SO, ID_MC, ID_IM, ID_AC + /* + constraints, modifiers and game logic ID types... */); +#else + return true; +#endif + case ID_ME: + return ELEM(id_type_used, ID_ME, ID_KE, ID_MA); + case ID_CU: + return ELEM(id_type_used, ID_OB, ID_KE, ID_MA, ID_VF); + case ID_MB: + return ELEM(id_type_used, ID_MA); + case ID_MA: + return (ELEM(id_type_used, ID_TE, ID_GR) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_TE: + return (ELEM(id_type_used, ID_IM, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_LT: + return ELEM(id_type_used, ID_KE); + case ID_LA: + return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_CA: + return ELEM(id_type_used, ID_OB); + case ID_KE: + return ELEM(id_type_used, ID_ME, ID_CU, ID_LT); /* Warning! key->from, could be more types in future? */ + case ID_SCR: + return ELEM(id_type_used, ID_SCE); + case ID_WO: + return (ELEM(id_type_used, ID_TE) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + case ID_SPK: + return ELEM(id_type_used, ID_SO); + case ID_GR: + return ELEM(id_type_used, ID_OB); + case ID_NT: + /* Could be the following, but node.id has no type restriction... */ +#if 0 + return ELEM(id_type_used, ID_GD /* + node.id types... */); +#else + return true; +#endif + case ID_BR: + return ELEM(id_type_used, ID_BR, ID_IM, ID_PC, ID_TE); + case ID_PA: + return ELEM(id_type_used, ID_OB, ID_GR, ID_TE); + case ID_MC: + return ELEM(id_type_used, ID_GD, ID_IM); + case ID_MSK: + return ELEM(id_type_used, ID_MC); /* WARNING! mask->parent.id, not typed. */ + case ID_LS: + return (ELEM(id_type_used, ID_TE, ID_OB) || BKE_library_idtype_can_use_idtype(ID_NT, id_type_used)); + default: + return false; + } +} + + /* ***** ID users iterator. ***** */ typedef struct IDUsersIter { ID *id; @@ -739,15 +939,26 @@ typedef struct IDUsersIter { int lb_idx; ID *curr_id; - int count; /* Set by callback. */ + int count_direct, count_indirect; /* Set by callback. */ } IDUsersIter; -static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int UNUSED(cb_flag)) +static int foreach_libblock_id_users_callback(void *user_data, ID *UNUSED(self_id), ID **id_p, int cb_flag) { IDUsersIter *iter = user_data; if (*id_p && (*id_p == iter->id)) { - iter->count++; +#if 0 + printf("%s uses %s (refcounted: %d, userone: %d, used_one: %d, used_one_active: %d, indirect_usage: %d)\n", + iter->curr_id->name, iter->id->name, (cb_flag & IDWALK_USER) ? 1 : 0, (cb_flag & IDWALK_USER_ONE) ? 1 : 0, + (iter->id->tag & LIB_TAG_EXTRAUSER) ? 1 : 0, (iter->id->tag & LIB_TAG_EXTRAUSER_SET) ? 1 : 0, + (cb_flag & IDWALK_INDIRECT_USAGE) ? 1 : 0); +#endif + if (cb_flag & IDWALK_INDIRECT_USAGE) { + iter->count_indirect++; + } + else { + iter->count_direct++; + } } return IDWALK_RET_NOP; @@ -770,9 +981,86 @@ int BKE_library_ID_use_ID(ID *id_user, ID *id_used) /* We do not care about iter.lb_array/lb_idx here... */ iter.id = id_used; iter.curr_id = id_user; - iter.count = 0; + iter.count_direct = iter.count_indirect = 0; BKE_library_foreach_ID_link(iter.curr_id, foreach_libblock_id_users_callback, (void *)&iter, IDWALK_NOP); - return iter.count; + return iter.count_direct + iter.count_indirect; +} + +static bool library_ID_is_used(Main *bmain, void *idv, const bool check_linked) +{ + IDUsersIter iter; + ListBase *lb_array[MAX_LIBARRAY]; + ID *id = idv; + int i = set_listbasepointers(bmain, lb_array); + bool is_defined = false; + + iter.id = id; + iter.count_direct = iter.count_indirect = 0; + while (i-- && !is_defined) { + ID *id_curr = lb_array[i]->first; + + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + continue; + } + + for (; id_curr && !is_defined; id_curr = id_curr->next) { + iter.curr_id = id_curr; + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + + is_defined = ((check_linked ? iter.count_indirect : iter.count_direct) != 0); + } + } + + return is_defined; +} + +/** + * Check whether given ID is used locally (i.e. by another non-linked ID). + */ +bool BKE_library_ID_is_locally_used(Main *bmain, void *idv) +{ + return library_ID_is_used(bmain, idv, false); +} + +/** + * Check whether given ID is used indirectly (i.e. by another linked ID). + */ +bool BKE_library_ID_is_indirectly_used(Main *bmain, void *idv) +{ + return library_ID_is_used(bmain, idv, true); +} + +/** + * Combine \a BKE_library_ID_is_locally_used() and \a BKE_library_ID_is_indirectly_used() in a single call. + */ +void BKE_library_ID_test_usages(Main *bmain, void *idv, bool *is_used_local, bool *is_used_linked) +{ + IDUsersIter iter; + ListBase *lb_array[MAX_LIBARRAY]; + ID *id = idv; + int i = set_listbasepointers(bmain, lb_array); + bool is_defined = false; + + iter.id = id; + iter.count_direct = iter.count_indirect = 0; + while (i-- && !is_defined) { + ID *id_curr = lb_array[i]->first; + + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(id->name))) { + continue; + } + + for (; id_curr && !is_defined; id_curr = id_curr->next) { + iter.curr_id = id_curr; + BKE_library_foreach_ID_link(id_curr, foreach_libblock_id_users_callback, &iter, IDWALK_NOP); + + is_defined = (iter.count_direct != 0 && iter.count_indirect != 0); + } + } + + *is_used_local = (iter.count_direct != 0); + *is_used_linked = (iter.count_indirect != 0); } diff --git a/source/blender/blenkernel/intern/library_remap.c b/source/blender/blenkernel/intern/library_remap.c new file mode 100644 index 00000000000..f3e6ec1ec51 --- /dev/null +++ b/source/blender/blenkernel/intern/library_remap.c @@ -0,0 +1,910 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/blenkernel/intern/library_remap.c + * \ingroup bke + * + * Contains management of ID's and libraries remap, unlink and free logic. + */ + +#include <stdio.h> +#include <ctype.h> +#include <string.h> +#include <stdlib.h> +#include <stddef.h> +#include <assert.h> + +#include "MEM_guardedalloc.h" + +/* all types are needed here, in order to do memory operations */ +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_brush_types.h" +#include "DNA_camera_types.h" +#include "DNA_group_types.h" +#include "DNA_gpencil_types.h" +#include "DNA_ipo_types.h" +#include "DNA_key_types.h" +#include "DNA_lamp_types.h" +#include "DNA_lattice_types.h" +#include "DNA_linestyle_types.h" +#include "DNA_material_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" +#include "DNA_movieclip_types.h" +#include "DNA_mask_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_speaker_types.h" +#include "DNA_sound_types.h" +#include "DNA_text_types.h" +#include "DNA_vfont_types.h" +#include "DNA_windowmanager_types.h" +#include "DNA_world_types.h" + +#include "BLI_blenlib.h" +#include "BLI_utildefines.h" + +#include "BKE_action.h" +#include "BKE_animsys.h" +#include "BKE_armature.h" +#include "BKE_brush.h" +#include "BKE_camera.h" +#include "BKE_curve.h" +#include "BKE_depsgraph.h" +#include "BKE_fcurve.h" +#include "BKE_font.h" +#include "BKE_group.h" +#include "BKE_gpencil.h" +#include "BKE_idprop.h" +#include "BKE_image.h" +#include "BKE_ipo.h" +#include "BKE_key.h" +#include "BKE_lamp.h" +#include "BKE_lattice.h" +#include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" +#include "BKE_linestyle.h" +#include "BKE_mesh.h" +#include "BKE_material.h" +#include "BKE_main.h" +#include "BKE_mask.h" +#include "BKE_mball.h" +#include "BKE_modifier.h" +#include "BKE_movieclip.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_speaker.h" +#include "BKE_sound.h" +#include "BKE_screen.h" +#include "BKE_scene.h" +#include "BKE_text.h" +#include "BKE_texture.h" +#include "BKE_world.h" + +#ifdef WITH_PYTHON +#include "BPY_extern.h" +#endif + +static BKE_library_free_window_manager_cb free_windowmanager_cb = NULL; + +void BKE_library_callback_free_window_manager_set(BKE_library_free_window_manager_cb func) +{ + free_windowmanager_cb = func; +} + +static BKE_library_free_notifier_reference_cb free_notifier_reference_cb = NULL; + +void BKE_library_callback_free_notifier_reference_set(BKE_library_free_notifier_reference_cb func) +{ + free_notifier_reference_cb = func; +} + +static BKE_library_remap_editor_id_reference_cb remap_editor_id_reference_cb = NULL; + +void BKE_library_callback_remap_editor_id_reference_set(BKE_library_remap_editor_id_reference_cb func) +{ + remap_editor_id_reference_cb = func; +} + +typedef struct IDRemap { + ID *old_id; + ID *new_id; + ID *id; /* The ID in which we are replacing old_id by new_id usages. */ + short flag; + + /* 'Output' data. */ + short status; + int skipped_direct; /* Number of direct usecases that could not be remapped (e.g.: obdata when in edit mode). */ + int skipped_indirect; /* Number of indirect usecases that could not be remapped. */ + int skipped_refcounted; /* Number of skipped usecases that refcount the datablock. */ +} IDRemap; + +/* IDRemap->flag enums defined in BKE_library.h */ + +/* IDRemap->status */ +enum { + /* *** Set by callback. *** */ + ID_REMAP_IS_LINKED_DIRECT = 1 << 0, /* new_id is directly linked in current .blend. */ + ID_REMAP_IS_USER_ONE_SKIPPED = 1 << 1, /* There was some skipped 'user_one' usages of old_id. */ +}; + +static int foreach_libblock_remap_callback(void *user_data, ID *UNUSED(id_self), ID **id_p, int cb_flag) +{ + IDRemap *id_remap_data = user_data; + ID *old_id = id_remap_data->old_id; + ID *new_id = id_remap_data->new_id; + ID *id = id_remap_data->id; + + if (!old_id) { /* Used to cleanup all IDs used by a specific one. */ + BLI_assert(!new_id); + old_id = *id_p; + } + + if (*id_p && (*id_p == old_id)) { + const bool is_indirect = (cb_flag & IDWALK_INDIRECT_USAGE) != 0; + const bool skip_indirect = (id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; + /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, + * on the other hand since they get reset to lib data on file open/reload it is indirect too... + * Edit Mode is also a 'skip direct' case. */ + const bool is_obj = (GS(id->name) == ID_OB); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); + const bool is_never_null = ((cb_flag & IDWALK_NEVER_NULL) && (new_id == NULL) && + (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); + const bool skip_never_null = (id_remap_data->flag & ID_REMAP_SKIP_NEVER_NULL_USAGE) != 0; + +#ifdef DEBUG_PRINT + printf("In %s: Remapping %s (%p) to %s (%p) (skip_indirect: %d)\n", + id->name, old_id->name, old_id, new_id ? new_id->name : "<NONE>", new_id, skip_indirect); +#endif + + if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_NEVER_NULL)) { + id->tag |= LIB_TAG_DOIT; + } + + /* Special hack in case it's Object->data and we are in edit mode (skipped_direct too). */ + if ((is_never_null && skip_never_null) || + (is_obj_editmode && (((Object *)id)->data == *id_p)) || + (skip_indirect && is_indirect)) + { + if (is_indirect) { + id_remap_data->skipped_indirect++; + } + else if (is_never_null || is_obj_editmode) { + id_remap_data->skipped_direct++; + } + else { + BLI_assert(0); + } + if (cb_flag & IDWALK_USER) { + id_remap_data->skipped_refcounted++; + } + else if (cb_flag & IDWALK_USER_ONE) { + /* No need to count number of times this happens, just a flag is enough. */ + id_remap_data->status |= ID_REMAP_IS_USER_ONE_SKIPPED; + } + } + else { + if (!is_never_null) { + *id_p = new_id; + } + if (cb_flag & IDWALK_USER) { + id_us_min(old_id); + /* We do not want to handle LIB_TAG_INDIRECT/LIB_TAG_EXTERN here. */ + if (new_id) + new_id->us++; + } + else if (cb_flag & IDWALK_USER_ONE) { + id_us_ensure_real(new_id); + /* We cannot affect old_id->us directly, LIB_TAG_EXTRAUSER(_SET) are assumed to be set as needed, + * that extra user is processed in final handling... */ + } + if (!is_indirect) { + id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } + } + + return IDWALK_RET_NOP; +} + +/* Some reamapping unfortunately require extra and/or specific handling, tackle those here. */ +static void libblock_remap_data_preprocess_scene_base_unlink( + IDRemap *r_id_remap_data, Scene *sce, Base *base, const bool skip_indirect, const bool is_indirect) +{ + if (skip_indirect && is_indirect) { + r_id_remap_data->skipped_indirect++; + r_id_remap_data->skipped_refcounted++; + } + else { + id_us_min((ID *)base->object); + BKE_scene_base_unlink(sce, base); + MEM_freeN(base); + if (!is_indirect) { + r_id_remap_data->status |= ID_REMAP_IS_LINKED_DIRECT; + } + } +} + +static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) +{ + switch (GS(r_id_remap_data->id->name)) { + case ID_SCE: + { + Scene *sce = (Scene *)r_id_remap_data->id; + + if (!r_id_remap_data->new_id) { + const bool is_indirect = (sce->id.lib != NULL); + const bool skip_indirect = (r_id_remap_data->flag & ID_REMAP_SKIP_INDIRECT_USAGE) != 0; + + /* In case we are unlinking... */ + if (!r_id_remap_data->old_id) { + /* ... everything from scene. */ + Base *base, *base_next; + for (base = sce->base.first; base; base = base_next) { + base_next = base->next; + libblock_remap_data_preprocess_scene_base_unlink( + r_id_remap_data, sce, base, skip_indirect, is_indirect); + } + } + else if (GS(r_id_remap_data->old_id->name) == ID_OB) { + /* ... a specific object from scene. */ + Object *old_ob = (Object *)r_id_remap_data->old_id; + Base *base = BKE_scene_base_find(sce, old_ob); + + if (base) { + libblock_remap_data_preprocess_scene_base_unlink( + r_id_remap_data, sce, base, skip_indirect, is_indirect); + } + } + } + break; + } + case ID_OB: + { + ID *old_id = r_id_remap_data->old_id; + if (!old_id || GS(old_id->name) == ID_AR) { + Object *ob = (Object *)r_id_remap_data->id; + /* Object's pose holds reference to armature bones... sic */ + /* Note that in theory, we should have to bother about linked/non-linked/never-null/etc. flags/states. + * Fortunately, this is just a tag, so we can accept to 'over-tag' a bit for pose recalc, and avoid + * another complex and risky condition nightmare like the one we have in + * foreach_libblock_remap_callback()... */ + if (ob->pose && (!old_id || ob->data == old_id)) { + BLI_assert(ob->type == OB_ARMATURE); + ob->pose->flag |= POSE_RECALC; + } + } + break; + } + default: + break; + } +} + +static void libblock_remap_data_postprocess_object_fromgroup_update(Main *bmain, Object *old_ob, Object *new_ob) +{ + if (old_ob->flag & OB_FROMGROUP) { + /* Note that for Scene's BaseObject->flag, either we: + * - unlinked old_ob (i.e. new_ob is NULL), in which case scenes' bases have been removed already. + * - remapped old_ob by new_ob, in which case scenes' bases are still valid as is. + * So in any case, no need to update them here. */ + if (BKE_group_object_find(NULL, old_ob) == NULL) { + old_ob->flag &= ~OB_FROMGROUP; + } + if (new_ob == NULL) { /* We need to remove NULL-ified groupobjects... */ + for (Group *group = bmain->group.first; group; group = group->id.next) { + BKE_group_object_unlink(group, NULL, NULL, NULL); + } + } + else { + new_ob->flag |= OB_FROMGROUP; + } + } +} + +static void libblock_remap_data_postprocess_group_scene_unlink(Main *UNUSED(bmain), Scene *sce, ID *old_id) +{ + /* Note that here we assume no object has no base (i.e. all objects are assumed instanced + * in one scene...). */ + for (Base *base = sce->base.first; base; base = base->next) { + if (base->flag & OB_FROMGROUP) { + Object *ob = base->object; + + if (ob->flag & OB_FROMGROUP) { + Group *grp = BKE_group_object_find(NULL, ob); + + /* Unlinked group (old_id) is still in bmain... */ + if (grp && (&grp->id == old_id || grp->id.us == 0)) { + grp = BKE_group_object_find(grp, ob); + } + if (!grp) { + ob->flag &= ~OB_FROMGROUP; + } + } + if (!(ob->flag & OB_FROMGROUP)) { + base->flag &= ~OB_FROMGROUP; + } + } + } +} + +static void libblock_remap_data_postprocess_obdata_relink(Main *UNUSED(bmain), Object *ob, ID *new_id) +{ + if (ob->data == new_id) { + switch (GS(new_id->name)) { + case ID_ME: + multires_force_update(ob); + break; + case ID_CU: + BKE_curve_type_test(ob); + break; + default: + break; + } + test_object_modifiers(ob); + test_object_materials(ob, new_id); + } +} + +/** + * Execute the 'data' part of the remapping (that is, all ID pointers from other ID datablocks). + * + * Behavior differs depending on whether given \a id is NULL or not: + * - \a id NULL: \a old_id must be non-NULL, \a new_id may be NULL (unlinking \a old_id) or not + * (remapping \a old_id to \a new_id). The whole \a bmain database is checked, and all pointers to \a old_id + * are remapped to \a new_id. + * - \a id is non-NULL: + * + If \a old_id is NULL, \a new_id must also be NULL, and all ID pointers from \a id are cleared (i.e. \a id + * does not references any other datablock anymore). + * + If \a old_id is non-NULL, behavior is as with a NULL \a id, but only for given \a id. + * + * \param bmain: the Main data storage to operate on (can be NULL if \a id is non-NULL). + * \param id: the datablock to operate on (can be NULL if \a bmain is non-NULL). + * \param old_id: the datablock to dereference (may be NULL if \a id is non-NULL). + * \param new_id: the new datablock to replace \a old_id references with (may be NULL). + * \param r_id_remap_data: if non-NULL, the IDRemap struct to use (uselful to retrieve info about remapping process). + */ +static void libblock_remap_data( + Main *bmain, ID *id, ID *old_id, ID *new_id, const short remap_flags, IDRemap *r_id_remap_data) +{ + IDRemap id_remap_data; + ListBase *lb_array[MAX_LIBARRAY]; + int i; + + if (r_id_remap_data == NULL) { + r_id_remap_data = &id_remap_data; + } + r_id_remap_data->old_id = old_id; + r_id_remap_data->new_id = new_id; + r_id_remap_data->id = NULL; + r_id_remap_data->flag = remap_flags; + r_id_remap_data->status = 0; + r_id_remap_data->skipped_direct = 0; + r_id_remap_data->skipped_indirect = 0; + r_id_remap_data->skipped_refcounted = 0; + + if (id) { +#ifdef DEBUG_PRINT + printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); +#endif + r_id_remap_data->id = id; + libblock_remap_data_preprocess(r_id_remap_data); + BKE_library_foreach_ID_link(id, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + else { + i = set_listbasepointers(bmain, lb_array); + + /* Note that this is a very 'bruteforce' approach, maybe we could use some depsgraph to only process + * objects actually using given old_id... sounds rather unlikely currently, though, so this will do for now. */ + + while (i--) { + ID *id_curr = lb_array[i]->first; + + if (!id_curr || !BKE_library_idtype_can_use_idtype(GS(id_curr->name), GS(old_id->name))) { + continue; + } + + for (; id_curr; id_curr = id_curr->next) { + /* Note that we cannot skip indirect usages of old_id here (if requested), we still need to check it for + * the user count handling... + * XXX No more true (except for debug usage of those skipping counters). */ + r_id_remap_data->id = id_curr; + libblock_remap_data_preprocess(r_id_remap_data); + BKE_library_foreach_ID_link( + id_curr, foreach_libblock_remap_callback, (void *)r_id_remap_data, IDWALK_NOP); + } + } + } + + /* XXX We may not want to always 'transfer' fakeuser from old to new id... Think for now it's desired behavior + * though, we can always add an option (flag) to control this later if needed. */ + if (old_id && (old_id->flag & LIB_FAKEUSER)) { + id_fake_user_clear(old_id); + id_fake_user_set(new_id); + } + + id_us_clear_real(old_id); + + if (new_id && (new_id->tag & LIB_TAG_INDIRECT) && (r_id_remap_data->status & ID_REMAP_IS_LINKED_DIRECT)) { + new_id->tag &= ~LIB_TAG_INDIRECT; + new_id->tag |= LIB_TAG_EXTERN; + } + +#ifdef DEBUG_PRINT + printf("%s: %d occurences skipped (%d direct and %d indirect ones)\n", __func__, + r_id_remap_data->skipped_direct + r_id_remap_data->skipped_indirect, + r_id_remap_data->skipped_direct, r_id_remap_data->skipped_indirect); +#endif +} + +/** + * Replace all references in given Main to \a old_id by \a new_id + * (if \a new_id is NULL, it unlinks \a old_id). + */ +void BKE_libblock_remap_locked( + Main *bmain, void *old_idv, void *new_idv, + const short remap_flags) +{ + IDRemap id_remap_data; + ID *old_id = old_idv; + ID *new_id = new_idv; + int skipped_direct, skipped_refcounted; + + BLI_assert(old_id != NULL); + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + + libblock_remap_data(bmain, NULL, old_id, new_id, remap_flags, &id_remap_data); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(old_id); + } + + /* We assume editors do not hold references to their IDs... This is false in some cases + * (Image is especially tricky here), editors' code is to handle refcount (id->us) itself then. */ + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(old_id, new_id); + } + + skipped_direct = id_remap_data.skipped_direct; + skipped_refcounted = id_remap_data.skipped_refcounted; + + /* If old_id was used by some ugly 'user_one' stuff (like Image or Clip editors...), and user count has actually + * been incremented for that, we have to decrease once more its user count... unless we had to skip + * some 'user_one' cases. */ + if ((old_id->tag & LIB_TAG_EXTRAUSER_SET) && !(id_remap_data.status & ID_REMAP_IS_USER_ONE_SKIPPED)) { + id_us_min(old_id); + old_id->tag &= ~LIB_TAG_EXTRAUSER_SET; + } + + BLI_assert(old_id->us - skipped_refcounted >= 0); + UNUSED_VARS_NDEBUG(skipped_refcounted); + + if (skipped_direct == 0) { + /* old_id is assumed to not be used directly anymore... */ + if (old_id->lib && (old_id->tag & LIB_TAG_EXTERN)) { + old_id->tag &= ~LIB_TAG_EXTERN; + old_id->tag |= LIB_TAG_INDIRECT; + } + } + + /* Some after-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + switch (GS(old_id->name)) { + case ID_OB: + libblock_remap_data_postprocess_object_fromgroup_update(bmain, (Object *)old_id, (Object *)new_id); + break; + case ID_GR: + if (!new_id) { /* Only affects us in case group was unlinked. */ + for (Scene *sce = bmain->scene.first; sce; sce = sce->id.next) { + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); + } + } + break; + case ID_ME: + case ID_CU: + case ID_MB: + if (new_id) { /* Only affects us in case obdata was relinked (changed). */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + libblock_remap_data_postprocess_obdata_relink(bmain, ob, new_id); + } + } + break; + default: + break; + } + + /* Full rebuild of DAG! */ + DAG_relations_tag_update(bmain); +} + +void BKE_libblock_remap(Main *bmain, void *old_idv, void *new_idv, const short remap_flags) +{ + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, old_idv, new_idv, remap_flags); + + BKE_main_unlock(bmain); +} + +/** + * Unlink given \a id from given \a bmain (does not touch to indirect, i.e. library, usages of the ID). + * + * \param do_flag_never_null: If true, all IDs using \a idv in a 'non-NULL' way are flagged by \a LIB_TAG_DOIT flag + * (quite obviously, 'non-NULL' usages can never be unlinked by this function...). + */ +void BKE_libblock_unlink(Main *bmain, void *idv, const bool do_flag_never_null, const bool do_skip_indirect) +{ + const short remap_flags = (do_skip_indirect ? ID_REMAP_SKIP_INDIRECT_USAGE : 0) | + (do_flag_never_null ? ID_REMAP_FLAG_NEVER_NULL_USAGE : 0); + + BKE_main_lock(bmain); + + BKE_libblock_remap_locked(bmain, idv, NULL, remap_flags); + + BKE_main_unlock(bmain); +} + +/** Similar to libblock_remap, but only affects IDs used by given \a idv ID. + * + * \param old_idv: Unlike BKE_libblock_remap, can be NULL, + * in which case all ID usages by given \a idv will be cleared. + * \param us_min_never_null: If \a true and new_id is NULL, + * 'NEVER_NULL' ID usages keep their old id, but this one still gets its user count decremented + * (needed when given \a idv is going to be deleted right after being unlinked). + */ +/* Should be able to replace all _relink() funcs (constraints, rigidbody, etc.) ? */ +/* XXX Arg! Naming... :( + * _relink? avoids confusion with _remap, but is confusing with _unlink + * _remap_used_ids? + * _remap_datablocks? + * BKE_id_remap maybe? + * ... sigh + */ +void BKE_libblock_relink_ex( + Main *bmain, void *idv, void *old_idv, void *new_idv, const bool us_min_never_null) +{ + ID *id = idv; + ID *old_id = old_idv; + ID *new_id = new_idv; + int remap_flags = us_min_never_null ? 0 : ID_REMAP_SKIP_NEVER_NULL_USAGE; + + /* No need to lock here, we are only affecting given ID, not bmain database. */ + + BLI_assert(id); + if (old_id) { + BLI_assert((new_id == NULL) || GS(old_id->name) == GS(new_id->name)); + BLI_assert(old_id != new_id); + } + else { + BLI_assert(new_id == NULL); + } + + libblock_remap_data(NULL, id, old_id, new_id, remap_flags, NULL); + + /* Some after-process updates. + * This is a bit ugly, but cannot see a way to avoid it. Maybe we should do a per-ID callback for this instead? + */ + switch (GS(id->name)) { + case ID_SCE: + { + Scene *sce = (Scene *)id; + + if (old_id) { + switch (GS(old_id->name)) { + case ID_OB: + { + libblock_remap_data_postprocess_object_fromgroup_update( + bmain, (Object *)old_id, (Object *)new_id); + break; + } + case ID_GR: + if (!new_id) { /* Only affects us in case group was unlinked. */ + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, old_id); + } + break; + default: + break; + } + } + else { + /* No choice but to check whole objects/groups. */ + for (Object *ob = bmain->object.first; ob; ob = ob->id.next) { + libblock_remap_data_postprocess_object_fromgroup_update(bmain, ob, NULL); + } + for (Group *grp = bmain->group.first; grp; grp = grp->id.next) { + libblock_remap_data_postprocess_group_scene_unlink(bmain, sce, NULL); + } + } + break; + } + case ID_OB: + if (new_id) { /* Only affects us in case obdata was relinked (changed). */ + libblock_remap_data_postprocess_obdata_relink(bmain, (Object *)id, new_id); + } + break; + default: + break; + } +} + +static void animdata_dtar_clear_cb(ID *UNUSED(id), AnimData *adt, void *userdata) +{ + ChannelDriver *driver; + FCurve *fcu; + + /* find the driver this belongs to and update it */ + for (fcu = adt->drivers.first; fcu; fcu = fcu->next) { + driver = fcu->driver; + + if (driver) { + DriverVar *dvar; + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { + DRIVER_TARGETS_USED_LOOPER(dvar) + { + if (dtar->id == userdata) + dtar->id = NULL; + } + DRIVER_TARGETS_LOOPER_END + } + } + } +} + +void BKE_libblock_free_data(Main *bmain, ID *id) +{ + if (id->properties) { + IDP_FreeProperty(id->properties); + MEM_freeN(id->properties); + } + + /* this ID may be a driver target! */ + BKE_animdata_main_cb(bmain, animdata_dtar_clear_cb, (void *)id); +} + +/** + * used in headerbuttons.c image.c mesh.c screen.c sound.c and library.c + * + * \param do_id_user: if \a true, try to release other ID's 'references' hold by \a idv. + */ +void BKE_libblock_free_ex(Main *bmain, void *idv, const bool do_id_user) +{ + ID *id = idv; + short type = GS(id->name); + ListBase *lb = which_libbase(bmain, type); + + DAG_id_type_tag(bmain, type); + +#ifdef WITH_PYTHON + BPY_id_release(id); +#endif + + if (do_id_user) { + BKE_libblock_relink_ex(bmain, id, NULL, NULL, true); + } + + switch (type) { + case ID_SCE: + BKE_scene_free((Scene *)id); + break; + case ID_LI: + BKE_library_free((Library *)id); + break; + case ID_OB: + BKE_object_free((Object *)id); + break; + case ID_ME: + BKE_mesh_free((Mesh *)id); + break; + case ID_CU: + BKE_curve_free((Curve *)id); + break; + case ID_MB: + BKE_mball_free((MetaBall *)id); + break; + case ID_MA: + BKE_material_free((Material *)id); + break; + case ID_TE: + BKE_texture_free((Tex *)id); + break; + case ID_IM: + BKE_image_free((Image *)id); + break; + case ID_LT: + BKE_lattice_free((Lattice *)id); + break; + case ID_LA: + BKE_lamp_free((Lamp *)id); + break; + case ID_CA: + BKE_camera_free((Camera *) id); + break; + case ID_IP: /* Deprecated. */ + BKE_ipo_free((Ipo *)id); + break; + case ID_KE: + BKE_key_free((Key *)id); + break; + case ID_WO: + BKE_world_free((World *)id); + break; + case ID_SCR: + BKE_screen_free((bScreen *)id); + break; + case ID_VF: + BKE_vfont_free((VFont *)id); + break; + case ID_TXT: + BKE_text_free((Text *)id); + break; + case ID_SPK: + BKE_speaker_free((Speaker *)id); + break; + case ID_SO: + BKE_sound_free((bSound *)id); + break; + case ID_GR: + BKE_group_free((Group *)id); + break; + case ID_AR: + BKE_armature_free((bArmature *)id); + break; + case ID_AC: + BKE_action_free((bAction *)id); + break; + case ID_NT: + ntreeFreeTree((bNodeTree *)id); + break; + case ID_BR: + BKE_brush_free((Brush *)id); + break; + case ID_PA: + BKE_particlesettings_free((ParticleSettings *)id); + break; + case ID_WM: + if (free_windowmanager_cb) + free_windowmanager_cb(NULL, (wmWindowManager *)id); + break; + case ID_GD: + BKE_gpencil_free((bGPdata *)id); + break; + case ID_MC: + BKE_movieclip_free((MovieClip *)id); + break; + case ID_MSK: + BKE_mask_free((Mask *)id); + break; + case ID_LS: + BKE_linestyle_free((FreestyleLineStyle *)id); + break; + case ID_PAL: + BKE_palette_free((Palette *)id); + break; + case ID_PC: + BKE_paint_curve_free((PaintCurve *)id); + break; + } + + /* avoid notifying on removed data */ + BKE_main_lock(bmain); + + if (free_notifier_reference_cb) { + free_notifier_reference_cb(id); + } + + if (remap_editor_id_reference_cb) { + remap_editor_id_reference_cb(id, NULL); + } + + BLI_remlink(lb, id); + + BKE_libblock_free_data(bmain, id); + BKE_main_unlock(bmain); + + MEM_freeN(id); +} + +void BKE_libblock_free(Main *bmain, void *idv) +{ + BKE_libblock_free_ex(bmain, idv, true); +} + +void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */ +{ + ID *id = idv; + + id_us_min(id); + + /* XXX This is a temp (2.77) hack so that we keep same behavior as in 2.76 regarding groups when deleting an object. + * Since only 'user_one' usage of objects is groups, and only 'real user' usage of objects is scenes, + * removing that 'user_one' tag when there is no more real (scene) users of an object ensures it gets + * fully unlinked. + * Otherwise, there is no real way to get rid of an object anymore - better handling of this is TODO. + */ + if ((GS(id->name) == ID_OB) && (id->us == 1)) { + id_us_clear_real(id); + } + + if (id->us == 0) { + BKE_libblock_unlink(bmain, id, false, false); + + BKE_libblock_free(bmain, id); + } +} + +void BKE_libblock_delete(Main *bmain, void *idv) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int base_count, i; + + base_count = set_listbasepointers(bmain, lbarray); + BKE_main_id_tag_all(bmain, LIB_TAG_DOIT, false); + + /* First tag all datablocks directly from target lib. + * Note that we go forward here, since we want to check dependencies before users (e.g. meshes before objects). + * Avoids to have to loop twice. */ + for (i = 0; i < base_count; i++) { + ListBase *lb = lbarray[i]; + ID *id; + + for (id = lb->first; id; id = id->next) { + /* Note: in case we delete a library, we also delete all its datablocks! */ + if ((id == (ID *)idv) || (id->lib == (Library *)idv) || (id->tag & LIB_TAG_DOIT)) { + id->tag |= LIB_TAG_DOIT; + /* Will tag 'never NULL' users of this ID too. + * Note that we cannot use BKE_libblock_unlink() here, since it would ignore indirect (and proxy!) + * links, this can lead to nasty crashing here in second, actual deleting loop. + * Also, this will also flag users of deleted data that cannot be unlinked + * (object using deleted obdata, etc.), so that they also get deleted. */ + BKE_libblock_remap(bmain, id, NULL, ID_REMAP_FLAG_NEVER_NULL_USAGE | ID_REMAP_FORCE_NEVER_NULL_USAGE); + } + } + } + + /* In usual reversed order, such that all usage of a given ID, even 'never NULL' ones, have been already cleared + * when we reach it (e.g. Objects being processed before meshes, they'll have already released their 'reference' + * over meshes when we come to freeing obdata). */ + for (i = base_count; i--; ) { + ListBase *lb = lbarray[i]; + ID *id, *id_next; + + for (id = lb->first; id; id = id_next) { + id_next = id->next; + if (id->tag & LIB_TAG_DOIT) { + if (id->us != 0) { +#ifdef DEBUG_PRINT + printf("%s: deleting %s (%d)\n", __func__, id->name, id->us); +#endif + BLI_assert(id->us == 0); + } + BKE_libblock_free(bmain, id); + } + } + } +} diff --git a/source/blender/blenkernel/intern/linestyle.c b/source/blender/blenkernel/intern/linestyle.c index 5a1dfc04045..c4a0d0074fb 100644 --- a/source/blender/blenkernel/intern/linestyle.c +++ b/source/blender/blenkernel/intern/linestyle.c @@ -125,26 +125,25 @@ FreestyleLineStyle *BKE_linestyle_new(struct Main *bmain, const char *name) return linestyle; } +/** Free (or release) any data used by this linestyle (does not free the linestyle itself). */ void BKE_linestyle_free(FreestyleLineStyle *linestyle) { LineStyleModifier *m; - - MTex *mtex; int a; + BKE_animdata_free(&linestyle->id, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = linestyle->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(linestyle->mtex[a]); } + + /* is no lib link block, but linestyle extension */ if (linestyle->nodetree) { ntreeFreeTree(linestyle->nodetree); MEM_freeN(linestyle->nodetree); + linestyle->nodetree = NULL; } - BKE_animdata_free(&linestyle->id); while ((m = (LineStyleModifier *)linestyle->color_modifiers.first)) BKE_linestyle_color_modifier_remove(linestyle, m); while ((m = (LineStyleModifier *)linestyle->alpha_modifiers.first)) @@ -172,7 +171,7 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l } } if (linestyle->nodetree) { - new_linestyle->nodetree = ntreeCopyTree(linestyle->nodetree); + new_linestyle->nodetree = ntreeCopyTree(bmain, linestyle->nodetree); } new_linestyle->r = linestyle->r; @@ -219,8 +218,9 @@ FreestyleLineStyle *BKE_linestyle_copy(struct Main *bmain, FreestyleLineStyle *l for (m = (LineStyleModifier *)linestyle->geometry_modifiers.first; m; m = m->next) BKE_linestyle_geometry_modifier_copy(new_linestyle, m); - if (linestyle->id.lib) { - BKE_id_lib_local_paths(G.main, linestyle->id.lib, &new_linestyle->id); + if (ID_IS_LINKED_DATABLOCK(linestyle)) { + BKE_id_expand_local(&new_linestyle->id); + BKE_id_lib_local_paths(bmain, linestyle->id.lib, &new_linestyle->id); } return new_linestyle; @@ -1452,33 +1452,6 @@ char *BKE_linestyle_path_to_color_ramp(FreestyleLineStyle *linestyle, ColorBand return NULL; } -void BKE_linestyle_target_object_unlink(FreestyleLineStyle *linestyle, struct Object *ob) -{ - LineStyleModifier *m; - - for (m = (LineStyleModifier *)linestyle->color_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleColorModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleColorModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->alpha_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleAlphaModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleAlphaModifier_DistanceFromObject *)m)->target = NULL; - } - } - } - for (m = (LineStyleModifier *)linestyle->thickness_modifiers.first; m; m = m->next) { - if (m->type == LS_MODIFIER_DISTANCE_FROM_OBJECT) { - if (((LineStyleThicknessModifier_DistanceFromObject *)m)->target == ob) { - ((LineStyleThicknessModifier_DistanceFromObject *)m)->target = NULL; - } - } - } -} - bool BKE_linestyle_use_textures(FreestyleLineStyle *linestyle, const bool use_shading_nodes) { if (use_shading_nodes) { diff --git a/source/blender/blenkernel/intern/mask.c b/source/blender/blenkernel/intern/mask.c index 930a3c487ec..9e070bbef22 100644 --- a/source/blender/blenkernel/intern/mask.c +++ b/source/blender/blenkernel/intern/mask.c @@ -533,7 +533,6 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float MaskSplinePoint *points_array = BKE_mask_spline_point_array_from_point(spline, point); BezTriple *bezt = &point->bezt, *bezt_next; - float q0[2], q1[2], q2[2], r0[2], r1[2]; bezt_next = BKE_mask_spline_point_next_bezt(spline, points_array, point); @@ -542,14 +541,7 @@ void BKE_mask_point_segment_co(MaskSpline *spline, MaskSplinePoint *point, float return; } - interp_v2_v2v2(q0, bezt->vec[1], bezt->vec[2], u); - interp_v2_v2v2(q1, bezt->vec[2], bezt_next->vec[0], u); - interp_v2_v2v2(q2, bezt_next->vec[0], bezt_next->vec[1], u); - - interp_v2_v2v2(r0, q0, q1, u); - interp_v2_v2v2(r1, q1, q2, u); - - interp_v2_v2v2(co, r0, r1, u); + interp_v2_v2v2v2v2_cubic(co, bezt->vec[1], bezt->vec[2], bezt_next->vec[0], bezt_next->vec[1], u); } BLI_INLINE void orthogonal_direction_get(float vec[2], float result[2]) @@ -848,11 +840,11 @@ Mask *BKE_mask_copy_nolib(Mask *mask) return mask_new; } -Mask *BKE_mask_copy(Mask *mask) +Mask *BKE_mask_copy(Main *bmain, Mask *mask) { Mask *mask_new; - mask_new = BKE_libblock_copy(&mask->id); + mask_new = BKE_libblock_copy(bmain, &mask->id); BLI_listbase_clear(&mask_new->masklayers); @@ -861,8 +853,9 @@ Mask *BKE_mask_copy(Mask *mask) /* enable fake user by default */ id_fake_user_set(&mask->id); - if (mask->id.lib) { - BKE_id_lib_local_paths(G.main, mask->id.lib, &mask_new->id); + if (ID_IS_LINKED_DATABLOCK(mask)) { + BKE_id_expand_local(&mask_new->id); + BKE_id_lib_local_paths(bmain, mask->id.lib, &mask_new->id); } return mask_new; @@ -1010,63 +1003,10 @@ void BKE_mask_layer_free_list(ListBase *masklayers) } } -/** free for temp copy, but don't manage unlinking from other pointers */ -void BKE_mask_free_nolib(Mask *mask) +/** Free (or release) any data used by this mask (does not free the mask itself). */ +void BKE_mask_free(Mask *mask) { - BKE_mask_layer_free_list(&mask->masklayers); -} - -void BKE_mask_free(Main *bmain, Mask *mask) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *scene; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - switch (sl->spacetype) { - case SPACE_CLIP: - { - SpaceClip *sc = (SpaceClip *)sl; - - if (sc->mask_info.mask == mask) { - sc->mask_info.mask = NULL; - } - break; - } - case SPACE_IMAGE: - { - SpaceImage *sima = (SpaceImage *)sl; - - if (sima->mask_info.mask == mask) { - sima->mask_info.mask = NULL; - } - break; - } - } - } - } - } - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - if (scene->ed) { - Sequence *seq; - - SEQ_BEGIN (scene->ed, seq) - { - if (seq->mask == mask) { - seq->mask = NULL; - } - } - SEQ_END - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)mask, ntree); - } FOREACH_NODETREE_END + BKE_animdata_free((ID *)mask, false); /* free mask data */ BKE_mask_layer_free_list(&mask->masklayers); diff --git a/source/blender/blenkernel/intern/material.c b/source/blender/blenkernel/intern/material.c index 30f82a50ed9..2ae369fdd1b 100644 --- a/source/blender/blenkernel/intern/material.c +++ b/source/blender/blenkernel/intern/material.c @@ -61,6 +61,8 @@ #include "BKE_icons.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mesh.h" @@ -81,47 +83,33 @@ void init_def_material(void) BKE_material_init(&defmaterial); } -/* not material itself */ +/** Free (or release) any data used by this material (does not free the material itself). */ void BKE_material_free(Material *ma) { - BKE_material_free_ex(ma, true); -} - -/* not material itself */ -void BKE_material_free_ex(Material *ma, bool do_id_user) -{ - MTex *mtex; int a; + + BKE_animdata_free((ID *)ma, false); for (a = 0; a < MAX_MTEX; a++) { - mtex = ma->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(ma->mtex[a]); } - if (ma->ramp_col) MEM_freeN(ma->ramp_col); - if (ma->ramp_spec) MEM_freeN(ma->ramp_spec); - - BKE_animdata_free((ID *)ma); - - if (ma->preview) - BKE_previewimg_free(&ma->preview); - BKE_icon_id_delete((struct ID *)ma); - ma->id.icon_id = 0; + MEM_SAFE_FREE(ma->ramp_col); + MEM_SAFE_FREE(ma->ramp_spec); /* is no lib link block, but material extension */ if (ma->nodetree) { - ntreeFreeTree_ex(ma->nodetree, do_id_user); + ntreeFreeTree(ma->nodetree); MEM_freeN(ma->nodetree); + ma->nodetree = NULL; } - if (ma->texpaintslot) - MEM_freeN(ma->texpaintslot); + MEM_SAFE_FREE(ma->texpaintslot); + + GPU_material_free(&ma->gpumaterial); - if (ma->gpumaterial.first) - GPU_material_free(&ma->gpumaterial); + BKE_icon_id_delete((ID *)ma); + BKE_previewimg_free(&ma->preview); } void BKE_material_init(Material *ma) @@ -231,12 +219,12 @@ Material *BKE_material_add(Main *bmain, const char *name) } /* XXX keep synced with next function */ -Material *BKE_material_copy(Material *ma) +Material *BKE_material_copy(Main *bmain, Material *ma) { Material *man; int a; - man = BKE_libblock_copy(&ma->id); + man = BKE_libblock_copy(bmain, &ma->id); id_lib_extern((ID *)man->group); @@ -251,16 +239,17 @@ Material *BKE_material_copy(Material *ma) if (ma->ramp_col) man->ramp_col = MEM_dupallocN(ma->ramp_col); if (ma->ramp_spec) man->ramp_spec = MEM_dupallocN(ma->ramp_spec); - if (ma->preview) man->preview = BKE_previewimg_copy(ma->preview); - if (ma->nodetree) { - man->nodetree = ntreeCopyTree(ma->nodetree); + man->nodetree = ntreeCopyTree(bmain, ma->nodetree); } + man->preview = BKE_previewimg_copy(ma->preview); + BLI_listbase_clear(&man->gpumaterial); - - if (ma->id.lib) { - BKE_id_lib_local_paths(G.main, ma->id.lib, &man->id); + + if (ID_IS_LINKED_DATABLOCK(ma)) { + BKE_id_expand_local(&man->id); + BKE_id_lib_local_paths(bmain, ma->id.lib, &man->id); } return man; @@ -296,180 +285,33 @@ Material *localize_material(Material *ma) return man; } -static void extern_local_material(Material *ma) +void BKE_material_make_local(Main *bmain, Material *ma, const bool force_local) { - int i; - for (i = 0; i < MAX_MTEX; i++) { - if (ma->mtex[i]) id_lib_extern((ID *)ma->mtex[i]->tex); - } -} - -void BKE_material_make_local(Material *ma) -{ - Main *bmain = G.main; - Object *ob; - Mesh *me; - Curve *cu; - MetaBall *mb; - int a; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (ma->id.lib == NULL) return; - /* One local user; set flag and return. */ - if (ma->id.us == 1) { - id_clear_lib_data(bmain, &ma->id); - extern_local_material(ma); + if (!ID_IS_LINKED_DATABLOCK(ma)) { return; } - /* Check which other IDs reference this one to determine if it's used by - * lib or local */ - /* test objects */ - ob = bmain->object.first; - while (ob) { - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a] == ma) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - } - ob = ob->id.next; - } - /* test meshes */ - me = bmain->mesh.first; - while (me) { - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - if (me->id.lib) is_lib = true; - else is_local = true; - } - } - } - me = me->id.next; - } - /* test curves */ - cu = bmain->curve.first; - while (cu) { - if (cu->mat) { - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a] == ma) { - if (cu->id.lib) is_lib = true; - else is_local = true; - } - } - } - cu = cu->id.next; - } - /* test mballs */ - mb = bmain->mball.first; - while (mb) { - if (mb->mat) { - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a] == ma) { - if (mb->id.lib) is_lib = true; - else is_local = true; - } - } - } - mb = mb->id.next; - } + BKE_library_ID_test_usages(bmain, ma, &is_local, &is_lib); - /* Only local users. */ - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &ma->id); - extern_local_material(ma); - } - /* Both user and local, so copy. */ - else if (is_local && is_lib) { - Material *ma_new = BKE_material_copy(ma); - - ma_new->id.us = 0; + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &ma->id); + BKE_id_expand_local(&ma->id); + } + else { + Material *ma_new = BKE_material_copy(bmain, ma); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ma->id.lib, &ma_new->id); + ma_new->id.us = 0; - /* do objects */ - ob = bmain->object.first; - while (ob) { - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a] == ma) { - if (ob->id.lib == NULL) { - ob->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - ob = ob->id.next; - } - /* do meshes */ - me = bmain->mesh.first; - while (me) { - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a] == ma) { - if (me->id.lib == NULL) { - me->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - me = me->id.next; - } - /* do curves */ - cu = bmain->curve.first; - while (cu) { - if (cu->mat) { - for (a = 0; a < cu->totcol; a++) { - if (cu->mat[a] == ma) { - if (cu->id.lib == NULL) { - cu->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - cu = cu->id.next; + BKE_libblock_remap(bmain, ma, ma_new, ID_REMAP_SKIP_INDIRECT_USAGE); } - /* do mballs */ - mb = bmain->mball.first; - while (mb) { - if (mb->mat) { - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a] == ma) { - if (mb->id.lib == NULL) { - mb->mat[a] = ma_new; - id_us_plus(&ma_new->id); - id_us_min(&ma->id); - } - } - } - } - mb = mb->id.next; - } - } -} - -/* for curve, mball, mesh types */ -void extern_local_matarar(struct Material **matar, short totcol) -{ - short i; - for (i = 0; i < totcol; i++) { - id_lib_extern((ID *)matar[i]); } } @@ -625,7 +467,7 @@ void BKE_material_append_id(ID *id, Material *ma) (*matar)[(*totcol)++] = ma; id_us_plus((ID *)ma); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } } @@ -651,7 +493,7 @@ Material *BKE_material_pop_id(ID *id, int index_i, bool update_data) (*totcol)--; *matar = MEM_reallocN(*matar, sizeof(void *) * (*totcol)); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } if (update_data) { @@ -790,7 +632,19 @@ void BKE_material_resize_object(Object *ob, const short totcol, bool do_id_user) if (ob->actcol > ob->totcol) ob->actcol = ob->totcol; } -void test_object_materials(Main *bmain, ID *id) +void test_object_materials(Object *ob, ID *id) +{ + /* make the ob mat-array same size as 'ob->data' mat-array */ + const short *totcol; + + if (id == NULL || (totcol = give_totcolp_id(id)) == NULL) { + return; + } + + BKE_material_resize_object(ob, *totcol, false); +} + +void test_all_objects_materials(Main *bmain, ID *id) { /* make the ob mat-array same size as 'ob->data' mat-array */ Object *ob; @@ -853,7 +707,7 @@ void assign_material_id(ID *id, Material *ma, short act) if (ma) id_us_plus(&ma->id); - test_object_materials(G.main, id); + test_all_objects_materials(G.main, id); } void assign_material(Object *ob, Material *ma, short act, int assign_type) @@ -866,8 +720,8 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) if (act < 1) act = 1; /* prevent crashing when using accidentally */ - BLI_assert(ob->id.lib == NULL); - if (ob->id.lib) return; + BLI_assert(!ID_IS_LINKED_DATABLOCK(ob)); + if (ID_IS_LINKED_DATABLOCK(ob)) return; /* test arraylens */ @@ -938,7 +792,7 @@ void assign_material(Object *ob, Material *ma, short act, int assign_type) if (ma) id_us_plus(&ma->id); - test_object_materials(G.main, ob->data); + test_object_materials(ob, ob->data); } @@ -1135,7 +989,7 @@ static void do_init_render_material(Material *ma, int r_mode, float *amb) Group *group; for (group = G.main->group.first; group; group = group->id.next) { - if (!group->id.lib && STREQ(group->id.name, ma->group->id.name)) { + if (!ID_IS_LINKED_DATABLOCK(group) && STREQ(group->id.name, ma->group->id.name)) { ma->group = group; } } @@ -1840,7 +1694,7 @@ void free_matcopybuf(void) matcopybuf.ramp_spec = NULL; if (matcopybuf.nodetree) { - ntreeFreeTree_ex(matcopybuf.nodetree, false); + ntreeFreeTree(matcopybuf.nodetree); MEM_freeN(matcopybuf.nodetree); matcopybuf.nodetree = NULL; } @@ -2172,7 +2026,7 @@ static void convert_tfacematerial(Main *main, Material *ma) } /* create a new material */ else { - mat_new = BKE_material_copy(ma); + mat_new = BKE_material_copy(main, ma); if (mat_new) { /* rename the material*/ BLI_strncpy(mat_new->id.name, idname, sizeof(mat_new->id.name)); @@ -2244,7 +2098,7 @@ int do_version_tface(Main *main) /* 1st part: marking mesh materials to update */ for (me = main->mesh.first; me; me = me->id.next) { - if (me->id.lib) continue; + if (ID_IS_LINKED_DATABLOCK(me)) continue; /* get the active tface layer */ index = CustomData_get_active_layer_index(&me->fdata, CD_MTFACE); @@ -2298,7 +2152,7 @@ int do_version_tface(Main *main) * at doversion time: direct_link might not have happened on it, * so ma->mtex is not pointing to valid memory yet. * later we could, but it's better not */ - else if (ma->id.lib) + else if (ID_IS_LINKED_DATABLOCK(ma)) continue; /* material already marked as disputed */ @@ -2363,7 +2217,7 @@ int do_version_tface(Main *main) /* we shouldn't loop through the materials created in the loop. make the loop stop at its original length) */ for (ma = main->mat.first, a = 0; ma; ma = ma->id.next, a++) { - if (ma->id.lib) continue; + if (ID_IS_LINKED_DATABLOCK(ma)) continue; /* disputed material */ if (ma->game.flag == MAT_BGE_DISPUTED) { diff --git a/source/blender/blenkernel/intern/mball.c b/source/blender/blenkernel/intern/mball.c index d7019aa8458..aeb38b3bd1d 100644 --- a/source/blender/blenkernel/intern/mball.c +++ b/source/blender/blenkernel/intern/mball.c @@ -59,6 +59,8 @@ #include "BKE_depsgraph.h" #include "BKE_scene.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_displist.h" #include "BKE_mball.h" #include "BKE_object.h" @@ -66,28 +68,13 @@ /* Functions */ -void BKE_mball_unlink(MetaBall *mb) +/** Free (or release) any data used by this mball (does not free the mball itself). */ +void BKE_mball_free(MetaBall *mb) { - int a; - - for (a = 0; a < mb->totcol; a++) { - if (mb->mat[a]) - id_us_min(&mb->mat[a]->id); - mb->mat[a] = NULL; - } -} + BKE_animdata_free((ID *)mb, false); + MEM_SAFE_FREE(mb->mat); -/* do not free mball itself */ -void BKE_mball_free(MetaBall *mb) -{ - BKE_mball_unlink(mb); - - if (mb->adt) { - BKE_animdata_free((ID *)mb); - mb->adt = NULL; - } - if (mb->mat) MEM_freeN(mb->mat); BLI_freelistN(&mb->elems); if (mb->disp.first) BKE_displist_free(&mb->disp); } @@ -115,12 +102,12 @@ MetaBall *BKE_mball_add(Main *bmain, const char *name) return mb; } -MetaBall *BKE_mball_copy(MetaBall *mb) +MetaBall *BKE_mball_copy(Main *bmain, MetaBall *mb) { MetaBall *mbn; int a; - mbn = BKE_libblock_copy(&mb->id); + mbn = BKE_libblock_copy(bmain, &mb->id); BLI_duplicatelist(&mbn->elems, &mb->elems); @@ -132,65 +119,40 @@ MetaBall *BKE_mball_copy(MetaBall *mb) mbn->editelems = NULL; mbn->lastelem = NULL; - if (mb->id.lib) { - BKE_id_lib_local_paths(G.main, mb->id.lib, &mbn->id); + if (ID_IS_LINKED_DATABLOCK(mb)) { + BKE_id_expand_local(&mbn->id); + BKE_id_lib_local_paths(bmain, mb->id.lib, &mbn->id); } return mbn; } -static void extern_local_mball(MetaBall *mb) -{ - if (mb->mat) { - extern_local_matarar(mb->mat, mb->totcol); - } -} - -void BKE_mball_make_local(MetaBall *mb) +void BKE_mball_make_local(Main *bmain, MetaBall *mb, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (mb->id.lib == NULL) return; - if (mb->id.us == 1) { - id_clear_lib_data(bmain, &mb->id); - extern_local_mball(mb); - + + if (!ID_IS_LINKED_DATABLOCK(mb)) { return; } - for (ob = G.main->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (ob->data == mb) { - if (ob->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, mb, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &mb->id); + BKE_id_expand_local(&mb->id); } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &mb->id); - extern_local_mball(mb); - } - else if (is_local && is_lib) { - MetaBall *mb_new = BKE_mball_copy(mb); - mb_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, mb->id.lib, &mb_new->id); - - for (ob = G.main->object.first; ob; ob = ob->id.next) { - if (ob->data == mb) { - if (ob->id.lib == NULL) { - ob->data = mb_new; - id_us_plus(&mb_new->id); - id_us_min(&mb->id); - } - } + else { + MetaBall *mb_new = BKE_mball_copy(bmain, mb); + + mb_new->id.us = 0; + + BKE_libblock_remap(bmain, mb, mb_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/mball_tessellate.c b/source/blender/blenkernel/intern/mball_tessellate.c index e8418e876bb..2068854421f 100644 --- a/source/blender/blenkernel/intern/mball_tessellate.c +++ b/source/blender/blenkernel/intern/mball_tessellate.c @@ -1159,7 +1159,7 @@ static void init_meta(EvaluationContext *eval_ctx, PROCESS *process, Scene *scen new_ml->imat = BLI_memarena_alloc(process->pgn_elements, 4 * 4 * sizeof(float)); /* too big stiffness seems only ugly due to linear interpolation - * no need to have possibility for too big stiffness */ + * no need to have possibility for too big stiffness */ if (ml->s > 10.0f) new_ml->s = 10.0f; else new_ml->s = ml->s; @@ -1294,7 +1294,7 @@ void BKE_mball_polygonize(EvaluationContext *eval_ctx, Scene *scene, Object *ob, build_bvh_spatial(&process, &process.metaball_bvh, 0, process.totelem, &process.allbb); /* don't polygonize metaballs with too high resolution (base mball to small) - * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ + * note: Eps was 0.0001f but this was giving problems for blood animation for durian, using 0.00001f */ if (ob->size[0] > 0.00001f * (process.allbb.max[0] - process.allbb.min[0]) || ob->size[1] > 0.00001f * (process.allbb.max[1] - process.allbb.min[1]) || ob->size[2] > 0.00001f * (process.allbb.max[2] - process.allbb.min[2])) diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c index 2af78cca79f..b2f57328df3 100644 --- a/source/blender/blenkernel/intern/mesh.c +++ b/source/blender/blenkernel/intern/mesh.c @@ -49,6 +49,8 @@ #include "BKE_mesh.h" #include "BKE_displist.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_material.h" #include "BKE_modifier.h" #include "BKE_multires.h" @@ -427,38 +429,10 @@ bool BKE_mesh_has_custom_loop_normals(Mesh *me) } } -/* Note: unlinking is called when me->id.us is 0, question remains how - * much unlinking of Library data in Mesh should be done... probably - * we need a more generic method, like the expand() functions in - * readfile.c */ - -void BKE_mesh_unlink(Mesh *me) +/** Free (or release) any data used by this mesh (does not free the mesh itself). */ +void BKE_mesh_free(Mesh *me) { - int a; - - if (me == NULL) return; - - if (me->mat) { - for (a = 0; a < me->totcol; a++) { - if (me->mat[a]) - id_us_min(&me->mat[a]->id); - me->mat[a] = NULL; - } - } - - if (me->key) { - id_us_min(&me->key->id); - } - me->key = NULL; - - if (me->texcomesh) me->texcomesh = NULL; -} - -/* do not free mesh itself */ -void BKE_mesh_free(Mesh *me, int unlink) -{ - if (unlink) - BKE_mesh_unlink(me); + BKE_animdata_free(&me->id, false); CustomData_free(&me->vdata, me->totvert); CustomData_free(&me->edata, me->totedge); @@ -466,16 +440,10 @@ void BKE_mesh_free(Mesh *me, int unlink) CustomData_free(&me->ldata, me->totloop); CustomData_free(&me->pdata, me->totpoly); - if (me->adt) { - BKE_animdata_free(&me->id); - me->adt = NULL; - } - - if (me->mat) MEM_freeN(me->mat); - - if (me->bb) MEM_freeN(me->bb); - if (me->mselect) MEM_freeN(me->mselect); - if (me->edit_btmesh) MEM_freeN(me->edit_btmesh); + MEM_SAFE_FREE(me->mat); + MEM_SAFE_FREE(me->bb); + MEM_SAFE_FREE(me->mselect); + MEM_SAFE_FREE(me->edit_btmesh); } static void mesh_tessface_clear_intern(Mesh *mesh, int free_customdata) @@ -525,15 +493,13 @@ Mesh *BKE_mesh_add(Main *bmain, const char *name) return me; } -Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) +Mesh *BKE_mesh_copy(Main *bmain, Mesh *me) { Mesh *men; - MTFace *tface; - MTexPoly *txface; - int a, i; + int a; const int do_tessface = ((me->totface != 0) && (me->totpoly == 0)); /* only do tessface if we have no polys */ - men = BKE_libblock_copy_ex(bmain, &me->id); + men = BKE_libblock_copy(bmain, &me->id); men->mat = MEM_dupallocN(me->mat); for (a = 0; a < men->totcol; a++) { @@ -554,53 +520,32 @@ Mesh *BKE_mesh_copy_ex(Main *bmain, Mesh *me) BKE_mesh_update_customdata_pointers(men, do_tessface); - /* ensure indirect linked data becomes lib-extern */ - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) - if (tface->tpage) - id_lib_extern((ID *)tface->tpage); - } - } - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - txface = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, txface++) - if (txface->tpage) - id_lib_extern((ID *)txface->tpage); - } - } - men->edit_btmesh = NULL; men->mselect = MEM_dupallocN(men->mselect); men->bb = MEM_dupallocN(men->bb); - - men->key = BKE_key_copy(me->key); - if (men->key) men->key->from = (ID *)men; - if (me->id.lib) { + if (me->key) { + men->key = BKE_key_copy(bmain, me->key); + men->key->from = (ID *)men; + } + + if (ID_IS_LINKED_DATABLOCK(me)) { + BKE_id_expand_local(&men->id); BKE_id_lib_local_paths(bmain, me->id.lib, &men->id); } return men; } -Mesh *BKE_mesh_copy(Mesh *me) -{ - return BKE_mesh_copy_ex(G.main, me); -} - -BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index) +BMesh *BKE_mesh_to_bmesh( + Mesh *me, Object *ob, + const bool add_key_index, const struct BMeshCreateParams *params) { BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_ME(me); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create(&allocsize, params); BM_mesh_bm_from_me( bm, me, (&(struct BMeshFromMeshParams){ @@ -610,88 +555,32 @@ BMesh *BKE_mesh_to_bmesh(Mesh *me, Object *ob, const bool add_key_index) return bm; } -static void expand_local_mesh(Mesh *me) -{ - id_lib_extern((ID *)me->texcomesh); - - if (me->mtface || me->mtpoly) { - int a, i; - - for (i = 0; i < me->pdata.totlayer; i++) { - if (me->pdata.layers[i].type == CD_MTEXPOLY) { - MTexPoly *txface = (MTexPoly *)me->pdata.layers[i].data; - - for (a = 0; a < me->totpoly; a++, txface++) { - /* special case: ima always local immediately */ - if (txface->tpage) { - id_lib_extern((ID *)txface->tpage); - } - } - } - } - - for (i = 0; i < me->fdata.totlayer; i++) { - if (me->fdata.layers[i].type == CD_MTFACE) { - MTFace *tface = (MTFace *)me->fdata.layers[i].data; - - for (a = 0; a < me->totface; a++, tface++) { - /* special case: ima always local immediately */ - if (tface->tpage) { - id_lib_extern((ID *)tface->tpage); - } - } - } - } - } - - if (me->mat) { - extern_local_matarar(me->mat, me->totcol); - } -} - -void BKE_mesh_make_local(Mesh *me) +void BKE_mesh_make_local(Main *bmain, Mesh *me, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (me->id.lib == NULL) return; - if (me->id.us == 1) { - id_clear_lib_data(bmain, &me->id); - expand_local_mesh(me); + if (!ID_IS_LINKED_DATABLOCK(me)) { return; } - for (ob = bmain->object.first; ob && ELEM(0, is_lib, is_local); ob = ob->id.next) { - if (me == ob->data) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &me->id); - expand_local_mesh(me); - } - else if (is_local && is_lib) { - Mesh *me_new = BKE_mesh_copy(me); - me_new->id.us = 0; + BKE_library_ID_test_usages(bmain, me, &is_local, &is_lib); + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &me->id); + BKE_id_expand_local(&me->id); + } + else { + Mesh *me_new = BKE_mesh_copy(bmain, me); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, me->id.lib, &me_new->id); + me_new->id.us = 0; - for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (me == ob->data) { - if (ob->id.lib == NULL) { - BKE_mesh_assign_object(ob, me_new); - } - } + BKE_libblock_remap(bmain, me, me_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } @@ -1042,7 +931,7 @@ void BKE_mesh_assign_object(Object *ob, Mesh *me) id_us_plus((ID *)me); } - test_object_materials(G.main, (ID *)me); + test_object_materials(ob, (ID *)me); test_object_modifiers(ob); } @@ -2335,7 +2224,6 @@ Mesh *BKE_mesh_new_from_object( { Mesh *tmpmesh; Curve *tmpcu = NULL, *copycu; - Object *tmpobj = NULL; int render = settings == eModifierMode_Render, i; int cage = !apply_modifiers; @@ -2350,7 +2238,7 @@ Mesh *BKE_mesh_new_from_object( int uv_from_orco; /* copies object and modifiers (but not the data) */ - tmpobj = BKE_object_copy_ex(bmain, ob, true); + Object *tmpobj = BKE_object_copy_ex(bmain, ob, true); tmpcu = (Curve *)tmpobj->data; id_us_min(&tmpcu->id); @@ -2372,7 +2260,7 @@ Mesh *BKE_mesh_new_from_object( BKE_object_free_modifiers(tmpobj); /* copies the data */ - copycu = tmpobj->data = BKE_curve_copy((Curve *) ob->data); + copycu = tmpobj->data = BKE_curve_copy(bmain, (Curve *) ob->data); /* temporarily set edit so we get updates from edit mode, but * also because for text datablocks copying it while in edit @@ -2453,7 +2341,7 @@ Mesh *BKE_mesh_new_from_object( /* copies object and modifiers (but not the data) */ if (cage) { /* copies the data */ - tmpmesh = BKE_mesh_copy_ex(bmain, ob->data); + tmpmesh = BKE_mesh_copy(bmain, ob->data); /* if not getting the original caged mesh, get final derived mesh */ } else { @@ -2550,8 +2438,8 @@ Mesh *BKE_mesh_new_from_object( BKE_mesh_tessface_ensure(tmpmesh); } - /* make sure materials get updated in objects */ - test_object_materials(bmain, &tmpmesh->id); + /* make sure materials get updated in object */ + test_object_materials(ob, &tmpmesh->id); return tmpmesh; } diff --git a/source/blender/blenkernel/intern/modifier.c b/source/blender/blenkernel/intern/modifier.c index 716da14cae6..41e4c21d814 100644 --- a/source/blender/blenkernel/intern/modifier.c +++ b/source/blender/blenkernel/intern/modifier.c @@ -707,7 +707,7 @@ void test_object_modifiers(Object *ob) */ const char *modifier_path_relbase(Object *ob) { - if (G.relbase_valid || ob->id.lib) { + if (G.relbase_valid || ID_IS_LINKED_DATABLOCK(ob)) { return ID_BLEND_PATH(G.main, &ob->id); } else { diff --git a/source/blender/blenkernel/intern/modifiers_bmesh.c b/source/blender/blenkernel/intern/modifiers_bmesh.c index 18f3db6bd15..0838630a6cb 100644 --- a/source/blender/blenkernel/intern/modifiers_bmesh.c +++ b/source/blender/blenkernel/intern/modifiers_bmesh.c @@ -211,7 +211,9 @@ BMEditMesh *DM_to_editbmesh(DerivedMesh *dm, BMEditMesh *existing, const bool do bm = em->bm; } else { - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); } DM_to_bmesh_ex(dm, bm, do_tessellate); @@ -233,7 +235,9 @@ BMesh *DM_to_bmesh(DerivedMesh *dm, const bool calc_face_normal) BMesh *bm; const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_DM(dm); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm, bm, calc_face_normal); diff --git a/source/blender/blenkernel/intern/movieclip.c b/source/blender/blenkernel/intern/movieclip.c index d2bfcfb0887..f99457a4c26 100644 --- a/source/blender/blenkernel/intern/movieclip.c +++ b/source/blender/blenkernel/intern/movieclip.c @@ -1248,7 +1248,7 @@ static void free_buffers(MovieClip *clip) clip->anim = NULL; } - BKE_animdata_free((ID *) clip); + BKE_animdata_free((ID *) clip, false); } void BKE_movieclip_clear_cache(MovieClip *clip) @@ -1482,80 +1482,15 @@ void BKE_movieclip_build_proxy_frame_for_ibuf(MovieClip *clip, ImBuf *ibuf, stru } } +/** Free (or release) any data used by this movie clip (does not free the clip itself). */ void BKE_movieclip_free(MovieClip *clip) { + /* Also frees animdata. */ free_buffers(clip); BKE_tracking_free(&clip->tracking); } -void BKE_movieclip_unlink(Main *bmain, MovieClip *clip) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Scene *sce; - Object *ob; - - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_CLIP) { - SpaceClip *sc = (SpaceClip *) sl; - - if (sc->clip == clip) - sc->clip = NULL; - } - else if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - BGpic *bgpic; - - for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { - if (bgpic->clip == clip) - bgpic->clip = NULL; - } - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->clip == clip) - sce->clip = NULL; - } - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - bConstraint *con; - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_FOLLOWTRACK) { - bFollowTrackConstraint *data = (bFollowTrackConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_CAMERASOLVER) { - bCameraSolverConstraint *data = (bCameraSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - else if (con->type == CONSTRAINT_TYPE_OBJECTSOLVER) { - bObjectSolverConstraint *data = (bObjectSolverConstraint *) con->data; - - if (data->clip == clip) - data->clip = NULL; - } - } - } - - FOREACH_NODETREE(bmain, ntree, id) { - BKE_node_tree_unlink_id((ID *)clip, ntree); - } FOREACH_NODETREE_END - - clip->id.us = 0; -} - float BKE_movieclip_remap_scene_to_clip_frame(MovieClip *clip, float framenr) { return framenr - (float) clip->start_frame + 1.0f; diff --git a/source/blender/blenkernel/intern/nla.c b/source/blender/blenkernel/intern/nla.c index 0527df67033..c321bc92a71 100644 --- a/source/blender/blenkernel/intern/nla.c +++ b/source/blender/blenkernel/intern/nla.c @@ -183,7 +183,7 @@ NlaStrip *copy_nlastrip(NlaStrip *strip, const bool use_same_action) } else { /* use a copy of the action instead (user count shouldn't have changed yet) */ - strip_d->act = BKE_action_copy(strip_d->act); + strip_d->act = BKE_action_copy(G.main, strip_d->act); } } @@ -1291,7 +1291,7 @@ void BKE_nlastrip_recalculate_bounds(NlaStrip *strip) if (IS_EQF(mapping, 0.0f) == 0) strip->end = (actlen * mapping) + strip->start; - /* make sure we don't overlap our neighbours */ + /* make sure we don't overlap our neighbors */ nlastrip_fix_resize_overlaps(strip); } diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 3e446469b1c..2f7744684e2 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -58,6 +58,8 @@ #include "BKE_global.h" #include "BKE_idprop.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" @@ -1215,11 +1217,10 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski /* is ntree part of library? */ if (bmain && !skip_database && BLI_findindex(&bmain->nodetree, ntree) >= 0) { - newtree = BKE_libblock_copy(&ntree->id); + newtree = BKE_libblock_copy(bmain, &ntree->id); } else { newtree = BKE_libblock_copy_nolib(&ntree->id, true); - newtree->id.lib = NULL; /* same as owning datablock id.lib */ } id_us_plus((ID *)newtree->gpd); @@ -1299,7 +1300,8 @@ static bNodeTree *ntreeCopyTree_internal(bNodeTree *ntree, Main *bmain, bool ski /* node tree will generate its own interface type */ newtree->interface_type = NULL; - if (ntree->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ntree)) { + BKE_id_expand_local(&newtree->id); BKE_id_lib_local_paths(bmain, ntree->id.lib, &newtree->id); } @@ -1310,9 +1312,9 @@ bNodeTree *ntreeCopyTree_ex(bNodeTree *ntree, Main *bmain, const bool do_id_user { return ntreeCopyTree_internal(ntree, bmain, false, do_id_user, true, true); } -bNodeTree *ntreeCopyTree(bNodeTree *ntree) +bNodeTree *ntreeCopyTree(Main *bmain, bNodeTree *ntree) { - return ntreeCopyTree_ex(ntree, G.main, true); + return ntreeCopyTree_ex(ntree, bmain, true); } /* use when duplicating scenes */ @@ -1792,21 +1794,21 @@ static void free_localized_node_groups(bNodeTree *ntree) for (node = ntree->nodes.first; node; node = node->next) { if (node->type == NODE_GROUP && node->id) { bNodeTree *ngroup = (bNodeTree *)node->id; - ntreeFreeTree_ex(ngroup, false); + ntreeFreeTree(ngroup); MEM_freeN(ngroup); } } } -/* do not free ntree itself here, BKE_libblock_free calls this function too */ -void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) +/** Free (or release) any data used by this nodetree (does not free the nodetree itself). */ +void ntreeFreeTree(bNodeTree *ntree) { bNodeTree *tntree; bNode *node, *next; bNodeSocket *sock, *nextsock; - - if (ntree == NULL) return; - + + BKE_animdata_free((ID *)ntree, false); + /* XXX hack! node trees should not store execution graphs at all. * This should be removed when old tree types no longer require it. * Currently the execution data for texture nodes remains in the tree @@ -1830,29 +1832,10 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) /* unregister associated RNA types */ ntreeInterfaceTypeFree(ntree); - BKE_animdata_free((ID *)ntree); - - id_us_min((ID *)ntree->gpd); - BLI_freelistN(&ntree->links); /* do first, then unlink_node goes fast */ for (node = ntree->nodes.first; node; node = next) { next = node->next; - - /* ntreeUserIncrefID inline */ - - /* XXX, this is correct, however when freeing the entire database - * this ends up accessing freed data which isn't properly unlinking - * its self from scene nodes, SO - for now prefer invalid usercounts - * on free rather then bad memory access - Campbell */ -#if 0 - if (do_id_user) { - id_us_min(node->id); - } -#else - (void)do_id_user; -#endif - node_free_node_ex(ntree, node, false, false); } @@ -1884,11 +1867,6 @@ void ntreeFreeTree_ex(bNodeTree *ntree, const bool do_id_user) BKE_libblock_free_data(G.main, &ntree->id); } } -/* same as ntreeFreeTree_ex but always manage users */ -void ntreeFreeTree(bNodeTree *ntree) -{ - ntreeFreeTree_ex(ntree, true); -} void ntreeFreeCache(bNodeTree *ntree) { @@ -1982,70 +1960,33 @@ bNodeTree *ntreeFromID(ID *id) } } -static void extern_local_ntree(bNodeTree *ntree) -{ - for (bNode *node = ntree->nodes.first; node; node = node->next) { - if (node->id) { - id_lib_extern(node->id); - } - } -} - -void ntreeMakeLocal(bNodeTree *ntree, bool id_in_mainlist) +void ntreeMakeLocal(Main *bmain, bNodeTree *ntree, bool id_in_mainlist, const bool force_local) { - Main *bmain = G.main; - bool lib = false, local = false; + bool is_lib = false, is_local = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (ntree->id.lib == NULL) return; - if (ntree->id.us == 1) { - id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); - extern_local_ntree(ntree); + + if (!ID_IS_LINKED_DATABLOCK(ntree)) { return; } - - /* now check users of groups... again typedepending, callback... */ - FOREACH_NODETREE(G.main, tntree, owner_id) { - bNode *node; - /* find if group is in tree */ - for (node = tntree->nodes.first; node; node = node->next) { - if (node->id == (ID *)ntree) { - if (owner_id->lib) - lib = true; - else - local = true; - } + + BKE_library_ID_test_usages(bmain, ntree, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); + BKE_id_expand_local(&ntree->id); + } + else { + bNodeTree *ntree_new = ntreeCopyTree(bmain, ntree); + + ntree_new->id.us = 0; + + BKE_libblock_remap(bmain, ntree, ntree_new, ID_REMAP_SKIP_INDIRECT_USAGE); } - } FOREACH_NODETREE_END - - /* if all users are local, we simply make tree local */ - if (local && !lib) { - id_clear_lib_data_ex(bmain, (ID *)ntree, id_in_mainlist); - extern_local_ntree(ntree); - } - else if (local && lib) { - /* this is the mixed case, we copy the tree and assign it to local users */ - bNodeTree *newtree = ntreeCopyTree(ntree); - - newtree->id.us = 0; - - FOREACH_NODETREE(G.main, tntree, owner_id) { - bNode *node; - /* find if group is in tree */ - for (node = tntree->nodes.first; node; node = node->next) { - if (node->id == (ID *)ntree) { - if (owner_id->lib == NULL) { - node->id = (ID *)newtree; - id_us_plus(&newtree->id); - id_us_min(&ntree->id); - } - } - } - } FOREACH_NODETREE_END } } @@ -2175,7 +2116,7 @@ void ntreeLocalMerge(bNodeTree *localtree, bNodeTree *ntree) if (ntree->typeinfo->local_merge) ntree->typeinfo->local_merge(localtree, ntree); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } } @@ -2428,7 +2369,8 @@ void ntreeInterfaceTypeUpdate(bNodeTree *ntree) /* ************ find stuff *************** */ -bNode *ntreeFindType(const bNodeTree *ntree, int type) { +bNode *ntreeFindType(const bNodeTree *ntree, int type) +{ if (ntree) { for (bNode * node = ntree->nodes.first; node; node = node->next) { if (node->type == type) { @@ -2748,7 +2690,7 @@ void BKE_node_clipboard_add_node(bNode *node) node_info->id = node->id; if (node->id) { BLI_strncpy(node_info->id_name, node->id->name, sizeof(node_info->id_name)); - if (node->id->lib) { + if (ID_IS_LINKED_DATABLOCK(node->id)) { BLI_strncpy(node_info->library_name, node->id->lib->filepath, sizeof(node_info->library_name)); } else { diff --git a/source/blender/blenkernel/intern/object.c b/source/blender/blenkernel/intern/object.c index 65ee153e00b..4bdcec51360 100644 --- a/source/blender/blenkernel/intern/object.c +++ b/source/blender/blenkernel/intern/object.c @@ -93,6 +93,8 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_linestyle.h" #include "BKE_mesh.h" #include "BKE_editmesh.h" @@ -317,14 +319,14 @@ void BKE_object_free_derived_caches(Object *ob) if (ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->bb) { + if (me && me->bb) { me->bb->flag |= BOUNDBOX_DIRTY; } } else if (ELEM(ob->type, OB_SURF, OB_CURVE, OB_FONT)) { Curve *cu = ob->data; - if (cu->bb) { + if (cu && cu->bb) { cu->bb->flag |= BOUNDBOX_DIRTY; } } @@ -393,77 +395,52 @@ void BKE_object_free_caches(Object *object) } } -/* do not free object itself */ -void BKE_object_free_ex(Object *ob, bool do_id_user) +/** Free (or release) any data used by this object (does not free the object itself). */ +void BKE_object_free(Object *ob) { - int a; - + BKE_animdata_free((ID *)ob, false); + BKE_object_free_modifiers(ob); - - /* disconnect specific data, but not for lib data (might be indirect data, can get relinked) */ - if (ob->data) { - ID *id = ob->data; - id_us_min(id); - if (id->us == 0 && id->lib == NULL) { - switch (ob->type) { - case OB_MESH: - BKE_mesh_unlink((Mesh *)id); - break; - case OB_CURVE: - BKE_curve_unlink((Curve *)id); - break; - case OB_MBALL: - BKE_mball_unlink((MetaBall *)id); - break; - } - } - ob->data = NULL; - } - if (ob->mat) { - for (a = 0; a < ob->totcol; a++) { - if (ob->mat[a]) - id_us_min(&ob->mat[a]->id); - } - MEM_freeN(ob->mat); + MEM_SAFE_FREE(ob->mat); + MEM_SAFE_FREE(ob->matbits); + MEM_SAFE_FREE(ob->iuser); + MEM_SAFE_FREE(ob->bb); + + BLI_freelistN(&ob->defbase); + if (ob->pose) { + BKE_pose_free_ex(ob->pose, false); + ob->pose = NULL; } - if (ob->matbits) MEM_freeN(ob->matbits); - ob->mat = NULL; - ob->matbits = NULL; - if (ob->iuser) MEM_freeN(ob->iuser); - ob->iuser = NULL; - if (ob->bb) MEM_freeN(ob->bb); - ob->bb = NULL; - if (ob->adt) BKE_animdata_free((ID *)ob); - if (ob->poselib) - id_us_min(&ob->poselib->id); - if (ob->gpd) - id_us_min(&ob->gpd->id); - if (ob->defbase.first) - BLI_freelistN(&ob->defbase); - if (ob->pose) - BKE_pose_free_ex(ob->pose, do_id_user); - if (ob->mpath) + if (ob->mpath) { animviz_free_motionpath(ob->mpath); + ob->mpath = NULL; + } BKE_bproperty_free_list(&ob->prop); - + free_sensors(&ob->sensors); free_controllers(&ob->controllers); free_actuators(&ob->actuators); - BKE_constraints_free_ex(&ob->constraints, do_id_user); + BKE_constraints_free_ex(&ob->constraints, false); free_partdeflect(ob->pd); BKE_rigidbody_free_object(ob); BKE_rigidbody_free_constraint(ob); - if (ob->soft) sbFree(ob->soft); - if (ob->bsoft) bsbFree(ob->bsoft); - if (ob->gpulamp.first) GPU_lamp_free(ob); + if (ob->soft) { + sbFree(ob->soft); + ob->soft = NULL; + } + if (ob->bsoft) { + bsbFree(ob->bsoft); + ob->bsoft = NULL; + } + GPU_lamp_free(ob); BKE_sculptsession_free(ob); - if (ob->pc_ids.first) BLI_freelistN(&ob->pc_ids); + BLI_freelistN(&ob->pc_ids); BLI_freelistN(&ob->lodlevels); @@ -473,398 +450,12 @@ void BKE_object_free_ex(Object *ob, bool do_id_user) if (ob->curve_cache->path) free_path(ob->curve_cache->path); MEM_freeN(ob->curve_cache); + ob->curve_cache = NULL; } BKE_previewimg_free(&ob->preview); } -void BKE_object_free(Object *ob) -{ - BKE_object_free_ex(ob, true); -} - -static void unlink_object__unlinkModifierLinks(void *userData, Object *ob, Object **obpoin, int UNUSED(cd_flag)) -{ - Object *unlinkOb = userData; - - if (*obpoin == unlinkOb) { - *obpoin = NULL; - // XXX: should this just be OB_RECALC_DATA? - DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } -} - -void BKE_object_unlink(Main *bmain, Object *ob) -{ - Object *obt; - Material *mat; - World *wrld; - bScreen *sc; - Scene *sce; - SceneRenderLayer *srl; - FreestyleLineSet *lineset; - bNodeTree *ntree; - Curve *cu; - Tex *tex; - Group *group; - Camera *camera; - bConstraint *con; - //bActionStrip *strip; // XXX animsys - ModifierData *md; - ARegion *ar; - RegionView3D *rv3d; - LodLevel *lod; - int a, found; - - unlink_controllers(&ob->controllers); - unlink_actuators(&ob->actuators); - - /* check all objects: parents en bevels and fields, also from libraries */ - /* FIXME: need to check all animation blocks (drivers) */ - obt = bmain->object.first; - while (obt) { - if (obt->proxy == ob) - obt->proxy = NULL; - if (obt->proxy_from == ob) { - obt->proxy_from = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB); - } - if (obt->proxy_group == ob) - obt->proxy_group = NULL; - - if (obt->parent == ob) { - obt->parent = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - - modifiers_foreachObjectLink(obt, unlink_object__unlinkModifierLinks, ob); - - if (ELEM(obt->type, OB_CURVE, OB_FONT)) { - cu = obt->data; - - if (cu->bevobj == ob) { - cu->bevobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->taperobj == ob) { - cu->taperobj = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - if (cu->textoncurve == ob) { - cu->textoncurve = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); - } - } - else if (obt->type == OB_ARMATURE && obt->pose) { - bPoseChannel *pchan; - for (pchan = obt->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - if (pchan->custom == ob) - pchan->custom = NULL; - } - } - else if (ELEM(OB_MBALL, ob->type, obt->type)) { - if (BKE_mball_is_basis_for(obt, ob)) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - sca_remove_ob_poin(obt, ob); - - for (con = obt->constraints.first; con; con = con->next) { - const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); - ListBase targets = {NULL, NULL}; - bConstraintTarget *ct; - - if (cti && cti->get_constraint_targets) { - cti->get_constraint_targets(con, &targets); - - for (ct = targets.first; ct; ct = ct->next) { - if (ct->tar == ob) { - ct->tar = NULL; - ct->subtarget[0] = '\0'; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - } - - if (cti->flush_constraint_targets) - cti->flush_constraint_targets(con, &targets, 0); - } - } - - /* object is deflector or field */ - if (ob->pd) { - if (obt->soft) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - - /* cloth */ - for (md = obt->modifiers.first; md; md = md->next) - if (md->type == eModifierType_Cloth) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* strips */ -#if 0 // XXX old animation system - for (strip = obt->nlastrips.first; strip; strip = strip->next) { - if (strip->object == ob) - strip->object = NULL; - - if (strip->modifiers.first) { - bActionModifier *amod; - for (amod = strip->modifiers.first; amod; amod = amod->next) - if (amod->ob == ob) - amod->ob = NULL; - } - } -#endif // XXX old animation system - - /* particle systems */ - if (obt->particlesystem.first) { - ParticleSystem *tpsys = obt->particlesystem.first; - for (; tpsys; tpsys = tpsys->next) { - BoidState *state = NULL; - BoidRule *rule = NULL; - - ParticleTarget *pt = tpsys->targets.first; - for (; pt; pt = pt->next) { - if (pt->ob == ob) { - pt->ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - break; - } - } - - if (tpsys->target_ob == ob) { - tpsys->target_ob = NULL; - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - if (tpsys->part->dup_ob == ob) - tpsys->part->dup_ob = NULL; - - if (tpsys->part->phystype == PART_PHYS_BOIDS) { - ParticleData *pa; - BoidParticle *bpa; - int p; - - for (p = 0, pa = tpsys->particles; p < tpsys->totpart; p++, pa++) { - bpa = pa->boid; - if (bpa->ground == ob) - bpa->ground = NULL; - } - } - if (tpsys->part->boids) { - for (state = tpsys->part->boids->states.first; state; state = state->next) { - for (rule = state->rules.first; rule; rule = rule->next) { - if (rule->type == eBoidRuleType_Avoid) { - BoidRuleGoalAvoid *gabr = (BoidRuleGoalAvoid *)rule; - if (gabr->ob == ob) - gabr->ob = NULL; - } - else if (rule->type == eBoidRuleType_FollowLeader) { - BoidRuleFollowLeader *flbr = (BoidRuleFollowLeader *)rule; - if (flbr->ob == ob) - flbr->ob = NULL; - } - } - } - } - - if (tpsys->parent == ob) - tpsys->parent = NULL; - } - if (ob->pd) - DAG_id_tag_update(&obt->id, OB_RECALC_DATA); - } - - /* levels of detail */ - for (lod = obt->lodlevels.first; lod; lod = lod->next) { - if (lod->source == ob) - lod->source = NULL; - } - - obt = obt->id.next; - } - - /* materials */ - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - if (mat->nodetree) { - ntreeSwitchID(mat->nodetree, &ob->id, NULL); - } - for (a = 0; a < MAX_MTEX; a++) { - if (mat->mtex[a] && ob == mat->mtex[a]->object) { - /* actually, test for lib here... to do */ - mat->mtex[a]->object = NULL; - } - } - } - - /* node trees */ - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - if (ntree->type == NTREE_SHADER) - ntreeSwitchID(ntree, &ob->id, NULL); - } - - /* textures */ - for (tex = bmain->tex.first; tex; tex = tex->id.next) { - if (tex->env && (ob == tex->env->object)) tex->env->object = NULL; - if (tex->pd && (ob == tex->pd->object)) tex->pd->object = NULL; - if (tex->vd && (ob == tex->vd->object)) tex->vd->object = NULL; - } - - /* worlds */ - wrld = bmain->world.first; - while (wrld) { - if (wrld->id.lib == NULL) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && ob == wrld->mtex[a]->object) - wrld->mtex[a]->object = NULL; - } - } - - wrld = wrld->id.next; - } - - /* scenes */ - sce = bmain->scene.first; - while (sce) { - if (sce->id.lib == NULL) { - if (sce->camera == ob) sce->camera = NULL; - if (sce->toolsettings->skgen_template == ob) sce->toolsettings->skgen_template = NULL; - if (sce->toolsettings->particle.object == ob) sce->toolsettings->particle.object = NULL; - if (sce->toolsettings->particle.shape_object == ob) sce->toolsettings->particle.shape_object = NULL; - -#ifdef DURIAN_CAMERA_SWITCH - { - TimeMarker *m; - - for (m = sce->markers.first; m; m = m->next) { - if (m->camera == ob) - m->camera = NULL; - } - } -#endif - if (sce->ed) { - Sequence *seq; - SEQ_BEGIN(sce->ed, seq) - { - if (seq->scene_camera == ob) { - seq->scene_camera = NULL; - } - } - SEQ_END - } - - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (lineset = (FreestyleLineSet *)srl->freestyleConfig.linesets.first; - lineset; lineset = lineset->next) - { - if (lineset->linestyle) { - BKE_linestyle_target_object_unlink(lineset->linestyle, ob); - } - } - } - } - - sce = sce->id.next; - } - - /* screens */ - sc = bmain->screen.first; - while (sc) { - ScrArea *sa = sc->areabase.first; - while (sa) { - SpaceLink *sl; - - for (sl = sa->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_VIEW3D) { - View3D *v3d = (View3D *) sl; - - /* found doesn't need to be set here */ - if (v3d->ob_centre == ob) { - v3d->ob_centre = NULL; - v3d->ob_centre_bone[0] = '\0'; - } - if (v3d->localvd && v3d->localvd->ob_centre == ob) { - v3d->localvd->ob_centre = NULL; - v3d->localvd->ob_centre_bone[0] = '\0'; - } - - found = 0; - if (v3d->camera == ob) { - v3d->camera = NULL; - found = 1; - } - if (v3d->localvd && v3d->localvd->camera == ob) { - v3d->localvd->camera = NULL; - found += 2; - } - - if (found) { - if (sa->spacetype == SPACE_VIEW3D) { - for (ar = sa->regionbase.first; ar; ar = ar->next) { - if (ar->regiontype == RGN_TYPE_WINDOW) { - rv3d = (RegionView3D *)ar->regiondata; - if (found == 1 || found == 3) { - if (rv3d->persp == RV3D_CAMOB) - rv3d->persp = RV3D_PERSP; - } - if (found == 2 || found == 3) { - if (rv3d->localvd && rv3d->localvd->persp == RV3D_CAMOB) - rv3d->localvd->persp = RV3D_PERSP; - } - } - } - } - } - } -#if 0 - else if (ELEM(sl->spacetype, SPACE_OUTLINER, SPACE_BUTS, SPACE_NODE)) { - /* now handled by WM_main_remove_editor_id_reference */ - } -#endif - } - - sa = sa->next; - } - sc = sc->id.next; - } - - /* groups */ - group = bmain->group.first; - while (group) { - BKE_group_object_unlink(group, ob, NULL, NULL); - group = group->id.next; - } - - /* cameras */ - camera = bmain->camera.first; - while (camera) { - if (camera->dof_ob == ob) { - camera->dof_ob = NULL; - } - camera = camera->id.next; - } -} - /* actual check for internal data, not context or flags */ bool BKE_object_is_in_editmode(Object *ob) { @@ -1503,7 +1094,7 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) ModifierData *md; int a; - obn = BKE_libblock_copy_ex(bmain, &ob->id); + obn = BKE_libblock_copy(bmain, &ob->id); if (ob->totcol) { obn->mat = MEM_dupallocN(ob->mat); @@ -1575,11 +1166,11 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) copy_object_lod(obn, ob); - /* Copy runtime surve data. */ obn->curve_cache = NULL; - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { + BKE_id_expand_local(&obn->id); BKE_id_lib_local_paths(bmain, ob->id.lib, &obn->id); } @@ -1590,121 +1181,54 @@ Object *BKE_object_copy_ex(Main *bmain, Object *ob, bool copy_caches) } /* copy objects, will re-initialize cached simulation data */ -Object *BKE_object_copy(Object *ob) -{ - return BKE_object_copy_ex(G.main, ob, false); -} - -static void extern_local_object__modifiersForeachIDLink( - void *UNUSED(userData), Object *UNUSED(ob), ID **idpoin, int UNUSED(cd_flag)) +Object *BKE_object_copy(Main *bmain, Object *ob) { - if (*idpoin) { - /* intentionally omit ID_OB */ - if (ELEM(GS((*idpoin)->name), ID_IM, ID_TE)) { - id_lib_extern(*idpoin); - } - } + return BKE_object_copy_ex(bmain, ob, false); } -static void extern_local_object(Object *ob) +void BKE_object_make_local(Main *bmain, Object *ob, const bool force_local) { - ParticleSystem *psys; - - id_lib_extern((ID *)ob->data); - id_lib_extern((ID *)ob->dup_group); - id_lib_extern((ID *)ob->poselib); - id_lib_extern((ID *)ob->gpd); - - extern_local_matarar(ob->mat, ob->totcol); - - for (psys = ob->particlesystem.first; psys; psys = psys->next) - id_lib_extern((ID *)psys->part); - - modifiers_foreachIDLink(ob, extern_local_object__modifiersForeachIDLink, NULL); - - ob->preview = NULL; -} - -void BKE_object_make_local(Object *ob) -{ - Main *bmain = G.main; - Scene *sce; - Base *base; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (ob->id.lib == NULL) return; - - ob->proxy = ob->proxy_from = ob->proxy_group = NULL; - - if (ob->id.us == 1) { - id_clear_lib_data(bmain, &ob->id); - extern_local_object(ob); + if (!ID_IS_LINKED_DATABLOCK(ob)) { + return; } - else { - for (sce = bmain->scene.first; sce && ELEM(0, is_lib, is_local); sce = sce->id.next) { - if (BKE_scene_base_find(sce, ob)) { - if (sce->id.lib) is_lib = true; - else is_local = true; - } - } - if (is_local && is_lib == false) { + BKE_library_ID_test_usages(bmain, ob, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { id_clear_lib_data(bmain, &ob->id); - extern_local_object(ob); + BKE_id_expand_local(&ob->id); } - else if (is_local && is_lib) { - Object *ob_new = BKE_object_copy(ob); + else { + Object *ob_new = BKE_object_copy(bmain, ob); ob_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, ob->id.lib, &ob_new->id); - - sce = bmain->scene.first; - while (sce) { - if (sce->id.lib == NULL) { - base = sce->base.first; - while (base) { - if (base->object == ob) { - base->object = ob_new; - id_us_plus(&ob_new->id); - id_us_min(&ob->id); - } - base = base->next; - } - } - sce = sce->id.next; - } + ob_new->proxy = ob_new->proxy_from = ob_new->proxy_group = NULL; + + BKE_libblock_remap(bmain, ob, ob_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } -/* - * Returns true if the Object is a from an external blend file (libdata) - */ +/* Returns true if the Object is from an external blend file (libdata) */ bool BKE_object_is_libdata(Object *ob) { - if (!ob) return false; - if (ob->proxy) return false; - if (ob->id.lib) return true; - return false; + return (ob && ID_IS_LINKED_DATABLOCK(ob)); } -/* Returns true if the Object data is a from an external blend file (libdata) */ +/* Returns true if the Object data is from an external blend file (libdata) */ bool BKE_object_obdata_is_libdata(Object *ob) { - if (!ob) return false; - if (ob->proxy && (ob->data == NULL || ((ID *)ob->data)->lib == NULL)) return false; - if (ob->id.lib) return true; - if (ob->data == NULL) return false; - if (((ID *)ob->data)->lib) return true; - - return false; + /* Linked objects with local obdata are forbidden! */ + BLI_assert(!ob || !ob->data || (ID_IS_LINKED_DATABLOCK(ob) ? ID_IS_LINKED_DATABLOCK(ob->data) : true)); + return (ob && ob->data && ID_IS_LINKED_DATABLOCK(ob->data)); } /* *************** PROXY **************** */ @@ -1751,7 +1275,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) /* only on local objects because this causes indirect links * 'a -> b -> c', blend to point directly to a.blend * when a.blend has a proxy thats linked into c.blend */ - if (ob->id.lib == NULL) + if (!ID_IS_LINKED_DATABLOCK(ob)) id_lib_extern((ID *)dtar->id); } } @@ -1769,7 +1293,7 @@ void BKE_object_copy_proxy_drivers(Object *ob, Object *target) void BKE_object_make_proxy(Object *ob, Object *target, Object *gob) { /* paranoia checks */ - if (ob->id.lib || target->id.lib == NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) || !ID_IS_LINKED_DATABLOCK(target)) { printf("cannot make proxy\n"); return; } @@ -3146,7 +2670,7 @@ void BKE_object_handle_update_ex(EvaluationContext *eval_ctx, printf("recalcob %s\n", ob->id.name + 2); /* handle proxy copy for target */ - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { // printf("ob proxy copy, lib ob %s proxy %s\n", ob->id.name, ob->proxy_from->id.name); if (ob->proxy_from->proxy_group) { /* transform proxy into group space */ Object *obg = ob->proxy_from->proxy_group; diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index 67725ae5adf..cd457c77f89 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -860,7 +860,7 @@ static void make_duplis_particle_system(const DupliContext *ctx, ParticleSystem if (part == NULL) return; - if (!psys_check_enabled(par, psys)) + if (!psys_check_enabled(par, psys, (ctx->eval_ctx->mode == DAG_EVAL_RENDER))) return; if (!for_render) diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c index 2468cb8b697..5cb704e4737 100644 --- a/source/blender/blenkernel/intern/object_update.c +++ b/source/blender/blenkernel/intern/object_update.c @@ -203,7 +203,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, break; } case OB_ARMATURE: - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { if (BKE_pose_copy_result(ob->pose, ob->proxy_from->pose) == false) { printf("Proxy copy error, lib Object: %s proxy Object: %s\n", ob->id.name + 2, ob->proxy_from->id.name + 2); @@ -269,7 +269,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, psys_changed_type(ob, psys); } - if (psys_check_enabled(ob, psys)) { + if (psys_check_enabled(ob, psys, eval_ctx->mode == DAG_EVAL_RENDER)) { /* check use of dupli objects here */ if (psys->part && (psys->part->draw_as == PART_DRAW_REND || eval_ctx->mode == DAG_EVAL_RENDER) && ((psys->part->ren_as == PART_DRAW_OB && psys->part->dup_ob) || @@ -278,7 +278,7 @@ void BKE_object_handle_data_update(EvaluationContext *eval_ctx, ob->transflag |= OB_DUPLIPARTS; } - particle_system_update(scene, ob, psys); + particle_system_update(scene, ob, psys, (eval_ctx->mode == DAG_EVAL_RENDER)); psys = psys->next; } else if (psys->flag & PSYS_DELETE) { @@ -315,7 +315,7 @@ void BKE_object_eval_uber_transform(EvaluationContext *UNUSED(eval_ctx), // XXX: it's almost redundant now... /* Handle proxy copy for target, */ - if (ob->id.lib && ob->proxy_from) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from) { if (ob->proxy_from->proxy_group) { /* Transform proxy into group space. */ Object *obg = ob->proxy_from->proxy_group; @@ -347,10 +347,3 @@ void BKE_object_eval_uber_data(EvaluationContext *eval_ctx, ob->recalc &= ~(OB_RECALC_DATA | OB_RECALC_TIME); } - -void BKE_object_eval_proxy_backlink(EvaluationContext *UNUSED(eval_ctx), Object *ob) -{ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - } -} diff --git a/source/blender/blenkernel/intern/packedFile.c b/source/blender/blenkernel/intern/packedFile.c index 1c318dfd115..489fc2f3710 100644 --- a/source/blender/blenkernel/intern/packedFile.c +++ b/source/blender/blenkernel/intern/packedFile.c @@ -232,7 +232,7 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) int tot = 0; for (ima = bmain->image.first; ima; ima = ima->id.next) { - if (BKE_image_has_packedfile(ima) == false && ima->id.lib == NULL) { + if (BKE_image_has_packedfile(ima) == false && !ID_IS_LINKED_DATABLOCK(ima)) { if (ima->source == IMA_SRC_FILE) { BKE_image_packfiles(reports, ima, ID_BLEND_PATH(bmain, &ima->id)); tot ++; @@ -245,14 +245,14 @@ void packAll(Main *bmain, ReportList *reports, bool verbose) } for (vfont = bmain->vfont.first; vfont; vfont = vfont->id.next) { - if (vfont->packedfile == NULL && vfont->id.lib == NULL && BKE_vfont_is_builtin(vfont) == false) { + if (vfont->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(vfont) && BKE_vfont_is_builtin(vfont) == false) { vfont->packedfile = newPackedFile(reports, vfont->name, bmain->name); tot ++; } } for (sound = bmain->sound.first; sound; sound = sound->id.next) { - if (sound->packedfile == NULL && sound->id.lib == NULL) { + if (sound->packedfile == NULL && !ID_IS_LINKED_DATABLOCK(sound)) { sound->packedfile = newPackedFile(reports, sound->name, bmain->name); tot++; } diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 3a2663c5d48..8c1502643c5 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -298,13 +298,11 @@ void BKE_paint_brush_set(Paint *p, Brush *br) } } +/** Free (or release) any data used by this paint curve (does not free the pcurve itself). */ void BKE_paint_curve_free(PaintCurve *pc) { - if (pc->points) { - MEM_freeN(pc->points); - pc->points = NULL; - pc->tot_points = 0; - } + MEM_SAFE_FREE(pc->points); + pc->tot_points = 0; } PaintCurve *BKE_paint_curve_add(Main *bmain, const char *name) @@ -378,6 +376,7 @@ Palette *BKE_palette_add(Main *bmain, const char *name) return palette; } +/** Free (or release) any data used by this palette (does not free the palette itself). */ void BKE_palette_free(Palette *palette) { BLI_freelistN(&palette->colors); @@ -493,8 +492,6 @@ void BKE_paint_init(Scene *sce, PaintMode mode, const char col[3]) void BKE_paint_free(Paint *paint) { - id_us_min((ID *)paint->brush); - id_us_min((ID *)paint->palette); curvemapping_free(paint->cavity_curve); } diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index 106720c4f1f..f88dfdb0306 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -76,6 +76,8 @@ #include "BKE_material.h" #include "BKE_key.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_depsgraph.h" #include "BKE_modifier.h" #include "BKE_mesh.h" @@ -283,7 +285,7 @@ bool psys_in_edit_mode(Scene *scene, ParticleSystem *psys) { return (scene->basact && (scene->basact->object->mode & OB_MODE_PARTICLE_EDIT) && psys == psys_get_current((scene->basact)->object) && (psys->edit || psys->pointcache->edit) && !psys->renderdata); } -bool psys_check_enabled(Object *ob, ParticleSystem *psys) +bool psys_check_enabled(Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSystemModifierData *psmd; @@ -291,7 +293,7 @@ bool psys_check_enabled(Object *ob, ParticleSystem *psys) return 0; psmd = psys_get_modifier(ob, psys); - if (psys->renderdata || G.is_rendering) { + if (psys->renderdata || use_render_params) { if (!(psmd->modifier.mode & eModifierMode_Render)) return 0; } @@ -376,12 +378,17 @@ static void fluid_free_settings(SPHFluidSettings *fluid) MEM_freeN(fluid); } +/** Free (or release) any data used by this particle settings (does not free the partsett itself). */ void BKE_particlesettings_free(ParticleSettings *part) { - MTex *mtex; int a; - BKE_animdata_free(&part->id); + + BKE_animdata_free((ID *)part, false); + for (a = 0; a < MAX_MTEX; a++) { + MEM_SAFE_FREE(part->mtex[a]); + } + if (part->clumpcurve) curvemapping_free(part->clumpcurve); if (part->roughcurve) @@ -390,21 +397,12 @@ void BKE_particlesettings_free(ParticleSettings *part) free_partdeflect(part->pd); free_partdeflect(part->pd2); - if (part->effector_weights) - MEM_freeN(part->effector_weights); + MEM_SAFE_FREE(part->effector_weights); BLI_freelistN(&part->dupliweights); boid_free_settings(part->boids); fluid_free_settings(part->fluid); - - for (a = 0; a < MAX_MTEX; a++) { - mtex = part->mtex[a]; - if (mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); - } } void free_hair(Object *UNUSED(ob), ParticleSystem *psys, int dynamics) @@ -573,10 +571,7 @@ void psys_free(Object *ob, ParticleSystem *psys) if (!nr) ob->transflag &= ~OB_DUPLIPARTS; - if (psys->part) { - id_us_min(&psys->part->id); - psys->part = NULL; - } + psys->part = NULL; BKE_ptcache_free_list(&psys->ptcaches); psys->pointcache = NULL; @@ -2014,7 +2009,7 @@ float *psys_cache_vgroup(DerivedMesh *dm, ParticleSystem *psys, int vgroup) } return vg; } -void psys_find_parents(ParticleSimulationData *sim) +void psys_find_parents(ParticleSimulationData *sim, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = sim->psys->part; @@ -2026,7 +2021,7 @@ void psys_find_parents(ParticleSimulationData *sim) int from = PART_FROM_FACE; totparent = (int)(totchild * part->parents * 0.3f); - if ((sim->psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr) + if ((sim->psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* hard limit, workaround for it being ignored above */ @@ -2057,7 +2052,9 @@ void psys_find_parents(ParticleSimulationData *sim) BLI_kdtree_free(tree); } -static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, float cfra, int editupdate) +static bool psys_thread_context_init_path( + ParticleThreadContext *ctx, ParticleSimulationData *sim, Scene *scene, + float cfra, const bool editupdate, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -2071,7 +2068,7 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi if (psys_in_edit_mode(scene, psys)) { ParticleEditSettings *pset = &scene->toolsettings->particle; - if ((psys->renderdata == 0 && G.is_rendering == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) + if ((psys->renderdata == 0 && use_render_params == 0) && (psys->edit == NULL || pset->flag & PE_DRAW_PART) == 0) totchild = 0; segments = 1 << pset->draw_step; @@ -2080,14 +2077,14 @@ static bool psys_thread_context_init_path(ParticleThreadContext *ctx, ParticleSi if (totchild && part->childtype == PART_CHILD_FACES) { totparent = (int)(totchild * part->parents * 0.3f); - if ((psys->renderdata || G.is_rendering) && part->child_nbr && part->ren_child_nbr) + if ((psys->renderdata || use_render_params) && part->child_nbr && part->ren_child_nbr) totparent *= (float)part->child_nbr / (float)part->ren_child_nbr; /* part->parents could still be 0 so we can't test with totparent */ between = 1; } - if (psys->renderdata || G.is_rendering) + if (psys->renderdata || use_render_params) segments = 1 << part->ren_step; else { totchild = (int)((float)totchild * (float)part->disp / 100.0f); @@ -2424,7 +2421,9 @@ static void exec_child_path_cache(TaskPool * __restrict UNUSED(pool), void *task } } -void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupdate) +void psys_cache_child_paths( + ParticleSimulationData *sim, float cfra, + const bool editupdate, const bool use_render_params) { TaskScheduler *task_scheduler; TaskPool *task_pool; @@ -2437,7 +2436,7 @@ void psys_cache_child_paths(ParticleSimulationData *sim, float cfra, int editupd return; /* create a task pool for child path tasks */ - if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate)) + if (!psys_thread_context_init_path(&ctx, sim, sim->scene, cfra, editupdate, use_render_params)) return; task_scheduler = BLI_task_scheduler_get(); @@ -2529,7 +2528,7 @@ static void cache_key_incremental_rotation(ParticleCacheKey *key0, ParticleCache * - Useful for making use of opengl vertex arrays for super fast strand drawing. * - Makes child strands possible and creates them too into the cache. * - Cached path data is also used to determine cut position for the editmode tool. */ -void psys_cache_paths(ParticleSimulationData *sim, float cfra) +void psys_cache_paths(ParticleSimulationData *sim, float cfra, const bool use_render_params) { PARTICLE_PSMD; ParticleEditSettings *pset = &sim->scene->toolsettings->particle; @@ -2553,7 +2552,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) float prev_tangent[3] = {0.0f, 0.0f, 0.0f}, hairmat[4][4]; float rotmat[3][3]; int k; - int segments = (int)pow(2.0, (double)((psys->renderdata || G.is_rendering) ? part->ren_step : part->draw_step)); + int segments = (int)pow(2.0, (double)((psys->renderdata || use_render_params) ? part->ren_step : part->draw_step)); int totpart = psys->totpart; float length, vec[3]; float *vg_effector = NULL; @@ -2732,7 +2731,7 @@ void psys_cache_paths(ParticleSimulationData *sim, float cfra) if (vg_length) MEM_freeN(vg_length); } -void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra) +void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cfra, const bool use_render_params) { ParticleCacheKey *ca, **cache = edit->pathcache; ParticleEditSettings *pset = &scene->toolsettings->particle; @@ -2928,7 +2927,7 @@ void psys_cache_edit_paths(Scene *scene, Object *ob, PTCacheEdit *edit, float cf sim.psys = psys; sim.psmd = psys_get_modifier(ob, psys); - psys_cache_child_paths(&sim, cfra, 1); + psys_cache_child_paths(&sim, cfra, true, use_render_params); } /* clear recalc flag if set here */ @@ -3307,12 +3306,13 @@ void BKE_particlesettings_rough_curve_init(ParticleSettings *part) part->roughcurve = cumap; } -ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part) +ParticleSettings *BKE_particlesettings_copy(Main *bmain, ParticleSettings *part) { ParticleSettings *partn; int a; - partn = BKE_libblock_copy(&part->id); + partn = BKE_libblock_copy(bmain, &part->id); + partn->pd = MEM_dupallocN(part->pd); partn->pd2 = MEM_dupallocN(part->pd2); partn->effector_weights = MEM_dupallocN(part->effector_weights); @@ -3335,73 +3335,40 @@ ParticleSettings *BKE_particlesettings_copy(ParticleSettings *part) BLI_duplicatelist(&partn->dupliweights, &part->dupliweights); - if (part->id.lib) { - BKE_id_lib_local_paths(G.main, part->id.lib, &partn->id); + if (ID_IS_LINKED_DATABLOCK(part)) { + BKE_id_expand_local(&partn->id); + BKE_id_lib_local_paths(bmain, part->id.lib, &partn->id); } return partn; } -static void expand_local_particlesettings(ParticleSettings *part) -{ - int i; - id_lib_extern((ID *)part->dup_group); - - for (i = 0; i < MAX_MTEX; i++) { - if (part->mtex[i]) id_lib_extern((ID *)part->mtex[i]->tex); - } -} - -void BKE_particlesettings_make_local(ParticleSettings *part) +void BKE_particlesettings_make_local(Main *bmain, ParticleSettings *part, const bool force_local) { - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (part->id.lib == 0) return; - if (part->id.us == 1) { - id_clear_lib_data(bmain, &part->id); - expand_local_particlesettings(part); + + if (!ID_IS_LINKED_DATABLOCK(part)) { return; } - /* test objects */ - for (ob = bmain->object.first; ob && ELEM(false, is_lib, is_local); ob = ob->id.next) { - ParticleSystem *psys = ob->particlesystem.first; - for (; psys; psys = psys->next) { - if (psys->part == part) { - if (ob->id.lib) is_lib = true; - else is_local = true; - } + BKE_library_ID_test_usages(bmain, part, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &part->id); + BKE_id_expand_local(&part->id); } - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &part->id); - expand_local_particlesettings(part); - } - else if (is_local && is_lib) { - ParticleSettings *part_new = BKE_particlesettings_copy(part); - part_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, part->id.lib, &part_new->id); - - /* do objects */ - for (ob = bmain->object.first; ob; ob = ob->id.next) { - ParticleSystem *psys; - for (psys = ob->particlesystem.first; psys; psys = psys->next) { - if (psys->part == part && ob->id.lib == 0) { - psys->part = part_new; - id_us_plus(&part_new->id); - id_us_min(&part->id); - } - } + else { + ParticleSettings *part_new = BKE_particlesettings_copy(bmain, part); + + part_new->id.us = 0; + + BKE_libblock_remap(bmain, part, part_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index 0d7fe04a1e4..44cf5b119c1 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -1011,18 +1011,18 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti int totmapped = 0; totweight = 0.0f; for (i = 0; i < totelem; i++) { - if (element_weight[i] != 0.0f) { + if (element_weight[i] > 0.0f) { totmapped++; + totweight += element_weight[i]; } - totweight += element_weight[i]; } - if (totweight == 0.0f) { + if (totmapped == 0) { /* We are not allowed to distribute particles anywhere... */ return 0; } - inv_totweight = (totweight > 0.f ? 1.f/totweight : 0.f); + inv_totweight = 1.0f / totweight; /* Calculate cumulative weights. * We remove all null-weighted elements from element_sum, and create a new mapping @@ -1039,15 +1039,17 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti element_map[i_mapped] = i; i_mapped++; for (i++; i < totelem; i++) { - if (element_weight[i] != 0.0f) { + if (element_weight[i] > 0.0f) { element_sum[i_mapped] = element_sum[i_mapped - 1] + element_weight[i] * inv_totweight; - element_map[i_mapped] = i; - i_mapped++; + /* Skip elements which weight is so small that it does not affect the sum. */ + if (element_sum[i_mapped] > element_sum[i_mapped - 1]) { + element_map[i_mapped] = i; + i_mapped++; + } } } + totmapped = i_mapped; - BLI_assert(i_mapped == totmapped); - /* Finally assign elements to particles */ if ((part->flag & PART_TRAND) || (part->simplify_flag & PART_SIMPLIFY_ENABLE)) { for (p = 0; p < totpart; p++) { @@ -1056,7 +1058,8 @@ static int psys_thread_context_init_distribute(ParticleThreadContext *ctx, Parti const float pos = BLI_frand() * element_sum[totmapped - 1]; const int eidx = distribute_binary_search(element_sum, totmapped, pos); particle_element[p] = element_map[eidx]; - BLI_assert(pos <= element_sum[eidx] && pos > (eidx ? element_sum[eidx - 1] : 0.0f)); + BLI_assert(pos <= element_sum[eidx]); + BLI_assert(eidx ? (pos > element_sum[eidx - 1]) : (pos >= 0.0f)); jitter_offset[particle_element[p]] = pos; } } diff --git a/source/blender/blenkernel/intern/particle_system.c b/source/blender/blenkernel/intern/particle_system.c index a571afa0532..d89eac327d5 100644 --- a/source/blender/blenkernel/intern/particle_system.c +++ b/source/blender/blenkernel/intern/particle_system.c @@ -230,7 +230,7 @@ static void realloc_particles(ParticleSimulationData *sim, int new_totpart) newboids= MEM_callocN(totpart*sizeof(BoidParticle), "boid particles"); if (newboids == NULL) { - /* allocation error! */ + /* allocation error! */ if (newpars) MEM_freeN(newpars); return; @@ -2885,7 +2885,7 @@ static void collision_check(ParticleSimulationData *sim, int p, float dfra, floa /* Hair */ /************************************************/ /* check if path cache or children need updating and do it if needed */ -static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) +static void psys_update_path_cache(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -2909,7 +2909,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) distribute_particles(sim, PART_FROM_CHILD); if (part->childtype==PART_CHILD_FACES && part->parents != 0.0f) - psys_find_parents(sim); + psys_find_parents(sim, use_render_params); } } else @@ -2947,7 +2947,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) } if (!skip) { - psys_cache_paths(sim, cfra); + psys_cache_paths(sim, cfra, use_render_params); /* for render, child particle paths are computed on the fly */ if (part->childtype) { @@ -2957,7 +2957,7 @@ static void psys_update_path_cache(ParticleSimulationData *sim, float cfra) skip = 1; if (!skip) - psys_cache_child_paths(sim, cfra, 0); + psys_cache_child_paths(sim, cfra, 0, use_render_params); } } else if (psys->pathcache) @@ -3193,7 +3193,7 @@ static void do_hair_dynamics(ParticleSimulationData *sim) /* restore cloth effector weights */ psys->clmd->sim_parms->effector_weights = clmd_effweights; } -static void hair_step(ParticleSimulationData *sim, float cfra) +static void hair_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3225,7 +3225,7 @@ static void hair_step(ParticleSimulationData *sim, float cfra) /* following lines were removed r29079 but cause bug [#22811], see report for details */ psys_update_effectors(sim); - psys_update_path_cache(sim, cfra); + psys_update_path_cache(sim, cfra, use_render_params); psys->flag |= PSYS_HAIR_UPDATED; } @@ -3732,7 +3732,7 @@ static void cached_step(ParticleSimulationData *sim, float cfra) } } -static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) +static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra), const bool use_render_params) { ParticleSystem *psys = sim->psys; if (psys->particles) { @@ -3775,7 +3775,7 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) } gzread(gzf, &totpart, sizeof(totpart)); - totpart = (G.is_rendering)?totpart:(part->disp*totpart) / 100; + totpart = (use_render_params) ? totpart:(part->disp*totpart) / 100; part->totpart= totpart; part->sta=part->end = 1.0f; @@ -3836,6 +3836,8 @@ static void particles_fluid_step(ParticleSimulationData *sim, int UNUSED(cfra)) } // fluid sim particles done } +#else + UNUSED_VARS(use_render_params); #endif // WITH_MOD_FLUID } @@ -3857,7 +3859,7 @@ static int emit_particles(ParticleSimulationData *sim, PTCacheID *pid, float UNU * 2. Check cache (if used) and return if frame is cached * 3. Do dynamics * 4. Save to cache */ -static void system_step(ParticleSimulationData *sim, float cfra) +static void system_step(ParticleSimulationData *sim, float cfra, const bool use_render_params) { ParticleSystem *psys = sim->psys; ParticleSettings *part = psys->part; @@ -3919,7 +3921,7 @@ static void system_step(ParticleSimulationData *sim, float cfra) if (ELEM(cache_result, PTCACHE_READ_EXACT, PTCACHE_READ_INTERPOLATED)) { cached_step(sim, cfra); update_children(sim); - psys_update_path_cache(sim, cfra); + psys_update_path_cache(sim, cfra, use_render_params); BKE_ptcache_validate(cache, (int)cache_cfra); @@ -4137,7 +4139,7 @@ static int hair_needs_recalc(ParticleSystem *psys) /* main particle update call, checks that things are ok on the large scale and * then advances in to actual particle calculations depending on particle type */ -void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) +void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys, const bool use_render_params) { ParticleSimulationData sim= {0}; ParticleSettings *part = psys->part; @@ -4146,7 +4148,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) /* drawdata is outdated after ANY change */ if (psys->pdd) psys->pdd->flag &= ~PARTICLE_DRAW_DATA_UPDATED; - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, use_render_params)) return; cfra= BKE_scene_frame_get(scene); @@ -4215,7 +4217,7 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) hcfra=100.0f*(float)i/(float)psys->part->hair_step; if ((part->flag & PART_HAIR_REGROW)==0) BKE_animsys_evaluate_animdata(scene, &part->id, part->adt, hcfra, ADT_RECALC_ANIM); - system_step(&sim, hcfra); + system_step(&sim, hcfra, use_render_params); psys->cfra = hcfra; psys->recalc = 0; save_hair(&sim, hcfra); @@ -4228,12 +4230,12 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) psys->flag |= PSYS_HAIR_DONE; if (psys->flag & PSYS_HAIR_DONE) - hair_step(&sim, cfra); + hair_step(&sim, cfra, use_render_params); break; } case PART_FLUID: { - particles_fluid_step(&sim, (int)cfra); + particles_fluid_step(&sim, (int)cfra, use_render_params); break; } default: @@ -4280,14 +4282,14 @@ void particle_system_update(Scene *scene, Object *ob, ParticleSystem *psys) if (part->phystype == PART_PHYS_KEYED) { psys_count_keyed_targets(&sim); set_keyed_keys(&sim); - psys_update_path_cache(&sim,(int)cfra); + psys_update_path_cache(&sim, (int)cfra, use_render_params); } break; } default: { /* the main dynamic particle system step */ - system_step(&sim, cfra); + system_step(&sim, cfra, use_render_params); break; } } diff --git a/source/blender/blenkernel/intern/pbvh.c b/source/blender/blenkernel/intern/pbvh.c index 58ec75dc706..ff69f381b06 100644 --- a/source/blender/blenkernel/intern/pbvh.c +++ b/source/blender/blenkernel/intern/pbvh.c @@ -276,16 +276,14 @@ static void build_mesh_leaf_node(PBVH *bvh, PBVHNode *node) /* reserve size is rough guess */ GHash *map = BLI_ghash_int_new_ex("build_mesh_leaf_node gh", 2 * totface); - int (*face_vert_indices)[4] = MEM_callocN(sizeof(int[4]) * totface, + int (*face_vert_indices)[3] = MEM_mallocN(sizeof(int[3]) * totface, "bvh node face vert indices"); - node->face_vert_indices = (const int (*)[4])face_vert_indices; + node->face_vert_indices = (const int (*)[3])face_vert_indices; for (int i = 0; i < totface; ++i) { const MLoopTri *lt = &bvh->looptri[node->prim_indices[i]]; - const int sides = 3; - - for (int j = 0; j < sides; ++j) { + for (int j = 0; j < 3; ++j) { face_vert_indices[i][j] = map_insert_vert(bvh, map, &node->face_verts, &node->uniq_verts, bvh->mloop[lt->tri[j]].v); @@ -690,8 +688,7 @@ static void pbvh_stack_push(PBVHIter *iter, PBVHNode *node, bool revisiting) { if (UNLIKELY(iter->stacksize == iter->stackspace)) { iter->stackspace *= 2; - - if (iter->stackspace != STACK_FIXED_DEPTH) { + if (iter->stackspace != (STACK_FIXED_DEPTH * 2)) { iter->stack = MEM_reallocN(iter->stack, sizeof(PBVHStack) * iter->stackspace); } else { @@ -1496,12 +1493,18 @@ typedef struct { static bool ray_aabb_intersect(PBVHNode *node, void *data_v) { RaycastData *rcd = data_v; - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; - if (rcd->original) - BKE_pbvh_node_get_original_BB(node, bb_min, bb_max); - else - BKE_pbvh_node_get_BB(node, bb_min, bb_max); + if (rcd->original) { + /* BKE_pbvh_node_get_original_BB */ + bb_min = node->orig_vb.bmin; + bb_max = node->orig_vb.bmax; + } + else { + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; + } return isect_ray_aabb_v3(&rcd->ray, bb_min, bb_max, &node->tmin); } @@ -1801,17 +1804,21 @@ static PlaneAABBIsect test_planes_aabb(const float bb_min[3], bool BKE_pbvh_node_planes_contain_AABB(PBVHNode *node, void *data) { - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; - BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_OUTSIDE; } bool BKE_pbvh_node_planes_exclude_AABB(PBVHNode *node, void *data) { - float bb_min[3], bb_max[3]; + const float *bb_min, *bb_max; + /* BKE_pbvh_node_get_BB */ + bb_min = node->vb.bmin; + bb_max = node->vb.bmax; - BKE_pbvh_node_get_BB(node, bb_min, bb_max); return test_planes_aabb(bb_min, bb_max, data) != ISECT_INSIDE; } diff --git a/source/blender/blenkernel/intern/pbvh_bmesh.c b/source/blender/blenkernel/intern/pbvh_bmesh.c index 88dc63d6cb2..55f9f384081 100644 --- a/source/blender/blenkernel/intern/pbvh_bmesh.c +++ b/source/blender/blenkernel/intern/pbvh_bmesh.c @@ -69,11 +69,134 @@ static void pbvh_bmesh_verify(PBVH *bvh); #endif +/** \name BMesh Utility API + * + * Use some local functions which assume triangles. + * \{ */ + +/** + * Typically using BM_LOOPS_OF_VERT and BM_FACES_OF_VERT iterators are fine, + * however this is an area where performance matters so do it in-line. + * + * Take care since 'break' won't works as expected within these macros! + */ + +#define BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) \ +{ \ + struct { BMVert *v; BMEdge *e_iter, *e_first; BMLoop *l_iter_radial; } _iter; \ + _iter.v = v_; \ + if (_iter.v->e) { \ + _iter.e_iter = _iter.e_first = _iter.v->e; \ + do { \ + if (_iter.e_iter->l) { \ + _iter.l_iter_radial = _iter.e_iter->l; \ + do { \ + if (_iter.l_iter_radial->v == _iter.v) { \ + l_iter_radial_ = _iter.l_iter_radial; + +#define BM_LOOPS_OF_VERT_ITER_END \ + } \ + } while ((_iter.l_iter_radial = _iter.l_iter_radial->radial_next) != _iter.e_iter->l); \ + } \ + } while ((_iter.e_iter = BM_DISK_EDGE_NEXT(_iter.e_iter, _iter.v)) != _iter.e_first); \ + } \ +} ((void)0) + +#define BM_FACES_OF_VERT_ITER_BEGIN(f_iter_, v_) \ +{ \ + BMLoop *l_iter_radial_; \ + BM_LOOPS_OF_VERT_ITER_BEGIN(l_iter_radial_, v_) { \ + f_iter_ = l_iter_radial_->f; \ + +#define BM_FACES_OF_VERT_ITER_END \ + } \ + BM_LOOPS_OF_VERT_ITER_END; \ +} + +static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) +{ + e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); + e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); + e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); +} + +BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) +{ + BMLoop *l = BM_FACE_FIRST_LOOP(f); + + BLI_assert(f->len == 3); + + r_index[0] = BM_elem_index_get(l->v); l = l->next; + r_index[1] = BM_elem_index_get(l->v); l = l->next; + r_index[2] = BM_elem_index_get(l->v); +} + +/** + * A version of #BM_face_exists, optimized for triangles + * when we know the loop and the opposite vertex. + * + * Check if any triangle is formed by (l_radial_first->v, l_radial_first->next->v, v_opposite), + * at either winding (since its a triangle no special checks are needed). + * + * <pre> + * l_radial_first->v & l_radial_first->next->v + * +---+ + * | / + * | / + * + v_opposite + * </pre> + * + * Its assumed that \a l_radial_first is never forming the target face. + */ +static bool bm_face_exists_tri_from_loop_vert( + BMLoop *l_radial_first, BMVert *v_opposite, BMFace **r_face_existing) +{ + BLI_assert(!ELEM(v_opposite, l_radial_first->v, l_radial_first->next->v, l_radial_first->prev->v)); + if (l_radial_first->radial_next != l_radial_first) { + BMLoop *l_radial_iter = l_radial_first->radial_next; + do { + BLI_assert(l_radial_iter->f->len == 3); + if (l_radial_iter->prev->v == v_opposite) { + *r_face_existing = l_radial_iter->f; + return true; + } + } while ((l_radial_iter = l_radial_iter->radial_next) != l_radial_first); + } + return false; +} + +/** + * Uses a map of vertices to lookup the final target. + * References can't point to previous items (would cause infinite loop). + */ +static BMVert *bm_vert_hash_lookup_chain(GHash *deleted_verts, BMVert *v) +{ + while (true) { + BMVert **v_next_p = (BMVert **)BLI_ghash_lookup_p(deleted_verts, v); + if (v_next_p == NULL) { + /* not remapped*/ + return v; + } + else if (*v_next_p == NULL) { + /* removed and not remapped */ + return NULL; + } + else { + /* remapped */ + v = *v_next_p; + } + } +} + +/** \} */ + /****************************** Building ******************************/ /* Update node data after splitting */ -static void pbvh_bmesh_node_finalize(PBVH *bvh, int node_index, const int cd_vert_node_offset, const int cd_face_node_offset) +static void pbvh_bmesh_node_finalize( + PBVH *bvh, const int node_index, + const int cd_vert_node_offset, const int cd_face_node_offset) { GSetIterator gs_iter; PBVHNode *n = &bvh->nodes[node_index]; @@ -200,7 +323,7 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde break; } } - + /* Clear this node */ /* Mark this node's unique verts as unclaimed */ @@ -224,18 +347,18 @@ static void pbvh_bmesh_node_split(PBVH *bvh, const BBC *bbc_array, int node_inde if (n->layer_disp) MEM_freeN(n->layer_disp); - + n->bm_faces = NULL; n->bm_unique_verts = NULL; n->bm_other_verts = NULL; n->layer_disp = NULL; - + if (n->draw_buffers) { GPU_free_pbvh_buffers(n->draw_buffers); n->draw_buffers = NULL; } n->flag &= ~PBVH_Leaf; - + /* Recurse */ pbvh_bmesh_node_split(bvh, bbc_array, children); pbvh_bmesh_node_split(bvh, bbc_array, children + 1); @@ -292,6 +415,7 @@ static bool pbvh_bmesh_node_limit_ensure(PBVH *bvh, int node_index) /**********************************************************************/ +#if 0 static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele) { switch (ele->head.htype) { @@ -304,7 +428,7 @@ static int pbvh_bmesh_node_offset_from_elem(PBVH *bvh, BMElem *ele) } -static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key) +static int pbvh_bmesh_node_index_from_elem(PBVH *bvh, void *key) { const int cd_node_offset = pbvh_bmesh_node_offset_from_elem(bvh, key); const int node_index = BM_ELEM_CD_GET_INT((BMElem *)key, cd_node_offset); @@ -316,18 +440,45 @@ static int pbvh_bmesh_node_lookup_index(PBVH *bvh, void *key) return node_index; } -static PBVHNode *pbvh_bmesh_node_lookup(PBVH *bvh, void *key) +static PBVHNode *pbvh_bmesh_node_from_elem(PBVH *bvh, void *key) { - return &bvh->nodes[pbvh_bmesh_node_lookup_index(bvh, key)]; + return &bvh->nodes[pbvh_bmesh_node_index_from_elem(bvh, key)]; } /* typecheck */ -#define pbvh_bmesh_node_lookup_index(bvh, key) ( \ +#define pbvh_bmesh_node_index_from_elem(bvh, key) ( \ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \ - pbvh_bmesh_node_lookup_index(bvh, key)) -#define pbvh_bmesh_node_lookup(bvh, key) ( \ + pbvh_bmesh_node_index_from_elem(bvh, key)) +#define pbvh_bmesh_node_from_elem(bvh, key) ( \ CHECK_TYPE_ANY(key, BMFace *, BMVert *), \ - pbvh_bmesh_node_lookup(bvh, key)) + pbvh_bmesh_node_from_elem(bvh, key)) +#endif + +BLI_INLINE int pbvh_bmesh_node_index_from_vert(PBVH *bvh, const BMVert *key) +{ + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_vert_node_offset); + BLI_assert(node_index != DYNTOPO_NODE_NONE); + BLI_assert(node_index < bvh->totnode); + return node_index; +} + +BLI_INLINE int pbvh_bmesh_node_index_from_face(PBVH *bvh, const BMFace *key) +{ + const int node_index = BM_ELEM_CD_GET_INT((const BMElem *)key, bvh->cd_face_node_offset); + BLI_assert(node_index != DYNTOPO_NODE_NONE); + BLI_assert(node_index < bvh->totnode); + return node_index; +} + +BLI_INLINE PBVHNode *pbvh_bmesh_node_from_vert(PBVH *bvh, const BMVert *key) +{ + return &bvh->nodes[pbvh_bmesh_node_index_from_vert(bvh, key)]; +} + +BLI_INLINE PBVHNode *pbvh_bmesh_node_from_face(PBVH *bvh, const BMFace *key) +{ + return &bvh->nodes[pbvh_bmesh_node_index_from_face(bvh, key)]; +} static BMVert *pbvh_bmesh_vert_create( @@ -357,6 +508,9 @@ static BMVert *pbvh_bmesh_vert_create( return v; } +/** + * \note Callers are responsible for checking if the face exists before adding. + */ static BMFace *pbvh_bmesh_face_create( PBVH *bvh, int node_index, BMVert *v_tri[3], BMEdge *e_tri[3], @@ -367,7 +521,7 @@ static BMFace *pbvh_bmesh_face_create( /* ensure we never add existing face */ BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); - BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NO_DOUBLE); + BMFace *f = BM_face_create(bvh->bm, v_tri, e_tri, 3, f_example, BM_CREATE_NOP); f->head.hflag = f_example->head.hflag; BLI_gset_insert(node->bm_faces, f); @@ -387,16 +541,16 @@ static BMFace *pbvh_bmesh_face_create( #if 0 static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) { - BMIter bm_iter; BMFace *f; int count = 0; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); if (f_node == node) { count++; } } + BM_FACES_OF_VERT_ITER_END; return count; } @@ -407,19 +561,19 @@ static int pbvh_bmesh_node_vert_use_count(PBVH *bvh, PBVHNode *node, BMVert *v) static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert *v, const int count_max) { - BMIter bm_iter; - BMFace *f; int count = 0; + BMFace *f; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); if (f_node == node) { count++; if (count == count_max) { - break; + return count; } } } + BM_FACES_OF_VERT_ITER_END; return count; } @@ -427,16 +581,17 @@ static int pbvh_bmesh_node_vert_use_count_ex(PBVH *bvh, PBVHNode *node, BMVert * /* Return a node that uses vertex 'v' other than its current owner */ static PBVHNode *pbvh_bmesh_vert_other_node_find(PBVH *bvh, BMVert *v) { - BMIter bm_iter; + PBVHNode *current_node = pbvh_bmesh_node_from_vert(bvh, v); BMFace *f; - PBVHNode *current_node = pbvh_bmesh_node_lookup(bvh, v); - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); - if (f_node != current_node) + if (f_node != current_node) { return f_node; + } } + BM_FACES_OF_VERT_ITER_END; return NULL; } @@ -445,7 +600,7 @@ static void pbvh_bmesh_vert_ownership_transfer( PBVH *bvh, PBVHNode *new_owner, BMVert *v) { - PBVHNode *current_owner = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *current_owner = pbvh_bmesh_node_from_vert(bvh, v); /* mark node for update */ current_owner->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; @@ -469,36 +624,36 @@ static void pbvh_bmesh_vert_remove(PBVH *bvh, BMVert *v) /* never match for first time */ int f_node_index_prev = DYNTOPO_NODE_NONE; - PBVHNode *v_node = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *v_node = pbvh_bmesh_node_from_vert(bvh, v); BLI_gset_remove(v_node->bm_unique_verts, v, NULL); BM_ELEM_CD_SET_INT(v, bvh->cd_vert_node_offset, DYNTOPO_NODE_NONE); /* Have to check each neighboring face's node */ - BMIter bm_iter; BMFace *f; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - const int f_node_index = pbvh_bmesh_node_lookup_index(bvh, f); + BM_FACES_OF_VERT_ITER_BEGIN(f, v) { + const int f_node_index = pbvh_bmesh_node_index_from_face(bvh, f); /* faces often share the same node, * quick check to avoid redundant #BLI_gset_remove calls */ - if (f_node_index_prev == f_node_index) - continue; - f_node_index_prev = f_node_index; + if (f_node_index_prev != f_node_index) { + f_node_index_prev = f_node_index; - PBVHNode *f_node = &bvh->nodes[f_node_index]; - f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; + PBVHNode *f_node = &bvh->nodes[f_node_index]; + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateBB; - /* Remove current ownership */ - BLI_gset_remove(f_node->bm_other_verts, v, NULL); + /* Remove current ownership */ + BLI_gset_remove(f_node->bm_other_verts, v, NULL); - BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v)); - BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_unique_verts, v)); + BLI_assert(!BLI_gset_haskey(f_node->bm_other_verts, v)); + } } + BM_FACES_OF_VERT_ITER_END; } static void pbvh_bmesh_face_remove(PBVH *bvh, BMFace *f) { - PBVHNode *f_node = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, f); /* Check if any of this face's vertices need to be removed * from the node */ @@ -923,13 +1078,6 @@ static void short_edge_queue_create( /*************************** Topology update **************************/ -static void bm_edges_from_tri(BMesh *bm, BMVert *v_tri[3], BMEdge *e_tri[3]) -{ - e_tri[0] = BM_edge_create(bm, v_tri[0], v_tri[1], NULL, BM_CREATE_NO_DOUBLE); - e_tri[1] = BM_edge_create(bm, v_tri[1], v_tri[2], NULL, BM_CREATE_NO_DOUBLE); - e_tri[2] = BM_edge_create(bm, v_tri[2], v_tri[0], NULL, BM_CREATE_NO_DOUBLE); -} - static void pbvh_bmesh_split_edge( EdgeQueueContext *eq_ctx, PBVH *bvh, BMEdge *e, BLI_Buffer *edge_loops) @@ -1101,15 +1249,16 @@ static bool pbvh_bmesh_subdivide_long_edges( static void pbvh_bmesh_collapse_edge( PBVH *bvh, BMEdge *e, BMVert *v1, BMVert *v2, - GSet *deleted_verts, + GHash *deleted_verts, BLI_Buffer *deleted_faces, EdgeQueueContext *eq_ctx) { BMVert *v_del, *v_conn; - float mask_v1 = BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset); /* one of the two vertices may be masked, select the correct one for deletion */ - if (mask_v1 < 1.0f) { + if (BM_ELEM_CD_GET_FLOAT(v1, eq_ctx->cd_vert_mask_offset) < + BM_ELEM_CD_GET_FLOAT(v2, eq_ctx->cd_vert_mask_offset)) + { v_del = v1; v_conn = v2; } @@ -1141,33 +1290,43 @@ static void pbvh_bmesh_collapse_edge( * really buy anything. */ BLI_buffer_empty(deleted_faces); - BMIter bm_iter; - BMFace *f; + BMLoop *l; - BM_ITER_ELEM (f, &bm_iter, v_del, BM_FACES_OF_VERT) { - BMVert *v_tri[3]; + BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_del) { BMFace *existing_face; /* Get vertices, replace use of v_del with v_conn */ // BM_iter_as_array(NULL, BM_VERTS_OF_FACE, f, (void **)v_tri, 3); + BMFace *f = l->f; +#if 0 + BMVert *v_tri[3]; BM_face_as_array_vert_tri(f, v_tri); for (int i = 0; i < 3; i++) { if (v_tri[i] == v_del) { v_tri[i] = v_conn; } } +#endif /* Check if a face using these vertices already exists. If so, * skip adding this face and mark the existing one for * deletion as well. Prevents extraneous "flaps" from being * created. */ - if (BM_face_exists(v_tri, 3, &existing_face)) { +#if 0 + if (UNLIKELY(BM_face_exists(v_tri, 3, &existing_face))) +#else + if (UNLIKELY(bm_face_exists_tri_from_loop_vert(l->next, v_conn, &existing_face))) +#endif + { BLI_assert(existing_face); BLI_buffer_append(deleted_faces, BMFace *, existing_face); } else { + BMVert *v_tri[3] = {v_conn, l->next->v, l->prev->v}; + + BLI_assert(BM_face_exists(v_tri, 3, NULL) == false); BMEdge *e_tri[3]; - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + PBVHNode *n = pbvh_bmesh_node_from_face(bvh, f); int ni = n - bvh->nodes; bm_edges_from_tri(bvh->bm, v_tri, e_tri); pbvh_bmesh_face_create(bvh, ni, v_tri, e_tri, f); @@ -1180,6 +1339,7 @@ static void pbvh_bmesh_collapse_edge( BLI_buffer_append(deleted_faces, BMFace *, f); } + BM_LOOPS_OF_VERT_ITER_END; /* Delete the tagged faces */ for (int i = 0; i < deleted_faces->count; i++) { @@ -1209,10 +1369,14 @@ static void pbvh_bmesh_collapse_edge( * remove them from the PBVH */ for (int j = 0; j < 3; j++) { if ((v_tri[j] != v_del) && (v_tri[j]->e == NULL)) { - BLI_gset_insert(deleted_verts, v_tri[j]); pbvh_bmesh_vert_remove(bvh, v_tri[j]); BM_log_vert_removed(bvh->bm_log, v_tri[j], eq_ctx->cd_vert_mask_offset); + + if (v_tri[j] == v_conn) { + v_conn = NULL; + } + BLI_ghash_insert(deleted_verts, v_tri[j], NULL); BM_vert_kill(bvh->bm, v_tri[j]); } } @@ -1220,17 +1384,26 @@ static void pbvh_bmesh_collapse_edge( /* Move v_conn to the midpoint of v_conn and v_del (if v_conn still exists, it * may have been deleted above) */ - if (!BLI_gset_haskey(deleted_verts, v_conn)) { + if (v_conn != NULL) { BM_log_vert_before_modified(bvh->bm_log, v_conn, eq_ctx->cd_vert_mask_offset); mid_v3_v3v3(v_conn->co, v_conn->co, v_del->co); add_v3_v3(v_conn->no, v_del->no); normalize_v3(v_conn->no); + + /* update boundboxes attached to the connected vertex + * note that we can often get-away without this but causes T48779 */ + BM_LOOPS_OF_VERT_ITER_BEGIN(l, v_conn) { + PBVHNode *f_node = pbvh_bmesh_node_from_face(bvh, l->f); + f_node->flag |= PBVH_UpdateDrawBuffers | PBVH_UpdateNormals | PBVH_UpdateBB; + } + BM_LOOPS_OF_VERT_ITER_END; } /* Delete v_del */ BLI_assert(!BM_vert_face_check(v_del)); - BLI_gset_insert(deleted_verts, v_del); BM_log_vert_removed(bvh->bm_log, v_del, eq_ctx->cd_vert_mask_offset); + /* v_conn == NULL is OK */ + BLI_ghash_insert(deleted_verts, v_del, v_conn); BM_vert_kill(bvh->bm, v_del); } @@ -1241,17 +1414,19 @@ static bool pbvh_bmesh_collapse_short_edges( { const float min_len_squared = bvh->bm_min_edge_len * bvh->bm_min_edge_len; bool any_collapsed = false; - GSet *deleted_verts = BLI_gset_ptr_new("deleted_verts"); + /* deleted verts point to vertices they were merged into, or NULL when removed. */ + GHash *deleted_verts = BLI_ghash_ptr_new("deleted_verts"); while (!BLI_heap_is_empty(eq_ctx->q->heap)) { BMVert **pair = BLI_heap_popmin(eq_ctx->q->heap); - BMVert *v1 = pair[0], *v2 = pair[1]; + BMVert *v1 = pair[0], *v2 = pair[1]; BLI_mempool_free(eq_ctx->pool, pair); pair = NULL; /* Check the verts still exist */ - if (BLI_gset_haskey(deleted_verts, v1) || - BLI_gset_haskey(deleted_verts, v2)) + if (!(v1 = bm_vert_hash_lookup_chain(deleted_verts, v1)) || + !(v2 = bm_vert_hash_lookup_chain(deleted_verts, v2)) || + (v1 == v2)) { continue; } @@ -1285,7 +1460,7 @@ static bool pbvh_bmesh_collapse_short_edges( deleted_faces, eq_ctx); } - BLI_gset_free(deleted_verts, NULL); + BLI_ghash_free(deleted_verts, NULL, NULL); return any_collapsed; } @@ -1406,18 +1581,23 @@ void pbvh_bmesh_normals_update(PBVHNode **nodes, int totnode) } } -typedef struct FastNodeBuildInfo { +struct FastNodeBuildInfo { int totface; /* number of faces */ int start; /* start of faces in array */ struct FastNodeBuildInfo *child1; struct FastNodeBuildInfo *child2; -} FastNodeBuildInfo; +}; -/* Recursively split the node if it exceeds the leaf_limit. This function is multithreadabe since each invocation applies - * to a sub part of the arrays */ -static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, MemArena *arena) +/** + * Recursively split the node if it exceeds the leaf_limit. + * This function is multithreadabe since each invocation applies + * to a sub part of the arrays + */ +static void pbvh_bmesh_node_limit_ensure_fast( + PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, struct FastNodeBuildInfo *node, + MemArena *arena) { - FastNodeBuildInfo *child1, *child2; + struct FastNodeBuildInfo *child1, *child2; if (node->totface <= bvh->leaf_limit) { return; @@ -1497,8 +1677,8 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC * each sequential part belonging to one node only */ BLI_assert((num_child1 + num_child2) == node->totface); - node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); - node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(FastNodeBuildInfo)); + node->child1 = child1 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo)); + node->child2 = child2 = BLI_memarena_alloc(arena, sizeof(struct FastNodeBuildInfo)); child1->totface = num_child1; child1->start = node->start; @@ -1510,7 +1690,9 @@ static void pbvh_bmesh_node_limit_ensure_fast(PBVH *bvh, BMFace **nodeinfo, BBC pbvh_bmesh_node_limit_ensure_fast(bvh, nodeinfo, bbc_array, child2, arena); } -static void pbvh_bmesh_create_nodes_fast_recursive(PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, FastNodeBuildInfo *node, int node_index) +static void pbvh_bmesh_create_nodes_fast_recursive( + PBVH *bvh, BMFace **nodeinfo, BBC *bbc_array, + struct FastNodeBuildInfo *node, int node_index) { PBVHNode *n = bvh->nodes + node_index; /* two cases, node does not have children or does have children */ @@ -1651,7 +1833,7 @@ void BKE_pbvh_build_bmesh( bm->elem_index_dirty |= BM_FACE; /* setup root node */ - FastNodeBuildInfo rootnode = {0}; + struct FastNodeBuildInfo rootnode = {0}; rootnode.totface = bm->totface; /* start recursion, assign faces to nodes accordingly */ @@ -1693,12 +1875,14 @@ bool BKE_pbvh_bmesh_update_topology( if (mode & PBVH_Collapse) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); - EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; + EdgeQueueContext eq_ctx = { + &q, queue_pool, bvh->bm, + cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, + }; short_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); - modified |= !BLI_heap_is_empty(q.heap); - pbvh_bmesh_collapse_short_edges(&eq_ctx, bvh, - &deleted_faces); + modified |= pbvh_bmesh_collapse_short_edges( + &eq_ctx, bvh, &deleted_faces); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } @@ -1706,15 +1890,18 @@ bool BKE_pbvh_bmesh_update_topology( if (mode & PBVH_Subdivide) { EdgeQueue q; BLI_mempool *queue_pool = BLI_mempool_create(sizeof(BMVert *[2]), 0, 128, BLI_MEMPOOL_NOP); - EdgeQueueContext eq_ctx = {&q, queue_pool, bvh->bm, cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset}; + EdgeQueueContext eq_ctx = { + &q, queue_pool, bvh->bm, + cd_vert_mask_offset, cd_vert_node_offset, cd_face_node_offset, + }; long_edge_queue_create(&eq_ctx, bvh, center, view_normal, radius); - modified |= !BLI_heap_is_empty(q.heap); - pbvh_bmesh_subdivide_long_edges(&eq_ctx, bvh, &edge_loops); + modified |= pbvh_bmesh_subdivide_long_edges( + &eq_ctx, bvh, &edge_loops); BLI_heap_free(q.heap, NULL); BLI_mempool_destroy(queue_pool); } - + /* Unmark nodes */ for (int n = 0; n < bvh->totnode; n++) { PBVHNode *node = &bvh->nodes[n]; @@ -1735,16 +1922,6 @@ bool BKE_pbvh_bmesh_update_topology( return modified; } -BLI_INLINE void bm_face_as_array_index_tri(BMFace *f, int r_index[3]) -{ - BMLoop *l = BM_FACE_FIRST_LOOP(f); - - BLI_assert(f->len == 3); - - r_index[0] = BM_elem_index_get(l->v); l = l->next; - r_index[1] = BM_elem_index_get(l->v); l = l->next; - r_index[2] = BM_elem_index_get(l->v); -} /* In order to perform operations on the original node coordinates * (currently just raycast), store the node's triangles and vertices. @@ -1858,8 +2035,8 @@ static void pbvh_bmesh_print(PBVH *bvh) BMFace *f; BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", - BM_elem_index_get(v), - pbvh_bmesh_node_lookup_index(bvh, f)); + BM_elem_index_get(f), + pbvh_bmesh_node_index_from_face(bvh, f)); } fprintf(stderr, "bm_vert_to_node:\n"); @@ -1867,7 +2044,7 @@ static void pbvh_bmesh_print(PBVH *bvh) BM_ITER_MESH(v, &iter, bvh->bm, BM_FACES_OF_MESH) { fprintf(stderr, " %d -> %d\n", BM_elem_index_get(v), - pbvh_bmesh_node_lookup_index(bvh, v)); + pbvh_bmesh_node_index_from_vert(bvh, v)); } for (int n = 0; n < bvh->totnode; n++) { @@ -1909,17 +2086,23 @@ static void pbvh_bmesh_verify(PBVH *bvh) { /* build list of faces & verts to lookup */ GSet *faces_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totface); - BMFace *f; BMIter iter; - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BLI_gset_insert(faces_all, f); + + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BLI_assert(BM_ELEM_CD_GET_INT(f, bvh->cd_face_node_offset) != DYNTOPO_NODE_NONE); + BLI_gset_insert(faces_all, f); + } } GSet *verts_all = BLI_gset_ptr_new_ex(__func__, bvh->bm->totvert); - BMVert *v; - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { - BLI_gset_insert(verts_all, v); + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) != DYNTOPO_NODE_NONE) { + BLI_gset_insert(verts_all, v); + } } } @@ -1936,76 +2119,83 @@ static void pbvh_bmesh_verify(PBVH *bvh) BLI_assert(totvert == BLI_gset_size(verts_all)); } - BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { - BMIter bm_iter; - BMVert *v; - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); + { + BMFace *f; + BM_ITER_MESH(f, &iter, bvh->bm, BM_FACES_OF_MESH) { + BMIter bm_iter; + BMVert *v; + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, f); - /* Check that the face's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the face's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the face's node knows it owns the face */ - BLI_assert(BLI_gset_haskey(n->bm_faces, f)); + /* Check that the face's node knows it owns the face */ + BLI_assert(BLI_gset_haskey(n->bm_faces, f)); - /* Check the face's vertices... */ - BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { - PBVHNode *nv; + /* Check the face's vertices... */ + BM_ITER_ELEM (v, &bm_iter, f, BM_VERTS_OF_FACE) { + PBVHNode *nv; - /* Check that the vertex is in the node */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ - BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex is in the node */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v) ^ + BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vertex has a node owner */ - nv = pbvh_bmesh_node_lookup(bvh, v); + /* Check that the vertex has a node owner */ + nv = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vertex's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); + /* Check that the vertex's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(nv->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(nv->bm_other_verts, v)); + } } } /* Check verts */ - BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { - /* vertex isn't tracked */ - if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { - continue; - } + { + BMVert *v; + BM_ITER_MESH(v, &iter, bvh->bm, BM_VERTS_OF_MESH) { + /* vertex isn't tracked */ + if (BM_ELEM_CD_GET_INT(v, bvh->cd_vert_node_offset) == DYNTOPO_NODE_NONE) { + continue; + } - PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); + PBVHNode *n = pbvh_bmesh_node_lookup(bvh, v); - /* Check that the vert's node is a leaf */ - BLI_assert(n->flag & PBVH_Leaf); + /* Check that the vert's node is a leaf */ + BLI_assert(n->flag & PBVH_Leaf); - /* Check that the vert's node knows it owns the vert */ - BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); + /* Check that the vert's node knows it owns the vert */ + BLI_assert(BLI_gset_haskey(n->bm_unique_verts, v)); - /* Check that the vertex isn't duplicated as an 'other' vert */ - BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); + /* Check that the vertex isn't duplicated as an 'other' vert */ + BLI_assert(!BLI_gset_haskey(n->bm_other_verts, v)); - /* Check that the vert's node also contains one of the vert's - * adjacent faces */ - bool found = false; - BMIter bm_iter; - BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { - if (pbvh_bmesh_node_lookup(bvh, f) == n) { - found = true; - break; + /* Check that the vert's node also contains one of the vert's + * adjacent faces */ + bool found = false; + BMIter bm_iter; + BMFace *f = NULL; + BM_ITER_ELEM (f, &bm_iter, v, BM_FACES_OF_VERT) { + if (pbvh_bmesh_node_lookup(bvh, f) == n) { + found = true; + break; + } } - } - BLI_assert(found); + BLI_assert(found || f == NULL); #if 1 - /* total freak stuff, check if node exists somewhere else */ - /* Slow */ - for (int i = 0; i < bvh->totnode; i++) { - PBVHNode *n_other = &bvh->nodes[i]; - if ((n != n_other) && (n_other->bm_unique_verts)) { - BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + /* total freak stuff, check if node exists somewhere else */ + /* Slow */ + for (int i = 0; i < bvh->totnode; i++) { + PBVHNode *n_other = &bvh->nodes[i]; + if ((n != n_other) && (n_other->bm_unique_verts)) { + BLI_assert(!BLI_gset_haskey(n_other->bm_unique_verts, v)); + } } - } #endif + } } #if 0 @@ -2049,7 +2239,8 @@ static void pbvh_bmesh_verify(PBVH *bvh) GSET_ITER (gs_iter, n->bm_other_verts) { BMVert *v = BLI_gsetIterator_getKey(&gs_iter); - BLI_assert(!BM_vert_face_check(v)); + /* this happens sometimes and seems harmless */ + // BLI_assert(!BM_vert_face_check(v)); BLI_assert(BLI_gset_haskey(verts_all, v)); } } diff --git a/source/blender/blenkernel/intern/pbvh_intern.h b/source/blender/blenkernel/intern/pbvh_intern.h index 4d2307c3e12..19d3b31bd31 100644 --- a/source/blender/blenkernel/intern/pbvh_intern.h +++ b/source/blender/blenkernel/intern/pbvh_intern.h @@ -83,12 +83,11 @@ struct PBVHNode { * array. The array is sized to match 'totprim', and each of * the face's corners gets an index into the vert_indices * array, in the same order as the corners in the original - * MFace. The fourth value should not be used if the original - * face is a triangle. + * MLoopTri. * * Used for leaf nodes in a mesh-based PBVH (not multires.) */ - const int (*face_vert_indices)[4]; + const int (*face_vert_indices)[3]; /* Indicates whether this node is a leaf or not; also used for * marking various updates that need to be applied. */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index f0ba63e35b4..e0a3e9743db 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -55,8 +55,6 @@ #include "PIL_time.h" -#include "WM_api.h" - #include "BKE_appdir.h" #include "BKE_anim.h" #include "BKE_cloth.h" @@ -2501,7 +2499,7 @@ static int ptcache_read_openvdb_stream(PTCacheID *pid, int cfra) #ifdef WITH_OPENVDB char filename[FILE_MAX * 2]; - /* save blend file before using disk pointcache */ + /* save blend file before using disk pointcache */ if (!G.relbase_valid && (pid->cache->flag & PTCACHE_EXTERNAL) == 0) return 0; diff --git a/source/blender/blenkernel/intern/sca.c b/source/blender/blenkernel/intern/sca.c index e90a39e8c0e..a468420f87d 100644 --- a/source/blender/blenkernel/intern/sca.c +++ b/source/blender/blenkernel/intern/sca.c @@ -653,77 +653,6 @@ void set_sca_new_poins(void) } } -void sca_remove_ob_poin(Object *obt, Object *ob) -{ - bSensor *sens; - bMessageSensor *ms; - bActuator *act; - bCameraActuator *ca; - bObjectActuator *oa; - bSceneActuator *sa; - bEditObjectActuator *eoa; - bPropertyActuator *pa; - bMessageActuator *ma; - bParentActuator *para; - bArmatureActuator *aa; - bSteeringActuator *sta; - - - sens= obt->sensors.first; - while (sens) { - switch (sens->type) { - case SENS_MESSAGE: - ms= sens->data; - if (ms->fromObject==ob) ms->fromObject= NULL; - } - sens= sens->next; - } - - act= obt->actuators.first; - while (act) { - switch (act->type) { - case ACT_CAMERA: - ca= act->data; - if (ca->ob==ob) ca->ob= NULL; - break; - case ACT_OBJECT: - oa= act->data; - if (oa->reference==ob) oa->reference= NULL; - break; - case ACT_PROPERTY: - pa= act->data; - if (pa->ob==ob) pa->ob= NULL; - break; - case ACT_SCENE: - sa= act->data; - if (sa->camera==ob) sa->camera= NULL; - break; - case ACT_EDIT_OBJECT: - eoa= act->data; - if (eoa->ob==ob) eoa->ob= NULL; - break; - case ACT_MESSAGE: - ma= act->data; - if (ma->toObject==ob) ma->toObject= NULL; - break; - case ACT_PARENT: - para = act->data; - if (para->ob==ob) para->ob = NULL; - break; - case ACT_ARMATURE: - aa = act->data; - if (aa->target == ob) aa->target = NULL; - if (aa->subtarget == ob) aa->subtarget = NULL; - break; - case ACT_STEERING: - sta = act->data; - if (sta->navmesh == ob) sta->navmesh = NULL; - if (sta->target == ob) sta->target = NULL; - } - act= act->next; - } -} - /* ******************** INTERFACE ******************* */ void sca_move_sensor(bSensor *sens_to_move, Object *ob, int move_up) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index a3393b6b9c0..11b60e1301d 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -150,7 +150,7 @@ static void remove_sequencer_fcurves(Scene *sce) } } -Scene *BKE_scene_copy(Scene *sce, int type) +Scene *BKE_scene_copy(Main *bmain, Scene *sce, int type) { Scene *scen; SceneRenderLayer *srl, *new_srl; @@ -161,7 +161,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (type == SCE_COPY_EMPTY) { ListBase rl, rv; /* XXX. main should become an arg */ - scen = BKE_scene_add(G.main, sce->id.name + 2); + scen = BKE_scene_add(bmain, sce->id.name + 2); rl = scen->r.layers; rv = scen->r.views; @@ -182,10 +182,10 @@ Scene *BKE_scene_copy(Scene *sce, int type) BKE_sound_destroy_scene(scen); } else { - scen = BKE_libblock_copy(&sce->id); + scen = BKE_libblock_copy(bmain, &sce->id); BLI_duplicatelist(&(scen->base), &(sce->base)); - BKE_main_id_clear_newpoins(G.main); + BKE_main_id_clear_newpoins(bmain); id_us_plus((ID *)scen->world); id_us_plus((ID *)scen->set); @@ -209,7 +209,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (sce->nodetree) { /* ID's are managed on both copy and switch */ - scen->nodetree = ntreeCopyTree(sce->nodetree); + scen->nodetree = ntreeCopyTree(bmain, sce->nodetree); ntreeSwitchID(scen->nodetree, &sce->id, &scen->id); } @@ -237,7 +237,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) for (lineset = new_srl->freestyleConfig.linesets.first; lineset; lineset = lineset->next) { if (lineset->linestyle) { id_us_plus((ID *)lineset->linestyle); - lineset->linestyle = BKE_linestyle_copy(G.main, lineset->linestyle); + lineset->linestyle = BKE_linestyle_copy(bmain, lineset->linestyle); } } } @@ -320,7 +320,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) if (type == SCE_COPY_FULL) { if (scen->world) { id_us_plus((ID *)scen->world); - scen->world = BKE_world_copy(scen->world); + scen->world = BKE_world_copy(bmain, scen->world); BKE_animdata_copy_id_action((ID *)scen->world); } @@ -334,7 +334,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) /* grease pencil */ if (scen->gpd) { if (type == SCE_COPY_FULL) { - scen->gpd = gpencil_data_duplicate(scen->gpd, false); + scen->gpd = gpencil_data_duplicate(bmain, scen->gpd, false); } else if (type == SCE_COPY_EMPTY) { scen->gpd = NULL; @@ -344,9 +344,7 @@ Scene *BKE_scene_copy(Scene *sce, int type) } } - if (sce->preview) { - scen->preview = BKE_previewimg_copy(sce->preview); - } + scen->preview = BKE_previewimg_copy(sce->preview); return scen; } @@ -357,41 +355,34 @@ void BKE_scene_groups_relink(Scene *sce) BKE_rigidbody_world_groups_relink(sce->rigidbody_world); } -/* do not free scene itself */ +/** Free (or release) any data used by this scene (does not free the scene itself). */ void BKE_scene_free(Scene *sce) { - Base *base; SceneRenderLayer *srl; + BKE_animdata_free((ID *)sce, false); + /* check all sequences */ BKE_sequencer_clear_scene_in_allseqs(G.main, sce); - base = sce->base.first; - while (base) { - id_us_min(&base->object->id); - base = base->next; - } - /* do not free objects! */ - - if (sce->gpd) { -#if 0 /* removed since this can be invalid memory when freeing everything */ - /* since the grease pencil data is freed before the scene. - * since grease pencil data is not (yet?), shared between objects - * its probably safe not to do this, some save and reload will free this. */ - id_us_min(&sce->gpd->id); -#endif - sce->gpd = NULL; - } - + sce->basact = NULL; BLI_freelistN(&sce->base); BKE_sequencer_editing_free(sce); - BKE_animdata_free((ID *)sce); BKE_keyingsets_free(&sce->keyingsets); - - if (sce->rigidbody_world) + + /* is no lib link block, but scene extension */ + if (sce->nodetree) { + ntreeFreeTree(sce->nodetree); + MEM_freeN(sce->nodetree); + sce->nodetree = NULL; + } + + if (sce->rigidbody_world) { BKE_rigidbody_free_world(sce->rigidbody_world); - + sce->rigidbody_world = NULL; + } + if (sce->r.avicodecdata) { free_avicodecdata(sce->r.avicodecdata); MEM_freeN(sce->r.avicodecdata); @@ -444,15 +435,8 @@ void BKE_scene_free(Scene *sce) if (sce->depsgraph) DEG_graph_free(sce->depsgraph); - if (sce->nodetree) { - ntreeFreeTree(sce->nodetree); - MEM_freeN(sce->nodetree); - } - - if (sce->stats) - MEM_freeN(sce->stats); - if (sce->fps_info) - MEM_freeN(sce->fps_info); + MEM_SAFE_FREE(sce->stats); + MEM_SAFE_FREE(sce->fps_info); BKE_sound_destroy_scene(sce); @@ -904,40 +888,6 @@ Scene *BKE_scene_set_name(Main *bmain, const char *name) return NULL; } -void BKE_scene_unlink(Main *bmain, Scene *sce, Scene *newsce) -{ - Scene *sce1; - bScreen *screen; - - /* check all sets */ - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) - if (sce1->set == sce) - sce1->set = NULL; - - for (sce1 = bmain->scene.first; sce1; sce1 = sce1->id.next) { - bNode *node; - - if (sce1 == sce || !sce1->nodetree) - continue; - - for (node = sce1->nodetree->nodes.first; node; node = node->next) { - if (node->id == &sce->id) - node->id = NULL; - } - } - - /* all screens */ - for (screen = bmain->screen.first; screen; screen = screen->id.next) { - if (screen->scene == sce) { - screen->scene = newsce; - } - - /* editors are handled by WM_main_remove_editor_id_reference */ - } - - BKE_libblock_free(bmain, sce); -} - /* Used by metaballs, return *all* objects (including duplis) existing in the scene (including scene's sets) */ int BKE_scene_base_iter_next(EvaluationContext *eval_ctx, SceneBaseIter *iter, Scene **scene, int val, Base **base, Object **ob) @@ -1173,7 +1123,7 @@ char *BKE_scene_find_last_marker_name(Scene *scene, int frame) Base *BKE_scene_base_add(Scene *sce, Object *ob) { - Base *b = MEM_callocN(sizeof(*b), "BKE_scene_base_add"); + Base *b = MEM_callocN(sizeof(*b), __func__); BLI_addhead(&sce->base, b); b->object = ob; @@ -1193,6 +1143,8 @@ void BKE_scene_base_unlink(Scene *sce, Base *base) BKE_rigidbody_remove_object(sce, base->object); BLI_remlink(&sce->base, base); + if (sce->basact == base) + sce->basact = NULL; } void BKE_scene_base_deselect_all(Scene *sce) diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 139c6670f74..857bd5447c8 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -273,17 +273,18 @@ void BKE_spacedata_draw_locks(int set) } } -static void (*spacedata_id_unref_cb)(struct SpaceLink *sl, const struct ID *id) = NULL; +static void (*spacedata_id_remap_cb)(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) = NULL; -void BKE_spacedata_callback_id_unref_set(void (*func)(struct SpaceLink *sl, const struct ID *)) +void BKE_spacedata_callback_id_remap_set(void (*func)(ScrArea *sa, SpaceLink *sl, ID *, ID *)) { - spacedata_id_unref_cb = func; + spacedata_id_remap_cb = func; } -void BKE_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id) +/* UNUSED!!! */ +void BKE_spacedata_id_unref(struct ScrArea *sa, struct SpaceLink *sl, struct ID *id) { - if (spacedata_id_unref_cb) { - spacedata_id_unref_cb(sl, id); + if (spacedata_id_remap_cb) { + spacedata_id_remap_cb(sa, sl, id, NULL); } } @@ -358,11 +359,13 @@ void BKE_screen_area_free(ScrArea *sa) BLI_freelistN(&sa->actionzones); } -/* don't free screen itself */ +/** Free (or release) any data used by this screen (does not free the screen itself). */ void BKE_screen_free(bScreen *sc) { ScrArea *sa, *san; ARegion *ar; + + /* No animdata here. */ for (ar = sc->regionbase.first; ar; ar = ar->next) BKE_area_region_free(NULL, ar); diff --git a/source/blender/blenkernel/intern/seqeffects.c b/source/blender/blenkernel/intern/seqeffects.c index 3de4a426973..ce7c520438a 100644 --- a/source/blender/blenkernel/intern/seqeffects.c +++ b/source/blender/blenkernel/intern/seqeffects.c @@ -123,28 +123,34 @@ static ImBuf *prepare_effect_imbufs(const SeqRenderData *context, ImBuf *ibuf1, out = IMB_allocImBuf(x, y, 32, IB_rect); } - if (ibuf1 && !ibuf1->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true); - } - if (ibuf2 && !ibuf2->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true); - } - if (ibuf3 && !ibuf3->rect_float && out->rect_float) { - BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true); - } + if (out->rect_float) { + if (ibuf1 && !ibuf1->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf1, true); + } + + if (ibuf2 && !ibuf2->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf2, true); + } + + if (ibuf3 && !ibuf3->rect_float) { + BKE_sequencer_imbuf_to_sequencer_space(scene, ibuf3, true); + } - if (ibuf1 && !ibuf1->rect && !out->rect_float) { - IMB_rect_from_float(ibuf1); - } - if (ibuf2 && !ibuf2->rect && !out->rect_float) { - IMB_rect_from_float(ibuf2); - } - if (ibuf3 && !ibuf3->rect && !out->rect_float) { - IMB_rect_from_float(ibuf3); + IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name); } + else { + if (ibuf1 && !ibuf1->rect) { + IMB_rect_from_float(ibuf1); + } - if (out->rect_float) - IMB_colormanagement_assign_float_colorspace(out, scene->sequencer_colorspace_settings.name); + if (ibuf2 && !ibuf2->rect) { + IMB_rect_from_float(ibuf2); + } + + if (ibuf3 && !ibuf3->rect) { + IMB_rect_from_float(ibuf3); + } + } /* If effect only affecting a single channel, forward input's metadata to the output. */ if (ibuf1 != NULL && ibuf1 == ibuf2 && ibuf2 == ibuf3) { diff --git a/source/blender/blenkernel/intern/sequencer.c b/source/blender/blenkernel/intern/sequencer.c index c82f3a3af23..2f497d807e4 100644 --- a/source/blender/blenkernel/intern/sequencer.c +++ b/source/blender/blenkernel/intern/sequencer.c @@ -1308,41 +1308,40 @@ StripElem *BKE_sequencer_give_stripelem(Sequence *seq, int cfra) static int evaluate_seq_frame_gen(Sequence **seq_arr, ListBase *seqbase, int cfra, int chanshown) { - Sequence *seq; - Sequence *effect_inputs[MAXSEQ + 1]; - int i, totseq = 0, num_effect_inputs = 0; + /* Use arbitrary sized linked list, the size could be over MAXSEQ. */ + LinkNodePair effect_inputs = {NULL, NULL}; + int totseq = 0; memset(seq_arr, 0, sizeof(Sequence *) * (MAXSEQ + 1)); - seq = seqbase->first; - while (seq) { - if (seq->startdisp <= cfra && seq->enddisp > cfra) { + for (Sequence *seq = seqbase->first; seq; seq = seq->next) { + if ((seq->startdisp <= cfra) && (seq->enddisp > cfra)) { if ((seq->type & SEQ_TYPE_EFFECT) && !(seq->flag & SEQ_MUTE)) { + if (seq->seq1) { - effect_inputs[num_effect_inputs++] = seq->seq1; + BLI_linklist_append_alloca(&effect_inputs, seq->seq1); } if (seq->seq2) { - effect_inputs[num_effect_inputs++] = seq->seq2; + BLI_linklist_append_alloca(&effect_inputs, seq->seq2); } if (seq->seq3) { - effect_inputs[num_effect_inputs++] = seq->seq3; + BLI_linklist_append_alloca(&effect_inputs, seq->seq3); } } seq_arr[seq->machine] = seq; totseq++; } - seq = seq->next; } /* Drop strips which are used for effect inputs, we don't want * them to blend into render stack in any other way than effect * string rendering. */ - for (i = 0; i < num_effect_inputs; i++) { - seq = effect_inputs[i]; + for (LinkNode *seq_item = effect_inputs.list; seq_item; seq_item = seq_item->next) { + Sequence *seq = seq_item->link; /* It's possible that effetc strip would be placed to the same * 'machine' as it's inputs. We don't want to clear such strips * from the stack. @@ -1826,8 +1825,10 @@ static void seq_proxy_build_frame( IMB_freeImBuf(ibuf); } -/* returns whether the file this context would read from even exist, if not, don't create the context -*/ +/** + * Returns whether the file this context would read from even exist, + * if not, don't create the context + */ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, const int view_id) { if ((scene->r.scemode & R_MULTIVIEW) == 0) @@ -1862,8 +1863,9 @@ static bool seq_proxy_multiview_context_invalid(Sequence *seq, Scene *scene, con return false; } -/** This returns the maximum possible number of required contexts -*/ +/** + * This returns the maximum possible number of required contexts + */ static int seq_proxy_context_count(Sequence *seq, Scene *scene) { int num_views = 1; @@ -3092,7 +3094,7 @@ static ImBuf *seq_render_mask(const SeqRenderData *context, Mask *mask, float nr BKE_maskrasterize_handle_init(mr_handle, mask_temp, context->rectx, context->recty, true, true, true); - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); BKE_maskrasterize_buffer(mr_handle, context->rectx, context->recty, maskbuf); @@ -5154,7 +5156,7 @@ Sequence *BKE_sequencer_add_sound_strip(bContext *C, ListBase *seqbasep, SeqLoad info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); #if 0 if (op) BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); diff --git a/source/blender/blenkernel/intern/shrinkwrap.c b/source/blender/blenkernel/intern/shrinkwrap.c index 518d8d68919..7094d5a3547 100644 --- a/source/blender/blenkernel/intern/shrinkwrap.c +++ b/source/blender/blenkernel/intern/shrinkwrap.c @@ -405,21 +405,28 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* use editmesh to avoid array allocation */ BMEditMesh *emtarget = NULL, *emaux = NULL; - BVHTreeFromEditMesh emtreedata_stack, emauxdata_stack; - BVHTreeFromMesh dmtreedata_stack, dmauxdata_stack; + union { + BVHTreeFromEditMesh emtreedata; + BVHTreeFromMesh dmtreedata; + } treedata_stack, auxdata_stack; + BVHTree *targ_tree; void *targ_callback; if (calc->smd->target && calc->target->type == DM_TYPE_EDITBMESH) { emtarget = BKE_editmesh_from_object(calc->smd->target); - if ((targ_tree = bvhtree_from_editmesh_looptri(&emtreedata_stack, emtarget, 0.0, 4, 6))) { - targ_callback = emtreedata_stack.raycast_callback; - treeData = &emtreedata_stack; + if ((targ_tree = bvhtree_from_editmesh_looptri( + &treedata_stack.emtreedata, emtarget, 0.0, 4, 6, &calc->target->bvhCache))) + { + targ_callback = treedata_stack.emtreedata.raycast_callback; + treeData = &treedata_stack.emtreedata; } } else { - if ((targ_tree = bvhtree_from_mesh_looptri(&dmtreedata_stack, calc->target, 0.0, 4, 6))) { - targ_callback = dmtreedata_stack.raycast_callback; - treeData = &dmtreedata_stack; + if ((targ_tree = bvhtree_from_mesh_looptri( + &treedata_stack.dmtreedata, calc->target, 0.0, 4, 6))) + { + targ_callback = treedata_stack.dmtreedata.raycast_callback; + treeData = &treedata_stack.dmtreedata; } } if (targ_tree) { @@ -429,15 +436,17 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* use editmesh to avoid array allocation */ if (calc->smd->auxTarget && auxMesh->type == DM_TYPE_EDITBMESH) { emaux = BKE_editmesh_from_object(calc->smd->auxTarget); - if ((aux_tree = bvhtree_from_editmesh_looptri(&emauxdata_stack, emaux, 0.0, 4, 6)) != NULL) { - aux_callback = emauxdata_stack.raycast_callback; - auxData = &emauxdata_stack; + if ((aux_tree = bvhtree_from_editmesh_looptri( + &auxdata_stack.emtreedata, emaux, 0.0, 4, 6, &auxMesh->bvhCache))) + { + aux_callback = auxdata_stack.emtreedata.raycast_callback; + auxData = &auxdata_stack.emtreedata; } } else { - if ((aux_tree = bvhtree_from_mesh_looptri(&dmauxdata_stack, auxMesh, 0.0, 4, 6)) != NULL) { - aux_callback = dmauxdata_stack.raycast_callback; - auxData = &dmauxdata_stack; + if ((aux_tree = bvhtree_from_mesh_looptri(&auxdata_stack.dmtreedata, auxMesh, 0.0, 4, 6)) != NULL) { + aux_callback = auxdata_stack.dmtreedata.raycast_callback; + auxData = &auxdata_stack.dmtreedata; } } } @@ -455,12 +464,21 @@ static void shrinkwrap_calc_normal_projection(ShrinkwrapCalcData *calc, bool for /* free data structures */ if (treeData) { - if (emtarget) free_bvhtree_from_editmesh(treeData); - else free_bvhtree_from_mesh(treeData); + if (emtarget) { + free_bvhtree_from_editmesh(treeData); + } + else { + free_bvhtree_from_mesh(treeData); + } } + if (auxData) { - if (emaux) free_bvhtree_from_editmesh(auxData); - else free_bvhtree_from_mesh(auxData); + if (emaux) { + free_bvhtree_from_editmesh(auxData); + } + else { + free_bvhtree_from_mesh(auxData); + } } } diff --git a/source/blender/blenkernel/intern/softbody.c b/source/blender/blenkernel/intern/softbody.c index 940dbc5de65..d1c7b240b94 100644 --- a/source/blender/blenkernel/intern/softbody.c +++ b/source/blender/blenkernel/intern/softbody.c @@ -2243,7 +2243,7 @@ static void softbody_calc_forces(Scene *scene, Object *ob, float forcetime, floa .. keeping G.debug_value==17 0x11 option for old files 'needing' the bug*/ /* rule we never alter free variables :bp->vec bp->pos in here ! - * this will ruin adaptive stepsize AKA heun! (BM) + * this will ruin adaptive stepsize AKA heun! (BM) */ SoftBody *sb= ob->soft; /* is supposed to be there */ BodyPoint *bp; diff --git a/source/blender/blenkernel/intern/sound.c b/source/blender/blenkernel/intern/sound.c index b016f8a49ed..414be73e234 100644 --- a/source/blender/blenkernel/intern/sound.c +++ b/source/blender/blenkernel/intern/sound.c @@ -123,8 +123,11 @@ bSound *BKE_sound_new_file_exists(struct Main *bmain, const char *filepath) return BKE_sound_new_file_exists_ex(bmain, filepath, NULL); } +/** Free (or release) any data used by this sound (does not free the sound itself). */ void BKE_sound_free(bSound *sound) { + /* No animdata here. */ + if (sound->packedfile) { freePackedFile(sound->packedfile); sound->packedfile = NULL; @@ -148,8 +151,7 @@ void BKE_sound_free(bSound *sound) BLI_spin_end(sound->spinlock); MEM_freeN(sound->spinlock); sound->spinlock = NULL; - } - + } #endif /* WITH_AUDASPACE */ } @@ -315,15 +317,6 @@ bSound *BKE_sound_new_limiter(struct Main *bmain, bSound *source, float start, f } #endif -void BKE_sound_delete(struct Main *bmain, bSound *sound) -{ - if (sound) { - BKE_sound_free(sound); - - BKE_libblock_free(bmain, sound); - } -} - void BKE_sound_cache(bSound *sound) { sound->flags |= SOUND_FLAGS_CACHING; diff --git a/source/blender/blenkernel/intern/speaker.c b/source/blender/blenkernel/intern/speaker.c index c452065fbad..c027f3b38ca 100644 --- a/source/blender/blenkernel/intern/speaker.c +++ b/source/blender/blenkernel/intern/speaker.c @@ -34,6 +34,8 @@ #include "BKE_animsys.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_speaker.h" @@ -66,83 +68,54 @@ void *BKE_speaker_add(Main *bmain, const char *name) return spk; } -Speaker *BKE_speaker_copy(Speaker *spk) +Speaker *BKE_speaker_copy(Main *bmain, Speaker *spk) { Speaker *spkn; - spkn = BKE_libblock_copy(&spk->id); + spkn = BKE_libblock_copy(bmain, &spk->id); + if (spkn->sound) id_us_plus(&spkn->sound->id); - if (spk->id.lib) { + if (ID_IS_LINKED_DATABLOCK(spk)) { + BKE_id_expand_local(&spkn->id); BKE_id_lib_local_paths(G.main, spk->id.lib, &spkn->id); } return spkn; } -static void extern_local_speaker(Speaker *spk) +void BKE_speaker_make_local(Main *bmain, Speaker *spk, const bool force_local) { - id_lib_extern((ID *)spk->sound); -} - -void BKE_speaker_make_local(Speaker *spk) -{ - Main *bmain = G.main; - Object *ob; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - if (spk->id.lib == NULL) return; - if (spk->id.us == 1) { - id_clear_lib_data(bmain, &spk->id); - extern_local_speaker(spk); + if (!ID_IS_LINKED_DATABLOCK(spk)) { return; } - ob = bmain->object.first; - while (ob) { - if (ob->data == spk) { - if (ob->id.lib) is_lib = true; - else is_local = true; + BKE_library_ID_test_usages(bmain, spk, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &spk->id); + BKE_id_expand_local(&spk->id); } - ob = ob->id.next; - } + else { + Speaker *spk_new = BKE_speaker_copy(bmain, spk); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &spk->id); - extern_local_speaker(spk); - } - else if (is_local && is_lib) { - Speaker *spk_new = BKE_speaker_copy(spk); - spk_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, spk->id.lib, &spk_new->id); - - ob = bmain->object.first; - while (ob) { - if (ob->data == spk) { - - if (ob->id.lib == NULL) { - ob->data = spk_new; - id_us_plus(&spk_new->id); - id_us_min(&spk->id); - } - } - ob = ob->id.next; + spk_new->id.us = 0; + + BKE_libblock_remap(bmain, spk, spk_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } void BKE_speaker_free(Speaker *spk) { - if (spk->sound) - id_us_min(&spk->sound->id); - - BKE_animdata_free((ID *)spk); + BKE_animdata_free((ID *)spk, false); } diff --git a/source/blender/blenkernel/intern/subsurf_ccg.c b/source/blender/blenkernel/intern/subsurf_ccg.c index b0d19320230..f73dbd8078f 100644 --- a/source/blender/blenkernel/intern/subsurf_ccg.c +++ b/source/blender/blenkernel/intern/subsurf_ccg.c @@ -3472,7 +3472,7 @@ static void ccgDM_drawFacesTex_common(DerivedMesh *dm, if (!flush && compareDrawOptions) { /* also compare draw options and flush buffer if they're different - * need for face selection highlight in edit mode */ + * need for face selection highlight in edit mode */ flush |= compareDrawOptions(userData, actualFace, next_actualFace) == 0; } diff --git a/source/blender/blenkernel/intern/text.c b/source/blender/blenkernel/intern/text.c index 6def9e3e503..269d6d32b31 100644 --- a/source/blender/blenkernel/intern/text.c +++ b/source/blender/blenkernel/intern/text.c @@ -171,14 +171,17 @@ void BKE_text_free_lines(Text *text) text->curl = text->sell = NULL; } +/** Free (or release) any data used by this text (does not free the text itself). */ void BKE_text_free(Text *text) { + /* No animdata here. */ + BKE_text_free_lines(text); - if (text->name) MEM_freeN(text->name); - MEM_freeN(text->undo_buf); + MEM_SAFE_FREE(text->name); + MEM_SAFE_FREE(text->undo_buf); #ifdef WITH_PYTHON - if (text->compiled) BPY_text_free_code(text); + BPY_text_free_code(text); #endif } @@ -449,7 +452,7 @@ Text *BKE_text_copy(Main *bmain, Text *ta) Text *tan; TextLine *line, *tmp; - tan = BKE_libblock_copy(&ta->id); + tan = BKE_libblock_copy(bmain, &ta->id); /* file name can be NULL */ if (ta->name) { @@ -488,198 +491,14 @@ Text *BKE_text_copy(Main *bmain, Text *ta) init_undo_text(tan); - if (ta->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ta)) { + BKE_id_expand_local(&tan->id); BKE_id_lib_local_paths(bmain, ta->id.lib, &tan->id); } return tan; } -void BKE_text_unlink(Main *bmain, Text *text) -{ - bScreen *scr; - ScrArea *area; - SpaceLink *sl; - Object *ob; - bController *cont; - bActuator *act; - bConstraint *con; - bNodeTree *ntree; - bNode *node; - Material *mat; - Lamp *la; - Tex *te; - World *wo; - FreestyleLineStyle *linestyle; - Scene *sce; - SceneRenderLayer *srl; - FreestyleModuleConfig *module; - bool update; - - for (ob = bmain->object.first; ob; ob = ob->id.next) { - /* game controllers */ - for (cont = ob->controllers.first; cont; cont = cont->next) { - if (cont->type == CONT_PYTHON) { - bPythonCont *pc; - - pc = cont->data; - if (pc->text == text) pc->text = NULL; - } - } - /* game actuators */ - for (act = ob->actuators.first; act; act = act->next) { - if (act->type == ACT_2DFILTER) { - bTwoDFilterActuator *tfa; - - tfa = act->data; - if (tfa->text == text) tfa->text = NULL; - } - } - - /* pyconstraints */ - update = 0; - - if (ob->type == OB_ARMATURE && ob->pose) { - bPoseChannel *pchan; - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - for (con = pchan->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - - } - } - } - } - - for (con = ob->constraints.first; con; con = con->next) { - if (con->type == CONSTRAINT_TYPE_PYTHON) { - bPythonConstraint *data = con->data; - if (data->text == text) data->text = NULL; - update = 1; - } - } - - if (update) - DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - } - - /* nodes */ - for (la = bmain->lamp.first; la; la = la->id.next) { - ntree = la->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (linestyle = bmain->linestyle.first; linestyle; linestyle = linestyle->id.next) { - ntree = linestyle->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (mat = bmain->mat.first; mat; mat = mat->id.next) { - ntree = mat->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (te = bmain->tex.first; te; te = te->id.next) { - ntree = te->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (wo = bmain->world.first; wo; wo = wo->id.next) { - ntree = wo->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - ntree = sce->nodetree; - if (!ntree) - continue; - for (node = ntree->nodes.first; node; node = node->next) { - if (node->type == NODE_FRAME) { - Text *ntext = (Text *)node->id; - if (ntext == text) node->id = NULL; - } - } - - /* Freestyle (while looping over the scene) */ - for (srl = sce->r.layers.first; srl; srl = srl->next) { - for (module = srl->freestyleConfig.modules.first; module; module = module->next) { - if (module->script == text) - module->script = NULL; - } - } - } - - for (ntree = bmain->nodetree.first; ntree; ntree = ntree->id.next) { - for (node = ntree->nodes.first; node; node = node->next) { - if (ELEM(node->type, SH_NODE_SCRIPT, NODE_FRAME)) { - if ((Text *)node->id == text) { - node->id = NULL; - } - } - } - } - - /* text space */ - for (scr = bmain->screen.first; scr; scr = scr->id.next) { - for (area = scr->areabase.first; area; area = area->next) { - for (sl = area->spacedata.first; sl; sl = sl->next) { - if (sl->spacetype == SPACE_TEXT) { - SpaceText *st = (SpaceText *) sl; - - if (st->text == text) { - st->text = NULL; - st->top = 0; - } - } - } - } - } - - text->id.us = 0; -} - void BKE_text_clear(Text *text) /* called directly from rna */ { int oldstate; diff --git a/source/blender/blenkernel/intern/texture.c b/source/blender/blenkernel/intern/texture.c index b6ce24de682..684ed7d3ab4 100644 --- a/source/blender/blenkernel/intern/texture.c +++ b/source/blender/blenkernel/intern/texture.c @@ -59,6 +59,8 @@ #include "BKE_main.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_image.h" #include "BKE_material.h" #include "BKE_texture.h" @@ -560,23 +562,38 @@ int colorband_element_remove(struct ColorBand *coba, int index) /* ******************* TEX ************************ */ +/** Free (or release) any data used by this texture (does not free the texure itself). */ void BKE_texture_free(Tex *tex) { - if (tex->coba) MEM_freeN(tex->coba); - if (tex->env) BKE_texture_envmap_free(tex->env); - if (tex->pd) BKE_texture_pointdensity_free(tex->pd); - if (tex->vd) BKE_texture_voxeldata_free(tex->vd); - if (tex->ot) BKE_texture_ocean_free(tex->ot); - BKE_animdata_free((struct ID *)tex); - - BKE_previewimg_free(&tex->preview); - BKE_icon_id_delete((struct ID *)tex); - tex->id.icon_id = 0; - + BKE_animdata_free((ID *)tex, false); + + /* is no lib link block, but texture extension */ if (tex->nodetree) { ntreeFreeTree(tex->nodetree); MEM_freeN(tex->nodetree); + tex->nodetree = NULL; } + + MEM_SAFE_FREE(tex->coba); + if (tex->env) { + BKE_texture_envmap_free(tex->env); + tex->env = NULL; + } + if (tex->pd) { + BKE_texture_pointdensity_free(tex->pd); + tex->pd = NULL; + } + if (tex->vd) { + BKE_texture_voxeldata_free(tex->vd); + tex->vd = NULL; + } + if (tex->ot) { + BKE_texture_ocean_free(tex->ot); + tex->ot = NULL; + } + + BKE_icon_id_delete((ID *)tex); + BKE_previewimg_free(&tex->preview); } /* ------------------------------------------------------------------------- */ @@ -832,11 +849,11 @@ MTex *BKE_texture_mtex_add_id(ID *id, int slot) /* ------------------------------------------------------------------------- */ -Tex *BKE_texture_copy(Tex *tex) +Tex *BKE_texture_copy(Main *bmain, Tex *tex) { Tex *texn; - texn = BKE_libblock_copy(&tex->id); + texn = BKE_libblock_copy(bmain, &tex->id); if (BKE_texture_is_image_user(tex)) { id_us_plus((ID *)texn->ima); } @@ -855,11 +872,14 @@ Tex *BKE_texture_copy(Tex *tex) if (tex->nodetree->execdata) { ntreeTexEndExecTree(tex->nodetree->execdata); } - texn->nodetree = ntreeCopyTree(tex->nodetree); + texn->nodetree = ntreeCopyTree(bmain, tex->nodetree); } - if (tex->id.lib) { - BKE_id_lib_local_paths(G.main, tex->id.lib, &texn->id); + texn->preview = BKE_previewimg_copy(tex->preview); + + if (ID_IS_LINKED_DATABLOCK(tex)) { + BKE_id_expand_local(&texn->id); + BKE_id_lib_local_paths(bmain, tex->id.lib, &texn->id); } return texn; @@ -901,193 +921,32 @@ Tex *BKE_texture_localize(Tex *tex) /* ------------------------------------------------------------------------- */ -static void extern_local_texture(Tex *tex) -{ - id_lib_extern((ID *)tex->ima); -} - -void BKE_texture_make_local(Tex *tex) +void BKE_texture_make_local(Main *bmain, Tex *tex, const bool force_local) { - Main *bmain = G.main; - Material *ma; - World *wrld; - Lamp *la; - Brush *br; - ParticleSettings *pa; - FreestyleLineStyle *ls; - int a; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (tex->id.lib == NULL) return; - if (tex->id.us == 1) { - id_clear_lib_data(bmain, &tex->id); - extern_local_texture(tex); + if (!ID_IS_LINKED_DATABLOCK(tex)) { return; } - - ma = bmain->mat.first; - while (ma) { - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex == tex) { - if (ma->id.lib) is_lib = true; - else is_local = true; - } - } - ma = ma->id.next; - } - la = bmain->lamp.first; - while (la) { - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex == tex) { - if (la->id.lib) is_lib = true; - else is_local = true; - } - } - la = la->id.next; - } - wrld = bmain->world.first; - while (wrld) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) { - if (wrld->id.lib) is_lib = true; - else is_local = true; - } - } - wrld = wrld->id.next; - } - br = bmain->brush.first; - while (br) { - if (br->mtex.tex == tex) { - if (br->id.lib) is_lib = true; - else is_local = true; - } - if (br->mask_mtex.tex == tex) { - if (br->id.lib) is_lib = true; - else is_local = true; - } - br = br->id.next; - } - pa = bmain->particle.first; - while (pa) { - for (a = 0; a < MAX_MTEX; a++) { - if (pa->mtex[a] && pa->mtex[a]->tex == tex) { - if (pa->id.lib) is_lib = true; - else is_local = true; - } - } - pa = pa->id.next; - } - ls = bmain->linestyle.first; - while (ls) { - for (a = 0; a < MAX_MTEX; a++) { - if (ls->mtex[a] && ls->mtex[a]->tex == tex) { - if (ls->id.lib) is_lib = true; - else is_local = true; - } - } - ls = ls->id.next; - } - - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &tex->id); - extern_local_texture(tex); - } - else if (is_local && is_lib) { - Tex *tex_new = BKE_texture_copy(tex); - tex_new->id.us = 0; + BKE_library_ID_test_usages(bmain, tex, &is_local, &is_lib); - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, tex->id.lib, &tex_new->id); - - ma = bmain->mat.first; - while (ma) { - for (a = 0; a < MAX_MTEX; a++) { - if (ma->mtex[a] && ma->mtex[a]->tex == tex) { - if (ma->id.lib == NULL) { - ma->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - ma = ma->id.next; - } - la = bmain->lamp.first; - while (la) { - for (a = 0; a < MAX_MTEX; a++) { - if (la->mtex[a] && la->mtex[a]->tex == tex) { - if (la->id.lib == NULL) { - la->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - la = la->id.next; - } - wrld = bmain->world.first; - while (wrld) { - for (a = 0; a < MAX_MTEX; a++) { - if (wrld->mtex[a] && wrld->mtex[a]->tex == tex) { - if (wrld->id.lib == NULL) { - wrld->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - wrld = wrld->id.next; - } - br = bmain->brush.first; - while (br) { - if (br->mtex.tex == tex) { - if (br->id.lib == NULL) { - br->mtex.tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - if (br->mask_mtex.tex == tex) { - if (br->id.lib == NULL) { - br->mask_mtex.tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - br = br->id.next; + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &tex->id); + BKE_id_expand_local(&tex->id); } - pa = bmain->particle.first; - while (pa) { - for (a = 0; a < MAX_MTEX; a++) { - if (pa->mtex[a] && pa->mtex[a]->tex == tex) { - if (pa->id.lib == NULL) { - pa->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - pa = pa->id.next; - } - ls = bmain->linestyle.first; - while (ls) { - for (a = 0; a < MAX_MTEX; a++) { - if (ls->mtex[a] && ls->mtex[a]->tex == tex) { - if (ls->id.lib == NULL) { - ls->mtex[a]->tex = tex_new; - id_us_plus(&tex_new->id); - id_us_min(&tex->id); - } - } - } - ls = ls->id.next; + else { + Tex *tex_new = BKE_texture_copy(bmain, tex); + + tex_new->id.us = 0; + + BKE_libblock_remap(bmain, tex, tex_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenkernel/intern/world.c b/source/blender/blenkernel/intern/world.c index 17a2e7f14fd..277aeaa7e42 100644 --- a/source/blender/blenkernel/intern/world.c +++ b/source/blender/blenkernel/intern/world.c @@ -46,44 +46,36 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_world.h" #include "GPU_material.h" -void BKE_world_free_ex(World *wrld, bool do_id_user) +/** Free (or release) any data used by this world (does not free the world itself). */ +void BKE_world_free(World *wrld) { - MTex *mtex; int a; - + + BKE_animdata_free((ID *)wrld, false); + for (a = 0; a < MAX_MTEX; a++) { - mtex = wrld->mtex[a]; - if (do_id_user && mtex && mtex->tex) - id_us_min(&mtex->tex->id); - if (mtex) - MEM_freeN(mtex); + MEM_SAFE_FREE(wrld->mtex[a]); } - BKE_previewimg_free(&wrld->preview); - - BKE_animdata_free((ID *)wrld); /* is no lib link block, but world extension */ if (wrld->nodetree) { - ntreeFreeTree_ex(wrld->nodetree, do_id_user); + ntreeFreeTree(wrld->nodetree); MEM_freeN(wrld->nodetree); + wrld->nodetree = NULL; } - if (wrld->gpumaterial.first) - GPU_material_free(&wrld->gpumaterial); + GPU_material_free(&wrld->gpumaterial); BKE_icon_id_delete((struct ID *)wrld); - wrld->id.icon_id = 0; -} - -void BKE_world_free(World *wrld) -{ - BKE_world_free_ex(wrld, true); + BKE_previewimg_free(&wrld->preview); } void BKE_world_init(World *wrld) @@ -127,12 +119,12 @@ World *add_world(Main *bmain, const char *name) return wrld; } -World *BKE_world_copy(World *wrld) +World *BKE_world_copy(Main *bmain, World *wrld) { World *wrldn; int a; - wrldn = BKE_libblock_copy(&wrld->id); + wrldn = BKE_libblock_copy(bmain, &wrld->id); for (a = 0; a < MAX_MTEX; a++) { if (wrld->mtex[a]) { @@ -143,16 +135,16 @@ World *BKE_world_copy(World *wrld) } if (wrld->nodetree) { - wrldn->nodetree = ntreeCopyTree(wrld->nodetree); + wrldn->nodetree = ntreeCopyTree(bmain, wrld->nodetree); } - if (wrld->preview) - wrldn->preview = BKE_previewimg_copy(wrld->preview); + wrldn->preview = BKE_previewimg_copy(wrld->preview); BLI_listbase_clear(&wrldn->gpumaterial); - if (wrld->id.lib) { - BKE_id_lib_local_paths(G.main, wrld->id.lib, &wrldn->id); + if (ID_IS_LINKED_DATABLOCK(wrld)) { + BKE_id_expand_local(&wrldn->id); + BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrldn->id); } return wrldn; @@ -184,48 +176,32 @@ World *localize_world(World *wrld) return wrldn; } -void BKE_world_make_local(World *wrld) +void BKE_world_make_local(Main *bmain, World *wrld, const bool force_local) { - Main *bmain = G.main; - Scene *sce; bool is_local = false, is_lib = false; - /* - only lib users: do nothing + /* - only lib users: do nothing (unless force_local is set) * - only local users: set flag * - mixed: make copy */ - - if (wrld->id.lib == NULL) return; - if (wrld->id.us == 1) { - id_clear_lib_data(bmain, &wrld->id); + + if (!ID_IS_LINKED_DATABLOCK(wrld)) { return; } - - for (sce = bmain->scene.first; sce && ELEM(false, is_lib, is_local); sce = sce->id.next) { - if (sce->world == wrld) { - if (sce->id.lib) is_lib = true; - else is_local = true; + + BKE_library_ID_test_usages(bmain, wrld, &is_local, &is_lib); + + if (force_local || is_local) { + if (!is_lib) { + id_clear_lib_data(bmain, &wrld->id); + BKE_id_expand_local(&wrld->id); } - } + else { + World *wrld_new = BKE_world_copy(bmain, wrld); - if (is_local && is_lib == false) { - id_clear_lib_data(bmain, &wrld->id); - } - else if (is_local && is_lib) { - World *wrld_new = BKE_world_copy(wrld); - wrld_new->id.us = 0; - - /* Remap paths of new ID using old library as base. */ - BKE_id_lib_local_paths(bmain, wrld->id.lib, &wrld_new->id); - - for (sce = bmain->scene.first; sce; sce = sce->id.next) { - if (sce->world == wrld) { - if (sce->id.lib == NULL) { - sce->world = wrld_new; - id_us_plus(&wrld_new->id); - id_us_min(&wrld->id); - } - } + wrld_new->id.us = 0; + + BKE_libblock_remap(bmain, wrld, wrld_new, ID_REMAP_SKIP_INDIRECT_USAGE); } } } diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index 5ef8421c003..a46c87cec40 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -48,6 +48,10 @@ int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_strid #define BLI_array_findindex(arr, arr_len, p) \ _bli_array_findindex(arr, arr_len, sizeof(*(arr)), p) +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p); +#define BLI_array_rfindindex(arr, arr_len, p) \ + _bli_array_rfindindex(arr, arr_len, sizeof(*(arr)), p) + void _bli_array_binary_and( void *arr, const void *arr_a, const void *arr_b, unsigned int arr_len, size_t arr_stride); diff --git a/source/blender/blenlib/BLI_kdopbvh.h b/source/blender/blenlib/BLI_kdopbvh.h index fb8c2520e67..91d39801645 100644 --- a/source/blender/blenlib/BLI_kdopbvh.h +++ b/source/blender/blenlib/BLI_kdopbvh.h @@ -96,7 +96,8 @@ typedef void (*BVHTree_NearestPointCallback)(void *userdata, int index, const fl typedef void (*BVHTree_RayCastCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeRayHit *hit); /* callback must update nearest in case it finds a nearest result */ -typedef void (*BVHTree_NearestToRayCallback)(void *userdata, int index, const BVHTreeRay *ray, BVHTreeNearest *nearest); +typedef void (*BVHTree_NearestToRayCallback)(void *userdata, const float ray_co[3], const float ray_dir[3], + const float scale[3], int index, BVHTreeNearest *nearest); /* callback to check if 2 nodes overlap (use thread if intersection results need to be stored) */ typedef bool (*BVHTree_OverlapCallback)(void *userdata, int index_a, int index_b, int thread); @@ -142,8 +143,16 @@ int BLI_bvhtree_find_nearest( BVHTree *tree, const float co[3], BVHTreeNearest *nearest, BVHTree_NearestPointCallback callback, void *userdata); +int BLI_bvhtree_find_nearest_to_ray_angle( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, + BVHTree_NearestToRayCallback callback, void *userdata); + int BLI_bvhtree_find_nearest_to_ray( - BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest, + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, BVHTree_NearestToRayCallback callback, void *userdata); int BLI_bvhtree_ray_cast_ex( diff --git a/source/blender/blenlib/BLI_math_geom.h b/source/blender/blenlib/BLI_math_geom.h index 54b824c91ac..84a25f533bf 100644 --- a/source/blender/blenlib/BLI_math_geom.h +++ b/source/blender/blenlib/BLI_math_geom.h @@ -115,6 +115,13 @@ float dist_signed_squared_to_corner_v3v3v3( const float p[3], const float v1[3], const float v2[3], const float v3[3], const float axis_ref[3]); +float dist_squared_to_ray_v3( + const float ray_origin[3], const float ray_direction[3], + const float co[3], float *r_depth); +float dist_squared_ray_to_seg_v3( + const float ray_origin[3], const float ray_direction[3], + const float v0[3], const float v1[3], + float r_point[3], float *r_depth); float closest_to_line_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); float closest_to_line_v3(float r_close[3], const float p[3], const float l1[3], const float l2[3]); void closest_to_line_segment_v2(float r_close[2], const float p[2], const float l1[2], const float l2[2]); diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index 6d6fbe4e7af..8124e07dd47 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -138,10 +138,14 @@ bool invert_m3_m3(float R[3][3], float A[3][3]); bool invert_m4(float R[4][4]); bool invert_m4_m4(float R[4][4], float A[4][4]); -/* double ariphmetics */ +/* double arithmetic (mixed float/double) */ void mul_m4_v4d(float M[4][4], double r[4]); void mul_v4d_m4v4d(double r[4], float M[4][4], double v[4]); +/* double matrix functions (no mixing types) */ +void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]); +void mul_m3_v3_db(double M[3][3], double r[3]); + /****************************** Linear Algebra *******************************/ @@ -269,7 +273,7 @@ void BLI_space_transform_invert_normal(const struct SpaceTransform *data, float /*********************************** Other ***********************************/ void print_m3(const char *str, float M[3][3]); -void print_m4(const char *str, float M[3][4]); +void print_m4(const char *str, float M[4][4]); #define print_m3_id(M) print_m3(STRINGIFY(M), M) #define print_m4_id(M) print_m4(STRINGIFY(M), M) diff --git a/source/blender/blenlib/BLI_math_vector.h b/source/blender/blenlib/BLI_math_vector.h index 25f485a25aa..d15fe1a95dc 100644 --- a/source/blender/blenlib/BLI_math_vector.h +++ b/source/blender/blenlib/BLI_math_vector.h @@ -148,6 +148,7 @@ MINLINE void negate_v4(float r[4]); MINLINE void negate_v4_v4(float r[4], const float a[3]); MINLINE void negate_v3_short(short r[3]); +MINLINE void negate_v3_db(double r[3]); MINLINE void invert_v2(float r[2]); @@ -190,6 +191,12 @@ MINLINE float len_manhattan_v3v3(const float a[3], const float b[3]) ATTR_WARN_U MINLINE float len_v3(const float a[3]) ATTR_WARN_UNUSED_RESULT; MINLINE float len_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT; +MINLINE float normalize_v2_length(float r[2], const float unit_scale); +MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_scale); +MINLINE float normalize_v3_length(float r[3], const float unit_scale); +MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_scale); +MINLINE double normalize_v3_length_d(double n[3], const double unit_scale); + MINLINE float normalize_v2(float r[2]); MINLINE float normalize_v2_v2(float r[2], const float a[2]); MINLINE float normalize_v3(float r[3]); @@ -214,6 +221,10 @@ bool interp_v2_v2v2_slerp(float target[2], const float a[2], const float b[2], c void interp_v3_v3v3_slerp_safe(float target[3], const float a[3], const float b[3], const float t); void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[2], const float t); +void interp_v2_v2v2v2v2_cubic( + float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const float u); + void interp_v3_v3v3_char(char target[3], const char a[3], const char b[3], const float t); void interp_v3_v3v3_uchar(unsigned char target[3], const unsigned char a[3], const unsigned char b[3], const float t); void interp_v4_v4v4_char(char target[4], const char a[4], const char b[4], const float t); @@ -231,6 +242,7 @@ void flip_v4_v4v4(float v[4], const float v1[4], const float v2[4]); void flip_v3_v3v3(float v[3], const float v1[3], const float v2[3]); void flip_v2_v2v2(float v[2], const float v1[2], const float v2[2]); + /********************************* Comparison ********************************/ MINLINE bool is_zero_v2(const float a[3]) ATTR_WARN_UNUSED_RESULT; diff --git a/source/blender/blenlib/BLI_quadric.h b/source/blender/blenlib/BLI_quadric.h index eaf9c7a0738..d46a221d108 100644 --- a/source/blender/blenlib/BLI_quadric.h +++ b/source/blender/blenlib/BLI_quadric.h @@ -39,8 +39,7 @@ typedef struct Quadric { /* conversion */ void BLI_quadric_from_plane(Quadric *q, const double v[4]); -void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]); -void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]); +void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]); void BLI_quadric_clear(Quadric *q); @@ -50,7 +49,7 @@ void BLI_quadric_add_qu_ququ(Quadric *r, const Quadric *a, const Quadric *b); void BLI_quadric_mul(Quadric *a, const double scalar); /* solve */ -double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]); -bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon); +double BLI_quadric_evaluate(const Quadric *q, const double v[3]); +bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon); #endif /* __BLI_QUADRIC_H__ */ diff --git a/source/blender/blenlib/BLI_threads.h b/source/blender/blenlib/BLI_threads.h index b4a465bbc74..0b1b4d8ee8c 100644 --- a/source/blender/blenlib/BLI_threads.h +++ b/source/blender/blenlib/BLI_threads.h @@ -42,7 +42,7 @@ extern "C" { #endif /* for tables, button in UI, etc */ -#define BLENDER_MAX_THREADS 64 +#define BLENDER_MAX_THREADS 1024 struct ListBase; struct TaskScheduler; diff --git a/source/blender/blenlib/intern/BLI_filelist.c b/source/blender/blenlib/intern/BLI_filelist.c index 527d9934797..76de52bda66 100644 --- a/source/blender/blenlib/intern/BLI_filelist.c +++ b/source/blender/blenlib/intern/BLI_filelist.c @@ -352,8 +352,6 @@ void BLI_filelist_entry_datetime_to_string( /** * Deep-duplicate of a single direntry. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *src) { @@ -368,8 +366,6 @@ void BLI_filelist_entry_duplicate(struct direntry *dst, const struct direntry *s /** * Deep-duplicate of an array of direntries, including the array itself. - * - * \param dup_poin If given, called for each non-NULL direntry->poin. Otherwise, pointer is always simply copied over. */ void BLI_filelist_duplicate( struct direntry **dest_filelist, struct direntry * const src_filelist, const unsigned int nrentries) diff --git a/source/blender/blenlib/intern/BLI_heap.c b/source/blender/blenlib/intern/BLI_heap.c index 4bd404e5d73..d48e9fbddde 100644 --- a/source/blender/blenlib/intern/BLI_heap.c +++ b/source/blender/blenlib/intern/BLI_heap.c @@ -32,7 +32,6 @@ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#include "BLI_memarena.h" #include "BLI_heap.h" #include "BLI_strict_flags.h" @@ -44,15 +43,37 @@ struct HeapNode { unsigned int index; }; +struct HeapNode_Chunk { + struct HeapNode_Chunk *prev; + unsigned int size; + unsigned int bufsize; + struct HeapNode buf[0]; +}; + +/** + * Number of nodes to include per #HeapNode_Chunk when no reserved size is passed, + * or we allocate past the reserved number. + * + * \note Optimize number for 64kb allocs. + */ +#define HEAP_CHUNK_DEFAULT_NUM \ + ((MEM_SIZE_OPTIMAL((1 << 16) - sizeof(struct HeapNode_Chunk))) / sizeof(HeapNode)) + struct Heap { unsigned int size; unsigned int bufsize; - MemArena *arena; - HeapNode *freenodes; HeapNode **tree; + + struct { + /* Always keep at least one chunk (never NULL) */ + struct HeapNode_Chunk *chunk; + /* when NULL, allocate a new chunk */ + HeapNode *free; + } nodes; }; -/* internal functions */ +/** \name Internal Functions + * \{ */ #define HEAP_PARENT(i) (((i) - 1) >> 1) #define HEAP_LEFT(i) (((i) << 1) + 1) @@ -92,11 +113,13 @@ static void heap_down(Heap *heap, unsigned int i) smallest = ((l < size) && HEAP_COMPARE(heap->tree[l], heap->tree[i])) ? l : i; - if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) + if ((r < size) && HEAP_COMPARE(heap->tree[r], heap->tree[smallest])) { smallest = r; + } - if (smallest == i) + if (smallest == i) { break; + } heap_swap(heap, i, smallest); i = smallest; @@ -108,25 +131,74 @@ static void heap_up(Heap *heap, unsigned int i) while (i > 0) { const unsigned int p = HEAP_PARENT(i); - if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) + if (HEAP_COMPARE(heap->tree[p], heap->tree[i])) { break; - + } heap_swap(heap, p, i); i = p; } } +/** \} */ -/***/ + +/** \name Internal Memory Management + * \{ */ + +static struct HeapNode_Chunk *heap_node_alloc_chunk( + unsigned int tot_nodes, struct HeapNode_Chunk *chunk_prev) +{ + struct HeapNode_Chunk *chunk = MEM_mallocN( + sizeof(struct HeapNode_Chunk) + (sizeof(HeapNode) * tot_nodes), __func__); + chunk->prev = chunk_prev; + chunk->bufsize = tot_nodes; + chunk->size = 0; + return chunk; +} + +static struct HeapNode *heap_node_alloc(Heap *heap) +{ + HeapNode *node; + + if (heap->nodes.free) { + node = heap->nodes.free; + heap->nodes.free = heap->nodes.free->ptr; + } + else { + struct HeapNode_Chunk *chunk = heap->nodes.chunk; + if (UNLIKELY(chunk->size == chunk->bufsize)) { + struct HeapNode_Chunk *chunk_next = heap_node_alloc_chunk(HEAP_CHUNK_DEFAULT_NUM, chunk); + chunk = chunk_next; + } + node = &chunk->buf[chunk->size++]; + } + + return node; +} + +static void heap_node_free(Heap *heap, HeapNode *node) +{ + node->ptr = heap->nodes.free; + heap->nodes.free = node; +} + +/** \} */ + + +/** \name Public Heap API + * \{ */ /* use when the size of the heap is known in advance */ Heap *BLI_heap_new_ex(unsigned int tot_reserve) { - Heap *heap = (Heap *)MEM_callocN(sizeof(Heap), __func__); + Heap *heap = MEM_mallocN(sizeof(Heap), __func__); /* ensure we have at least one so we can keep doubling it */ + heap->size = 0; heap->bufsize = MAX2(1u, tot_reserve); - heap->tree = (HeapNode **)MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); - heap->arena = BLI_memarena_new(MEM_SIZE_OPTIMAL(1 << 16), "heap arena"); + heap->tree = MEM_mallocN(heap->bufsize * sizeof(HeapNode *), "BLIHeapTree"); + + heap->nodes.chunk = heap_node_alloc_chunk((tot_reserve > 1) ? tot_reserve : HEAP_CHUNK_DEFAULT_NUM, NULL); + heap->nodes.free = NULL; return heap; } @@ -146,8 +218,15 @@ void BLI_heap_free(Heap *heap, HeapFreeFP ptrfreefp) } } + struct HeapNode_Chunk *chunk = heap->nodes.chunk; + do { + struct HeapNode_Chunk *chunk_prev; + chunk_prev = chunk->prev; + MEM_freeN(chunk); + chunk = chunk_prev; + } while (chunk); + MEM_freeN(heap->tree); - BLI_memarena_free(heap->arena); MEM_freeN(heap); } @@ -160,10 +239,16 @@ void BLI_heap_clear(Heap *heap, HeapFreeFP ptrfreefp) ptrfreefp(heap->tree[i]->ptr); } } - heap->size = 0; - BLI_memarena_clear(heap->arena); - heap->freenodes = NULL; + + /* Remove all except the last chunk */ + while (heap->nodes.chunk->prev) { + struct HeapNode_Chunk *chunk_prev = heap->nodes.chunk->prev; + MEM_freeN(heap->nodes.chunk); + heap->nodes.chunk = chunk_prev; + } + heap->nodes.chunk->size = 0; + heap->nodes.free = NULL; } HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) @@ -175,13 +260,7 @@ HeapNode *BLI_heap_insert(Heap *heap, float value, void *ptr) heap->tree = MEM_reallocN(heap->tree, heap->bufsize * sizeof(*heap->tree)); } - if (heap->freenodes) { - node = heap->freenodes; - heap->freenodes = heap->freenodes->ptr; - } - else { - node = (HeapNode *)BLI_memarena_alloc(heap->arena, sizeof(*node)); - } + node = heap_node_alloc(heap); node->ptr = ptr; node->value = value; @@ -217,8 +296,7 @@ void *BLI_heap_popmin(Heap *heap) BLI_assert(heap->size != 0); - heap->tree[0]->ptr = heap->freenodes; - heap->freenodes = heap->tree[0]; + heap_node_free(heap, heap->tree[0]); if (--heap->size) { heap_swap(heap, 0, heap->size); @@ -254,3 +332,4 @@ void *BLI_heap_node_ptr(HeapNode *node) return node->ptr; } +/** \} */ diff --git a/source/blender/blenlib/intern/BLI_kdopbvh.c b/source/blender/blenlib/intern/BLI_kdopbvh.c index 6cef1924e33..b14007a88cb 100644 --- a/source/blender/blenlib/intern/BLI_kdopbvh.c +++ b/source/blender/blenlib/intern/BLI_kdopbvh.c @@ -163,12 +163,23 @@ typedef struct BVHNearestRayData { BVHTree *tree; BVHTree_NearestToRayCallback callback; void *userdata; - BVHTreeRay ray; - struct NearestRayToAABB_Precalc nearest_precalc; + struct { + bool sign[3]; + float origin[3]; + float direction[3]; + + float direction_scaled_square[3]; + float inv_dir[3]; + + float cdot_axis[3]; + } ray; bool pick_smallest[3]; + BVHTreeNearest nearest; + + float scale[3]; } BVHNearestRayData; /** \} */ @@ -1889,58 +1900,374 @@ void BLI_bvhtree_ray_cast_all( /* -------------------------------------------------------------------- */ -/** \name BLI_bvhtree_find_nearest_to_ray +/** \name BLI_bvhtree_find_nearest_to_ray functions * * \{ */ +static void dist_squared_ray_to_aabb_scaled_v3_precalc( + BVHNearestRayData *data, + const float ray_origin[3], const float ray_direction[3], + const bool ray_is_normalized, const float scale[3]) +{ + if (scale) { + copy_v3_v3(data->scale, scale); + } + else { + copy_v3_fl(data->scale, 1.0f); + } + /* un-normalize ray */ + if (ray_is_normalized && scale && + (data->scale[0] != 1.0f || data->scale[1] != 1.0f || data->scale[2] != 1.0f)) + { + data->ray.direction[0] = ray_direction[0] * data->scale[0]; + data->ray.direction[1] = ray_direction[1] * data->scale[1]; + data->ray.direction[2] = ray_direction[2] * data->scale[2]; + + mul_v3_v3fl(data->ray.direction, ray_direction, 1 / len_v3(data->ray.direction)); + } + else { + copy_v3_v3(data->ray.direction, ray_direction); + } + + float dir_sq[3]; + + for (int i = 0; i < 3; i++) { + data->ray.origin[i] = ray_origin[i]; + data->ray.inv_dir[i] = (data->ray.direction[i] != 0.0f) ? + (1.0f / data->ray.direction[i]) : FLT_MAX; + /* It has to be in function of `ray.inv_dir`, + * since the division of 1 by 0.0f, can be -inf or +inf */ + data->ray.sign[i] = (data->ray.inv_dir[i] < 0.0f); + + data->ray.direction_scaled_square[i] = data->ray.direction[i] * data->scale[i]; + + dir_sq[i] = SQUARE(data->ray.direction_scaled_square[i]); + + data->ray.direction_scaled_square[i] *= data->scale[i]; + } + + /* `diag_sq` Length square of each face diagonal */ + float diag_sq[3] = { + dir_sq[1] + dir_sq[2], + dir_sq[0] + dir_sq[2], + dir_sq[0] + dir_sq[1], + }; + + data->ray.cdot_axis[0] = (diag_sq[0] != 0.0f) ? data->ray.direction[0] / diag_sq[0] : FLT_MAX; + data->ray.cdot_axis[1] = (diag_sq[1] != 0.0f) ? data->ray.direction[1] / diag_sq[1] : FLT_MAX; + data->ray.cdot_axis[2] = (diag_sq[2] != 0.0f) ? data->ray.direction[2] / diag_sq[2] : FLT_MAX; +} + +/** + * Returns the squared distance from a ray to a bound-box `AABB`. + * It is based on `fast_ray_nearest_hit` solution to obtain + * the coordinates of the nearest edge of Bound Box to the ray + */ +MINLINE float dist_squared_ray_to_aabb_scaled_v3__impl( + const BVHNearestRayData *data, + const float bv[6], float *r_depth_sq, bool r_axis_closest[3]) +{ + + /* `tmin` is a vector that has the smaller distances to each of the + * infinite planes of the `AABB` faces (hit in nearest face X plane, + * nearest face Y plane and nearest face Z plane) */ + float local_bvmin[3], local_bvmax[3]; + + if (data->ray.sign[0]) { + local_bvmin[0] = bv[1]; + local_bvmax[0] = bv[0]; + } + else { + local_bvmin[0] = bv[0]; + local_bvmax[0] = bv[1]; + } + + if (data->ray.sign[1]) { + local_bvmin[1] = bv[3]; + local_bvmax[1] = bv[2]; + } + else { + local_bvmin[1] = bv[2]; + local_bvmax[1] = bv[3]; + } + + if (data->ray.sign[2]) { + local_bvmin[2] = bv[5]; + local_bvmax[2] = bv[4]; + } + else { + local_bvmin[2] = bv[4]; + local_bvmax[2] = bv[5]; + } + + sub_v3_v3(local_bvmin, data->ray.origin); + sub_v3_v3(local_bvmax, data->ray.origin); + + const float tmin[3] = { + local_bvmin[0] * data->ray.inv_dir[0], + local_bvmin[1] * data->ray.inv_dir[1], + local_bvmin[2] * data->ray.inv_dir[2], + }; + + /* `tmax` is a vector that has the longer distances to each of the + * infinite planes of the `AABB` faces (hit in farthest face X plane, + * farthest face Y plane and farthest face Z plane) */ + const float tmax[3] = { + local_bvmax[0] * data->ray.inv_dir[0], + local_bvmax[1] * data->ray.inv_dir[1], + local_bvmax[2] * data->ray.inv_dir[2], + }; + /* `v1` and `v3` is be the coordinates of the nearest `AABB` edge to the ray*/ + float v1[3], v2[3]; + /* `rtmin` is the highest value of the smaller distances. == max_axis_v3(tmin) + * `rtmax` is the lowest value of longer distances. == min_axis_v3(tmax)*/ + float rtmin, rtmax, mul; + /* `main_axis` is the axis equivalent to edge close to the ray */ + int main_axis; + + r_axis_closest[0] = false; + r_axis_closest[1] = false; + r_axis_closest[2] = false; + + /* *** min_axis_v3(tmax) *** */ + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + // printf("# Hit in X %s\n", data->sign[0] ? "min", "max"); + rtmax = tmax[0]; + v1[0] = v2[0] = local_bvmax[0]; + mul = local_bvmax[0] * data->ray.direction_scaled_square[0]; + main_axis = 3; + r_axis_closest[0] = data->ray.sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + // printf("# Hit in Y %s\n", data->sign[1] ? "min", "max"); + rtmax = tmax[1]; + v1[1] = v2[1] = local_bvmax[1]; + mul = local_bvmax[1] * data->ray.direction_scaled_square[1]; + main_axis = 2; + r_axis_closest[1] = data->ray.sign[1]; + } + else { + // printf("# Hit in Z %s\n", data->sign[2] ? "min", "max"); + rtmax = tmax[2]; + v1[2] = v2[2] = local_bvmax[2]; + mul = local_bvmax[2] * data->ray.direction_scaled_square[2]; + main_axis = 1; + r_axis_closest[2] = data->ray.sign[2]; + } + + /* *** max_axis_v3(tmin) *** */ + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + // printf("# To X %s\n", data->sign[0] ? "max", "min"); + rtmin = tmin[0]; + v1[0] = v2[0] = local_bvmin[0]; + mul += local_bvmin[0] * data->ray.direction_scaled_square[0]; + main_axis -= 3; + r_axis_closest[0] = !data->ray.sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + // printf("# To Y %s\n", data->sign[1] ? "max", "min"); + rtmin = tmin[1]; + v1[1] = v2[1] = local_bvmin[1]; + mul += local_bvmin[1] * data->ray.direction_scaled_square[1]; + main_axis -= 1; + r_axis_closest[1] = !data->ray.sign[1]; + } + else { + // printf("# To Z %s\n", data->sign[2] ? "max", "min"); + rtmin = tmin[2]; + v1[2] = v2[2] = local_bvmin[2]; + mul += local_bvmin[2] * data->ray.direction_scaled_square[2]; + main_axis -= 2; + r_axis_closest[2] = !data->ray.sign[2]; + } + /* *** end min/max axis *** */ + + if (main_axis < 0) + main_axis += 3; + + /* if rtmin < rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { +#ifdef IGNORE_BEHIND_RAY + /* `if rtmax < depth_min`, the whole `AABB` is behind us */ + if (rtmax < min_depth) { + return fallback; + } +#endif + const float proj = rtmin * data->ray.direction[main_axis]; + + if (data->ray.sign[main_axis]) + r_axis_closest[main_axis] = (proj - local_bvmax[main_axis]) < (local_bvmin[main_axis] - proj); + else + r_axis_closest[main_axis] = (proj - local_bvmin[main_axis]) < (local_bvmax[main_axis] - proj); + + //if (r_depth_sq) + // *r_depth_sq = SQUARE(rtmin); + + return 0.0f; + } +#ifdef IGNORE_BEHIND_RAY + /* `if rtmin < depth_min`, the whole `AABB` is behing us */ + else if (rtmin < min_depth) { + return fallback; + } +#endif + + if (data->ray.sign[main_axis]) { + v1[main_axis] = local_bvmax[main_axis]; + v2[main_axis] = local_bvmin[main_axis]; + } + else { + v1[main_axis] = local_bvmin[main_axis]; + v2[main_axis] = local_bvmax[main_axis]; + } + { + /* `proj` equals to nearest point on the ray closest to the edge `v1 v2` of the `AABB`. */ + const float proj = mul * data->ray.cdot_axis[main_axis]; + float depth_sq, r_point[3]; + if (v1[main_axis] > proj) { /* the nearest point to the ray is the point v1 */ + r_axis_closest[main_axis] = true; + /* `depth` is equivalent the distance of the the projection of v1 on the ray */ + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v1[main_axis]; + + copy_v3_v3(r_point, v1); + } + else if (v2[main_axis] < proj) { /* the nearest point of the ray is the point v2 */ + r_axis_closest[main_axis] = false; + + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * v2[main_axis]; + + copy_v3_v3(r_point, v2); + } + else { /* the nearest point of the ray is on the edge of the `AABB`. */ + r_axis_closest[main_axis] = (proj - v1[main_axis]) < (v2[main_axis] - proj); + + depth_sq = mul + data->ray.direction_scaled_square[main_axis] * proj; +#if 0 + r_point[0] = main_axis == 0 ? proj : v2[0]; + r_point[1] = main_axis == 1 ? proj : v2[1]; + r_point[2] = main_axis == 2 ? proj : v2[2]; +#else + v2[main_axis] = proj; + copy_v3_v3(r_point, v2); +#endif + } + depth_sq *= depth_sq; + + if (r_depth_sq) + *r_depth_sq = depth_sq; + + /* TODO: scale can be optional */ + r_point[0] *= data->scale[0]; + r_point[1] *= data->scale[1]; + r_point[2] *= data->scale[2]; + + return len_squared_v3(r_point) - depth_sq; + } +} + +/** + * <pre> + * + r_point + * | + * | dist + * | + * +----depth----+orig <-- dir + * + * tangent = dist/depth + * </pre> + */ +static float calc_tangent_sq(BVHNearestRayData *data, BVHNode *node) +{ + float depth_sq; + const float dist_sq = dist_squared_ray_to_aabb_scaled_v3__impl( + data, node->bv, &depth_sq, data->pick_smallest); + + return (dist_sq != 0.0f) ? (dist_sq / depth_sq) : 0.0f; +} + static float calc_dist_sq_to_ray(BVHNearestRayData *data, BVHNode *node) { - const float *bv = node->bv; - const float bb_min[3] = {bv[0], bv[2], bv[4]}; - const float bb_max[3] = {bv[1], bv[3], bv[5]}; - return dist_squared_ray_to_aabb_v3(&data->nearest_precalc, bb_min, bb_max, data->pick_smallest); + return dist_squared_ray_to_aabb_scaled_v3__impl( + data, node->bv, NULL, + data->pick_smallest); } -static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node) +static void dfs_find_lowest_tangent_dfs(BVHNearestRayData *data, BVHNode *node) { if (node->totnode == 0) { if (data->callback) { - data->callback(data->userdata, node->index, &data->ray, &data->nearest); + data->callback(data->userdata, data->ray.origin, data->ray.direction, + data->scale, node->index, &data->nearest); + } + else { + data->nearest.index = node->index; + data->nearest.dist_sq = calc_tangent_sq(data, node); + /* TODO: return a value to the data->nearest.co + * not urgent however since users currently define own callbacks */ + } + } + else { + int i; + /* First pick the closest node to dive on */ + if (data->pick_smallest[node->main_axis]) { + for (i = 0; i != node->totnode; i++) { + if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_lowest_tangent_dfs(data, node->children[i]); + } + } } else { - const float dist_sq = calc_dist_sq_to_ray(data, node); - if (dist_sq != FLT_MAX) { /* not an invalid ray */ - data->nearest.index = node->index; - data->nearest.dist_sq = dist_sq; - /* TODO: return a value to the data->nearest.co - * not urgent however since users currently define own callbacks */ + for (i = node->totnode - 1; i >= 0; i--) { + if (calc_tangent_sq(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_lowest_tangent_dfs(data, node->children[i]); + } } } } +} + +static void dfs_find_nearest_to_ray_dfs(BVHNearestRayData *data, BVHNode *node) +{ + if (node->totnode == 0) { + if (data->callback) { + data->callback(data->userdata, data->ray.origin, data->ray.direction, + data->scale, node->index, &data->nearest); + } + else { + data->nearest.index = node->index; + data->nearest.dist_sq = calc_dist_sq_to_ray(data, node); + /* TODO: return a value to the data->nearest.co + * not urgent however since users currently define own callbacks */ + } + } else { int i; /* First pick the closest node to dive on */ if (data->pick_smallest[node->main_axis]) { for (i = 0; i != node->totnode; i++) { - if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) { - continue; + if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_nearest_to_ray_dfs(data, node->children[i]); } - dfs_find_nearest_to_ray_dfs(data, node->children[i]); } } else { for (i = node->totnode - 1; i >= 0; i--) { - if (calc_dist_sq_to_ray(data, node->children[i]) >= data->nearest.dist_sq) { - continue; + if (calc_dist_sq_to_ray(data, node->children[i]) < data->nearest.dist_sq) { + dfs_find_nearest_to_ray_dfs(data, node->children[i]); } - dfs_find_nearest_to_ray_dfs(data, node->children[i]); } } } } -int BLI_bvhtree_find_nearest_to_ray( - BVHTree *tree, const float co[3], const float dir[3], BVHTreeNearest *nearest, +/** + * Returns the point whose tangent defined by the angle between the point and ray is the lowest + * nearest.dist_sq returns the angle's tangent + */ +int BLI_bvhtree_find_nearest_to_ray_angle( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, BVHTree_NearestToRayCallback callback, void *userdata) { BVHNearestRayData data; @@ -1951,11 +2278,46 @@ int BLI_bvhtree_find_nearest_to_ray( data.callback = callback; data.userdata = userdata; - copy_v3_v3(data.ray.origin, co); - copy_v3_v3(data.ray.direction, dir); - data.ray.radius = 0.0f; /* unused here */ + dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale); + + if (nearest) { + memcpy(&data.nearest, nearest, sizeof(*nearest)); + } + else { + data.nearest.index = -1; + data.nearest.dist_sq = FLT_MAX; + } + + /* dfs search */ + if (root) { + if (calc_tangent_sq(&data, root) < data.nearest.dist_sq) + dfs_find_lowest_tangent_dfs(&data, root); + } + + /* copy back results */ + if (nearest) { + memcpy(nearest, &data.nearest, sizeof(*nearest)); + } + + return data.nearest.index; +} + +/* return the nearest point to ray */ +int BLI_bvhtree_find_nearest_to_ray( + BVHTree *tree, const float co[3], const float dir[3], + const bool ray_is_normalized, const float scale[3], + BVHTreeNearest *nearest, + BVHTree_NearestToRayCallback callback, void *userdata) +{ + BVHNearestRayData data; + BVHNode *root = tree->nodes[tree->totleaf]; + + data.tree = tree; + + data.callback = callback; + data.userdata = userdata; - dist_squared_ray_to_aabb_v3_precalc(&data.nearest_precalc, co, dir); + dist_squared_ray_to_aabb_scaled_v3_precalc(&data, co, dir, ray_is_normalized, scale); if (nearest) { memcpy(&data.nearest, nearest, sizeof(*nearest)); diff --git a/source/blender/blenlib/intern/array_store.c b/source/blender/blenlib/intern/array_store.c index 33565596c1f..6000c1a680c 100644 --- a/source/blender/blenlib/intern/array_store.c +++ b/source/blender/blenlib/intern/array_store.c @@ -249,7 +249,7 @@ typedef struct BArrayMemory { /** * Main storage for all states */ -typedef struct BArrayStore { +struct BArrayStore { /* static */ BArrayInfo info; @@ -260,7 +260,7 @@ typedef struct BArrayStore { * #BArrayState may be in any order (logic should never depend on state order). */ ListBase states; -} BArrayStore; +}; /** * A single instance of an array. @@ -272,13 +272,13 @@ typedef struct BArrayStore { * While this could be moved to a memory pool, * it makes it easier to trace invalid usage, so leave as-is for now. */ -typedef struct BArrayState { +struct BArrayState { /** linked list in #BArrayStore.states */ struct BArrayState *next, *prev; struct BChunkList *chunk_list; /* BChunkList's */ -} BArrayState; +}; typedef struct BChunkList { ListBase chunk_refs; /* BChunkRef's */ @@ -1750,10 +1750,11 @@ bool BLI_array_store_is_valid( } \ } ((void)0) - /* count chunk_list's */ - int totrefs = 0; GHash *chunk_list_map = BLI_ghash_ptr_new(__func__); + GHash *chunk_map = BLI_ghash_ptr_new(__func__); + + int totrefs = 0; for (BArrayState *state = bs->states.first; state; state = state->next) { GHASH_PTR_ADD_USER(chunk_list_map, state->chunk_list); } @@ -1771,7 +1772,6 @@ bool BLI_array_store_is_valid( } /* count chunk's */ - GHash *chunk_map = BLI_ghash_ptr_new(__func__); GHASH_ITER (gh_iter, chunk_list_map) { const struct BChunkList *chunk_list = BLI_ghashIterator_getKey(&gh_iter); for (const BChunkRef *cref = chunk_list->chunk_refs.first; cref; cref = cref->next) { diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 5d485e2033d..32f0111babd 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -134,8 +134,22 @@ void _bli_array_permute( int _bli_array_findindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) { const char *arr_step = (const char *)arr; - unsigned int i; - for (i = 0; i < arr_len; i++, arr_step += arr_stride) { + for (unsigned int i = 0; i < arr_len; i++, arr_step += arr_stride) { + if (memcmp(arr_step, p, arr_stride) == 0) { + return (int)i; + } + } + return -1; +} + +/** + * A version of #BLI_array_findindex that searches from the end of the list. + */ +int _bli_array_rfindindex(const void *arr, unsigned int arr_len, size_t arr_stride, const void *p) +{ + const char *arr_step = (const char *)arr + (arr_stride * arr_len); + for (unsigned int i = arr_len; i-- != 0; ) { + arr_step -= arr_stride; if (memcmp(arr_step, p, arr_stride) == 0) { return (int)i; } @@ -183,7 +197,7 @@ void _bli_array_binary_or( * \param user_data: User data for \a test_fn. * \param span_step: Indices to iterate over, * initialize both values to the array length to initialize iteration. - * \param: r_span_len: The length of the span, useful when \a use_wrap is enabled, + * \param r_span_len: The length of the span, useful when \a use_wrap is enabled, * where calculating the length isnt a simple subtraction. */ bool _bli_array_iter_span( diff --git a/source/blender/blenlib/intern/hash_md5.c b/source/blender/blenlib/intern/hash_md5.c index d98b915983c..c73fe7a3ff1 100644 --- a/source/blender/blenlib/intern/hash_md5.c +++ b/source/blender/blenlib/intern/hash_md5.c @@ -112,7 +112,7 @@ static void md5_init_ctx(struct md5_ctx *ctx) * the 'ctx' context for the next 'len' bytes starting at 'buffer'. * It is necessary that 'len' is a multiple of 64!!! */ -static void md5_process_block (const void *buffer, size_t len, struct md5_ctx *ctx) +static void md5_process_block(const void *buffer, size_t len, struct md5_ctx *ctx) { /* These are the four functions used in the four steps of the MD5 algorithm and defined in the RFC 1321. * The first function is a little bit optimized (as found in Colin Plumbs public domain implementation). diff --git a/source/blender/blenlib/intern/math_geom.c b/source/blender/blenlib/intern/math_geom.c index 370e8bb0035..40454a93ec8 100644 --- a/source/blender/blenlib/intern/math_geom.c +++ b/source/blender/blenlib/intern/math_geom.c @@ -572,6 +572,67 @@ float dist_signed_squared_to_corner_v3v3v3( } } +/** + * return the distance squared of a point to a ray. + */ +float dist_squared_to_ray_v3( + const float ray_origin[3], const float ray_direction[3], + const float co[3], float *r_depth) +{ + float dvec[3]; + sub_v3_v3v3(dvec, co, ray_origin); + *r_depth = dot_v3v3(dvec, ray_direction); + return len_squared_v3(dvec) - SQUARE(*r_depth); +} +/** + * Find the closest point in a seg to a ray and return the distance squared. + * \param r_point : Is the point on segment closest to ray (or to ray_origin if the ray and the segment are parallel). + * \param depth: the distance of r_point projection on ray to the ray_origin. + */ +float dist_squared_ray_to_seg_v3( + const float ray_origin[3], const float ray_direction[3], + const float v0[3], const float v1[3], + float r_point[3], float *r_depth) +{ + float a[3], t[3], n[3], lambda; + sub_v3_v3v3(a, v1, v0); + sub_v3_v3v3(t, v0, ray_origin); + cross_v3_v3v3(n, a, ray_direction); + const float nlen = len_squared_v3(n); + + /* if (nlen == 0.0f) the lines are parallel, + * has no nearest point, only distance squared.*/ + if (nlen == 0.0f) { + /* Calculate the distance to the point v0 then */ + copy_v3_v3(r_point, v0); + *r_depth = dot_v3v3(t, ray_direction); + } + else { + float c[3], cray[3]; + sub_v3_v3v3(c, n, t); + cross_v3_v3v3(cray, c, ray_direction); + lambda = dot_v3v3(cray, n) / nlen; + if (lambda <= 0) { + copy_v3_v3(r_point, v0); + + *r_depth = dot_v3v3(t, ray_direction); + } + else if (lambda >= 1) { + copy_v3_v3(r_point, v1); + + sub_v3_v3v3(t, v1, ray_origin); + *r_depth = dot_v3v3(t, ray_direction); + } + else { + madd_v3_v3v3fl(r_point, v0, a, lambda); + + sub_v3_v3v3(t, r_point, ray_origin); + *r_depth = dot_v3v3(t, ray_direction); + } + } + return len_squared_v3(t) - SQUARE(*r_depth); +} + /* Adapted from "Real-Time Collision Detection" by Christer Ericson, * published by Morgan Kaufmann Publishers, copyright 2005 Elsevier Inc. * @@ -2692,7 +2753,7 @@ bool isect_point_tri_prism_v3(const float p[3], const float v1[3], const float v } /** - * \param r_vi The point \a p projected onto the triangle. + * \param r_isect_co: The point \a p projected onto the triangle. * \return True when \a p is inside the triangle. * \note Its up to the caller to check the distance between \a p and \a r_vi against an error margin. */ @@ -5002,7 +5063,9 @@ float cubic_tangent_factor_circle_v3(const float tan_l[3], const float tan_r[3]) BLI_ASSERT_UNIT_V3(tan_l); BLI_ASSERT_UNIT_V3(tan_r); - const float eps = 1e-7f; + /* -7f causes instability/glitches with Bendy Bones + Custom Refs */ + const float eps = 1e-5f; + const float tan_dot = dot_v3v3(tan_l, tan_r); if (tan_dot > 1.0f - eps) { /* no angle difference (use fallback, length wont make any difference) */ diff --git a/source/blender/blenlib/intern/math_interp.c b/source/blender/blenlib/intern/math_interp.c index 069d23e7147..8c361673715 100644 --- a/source/blender/blenlib/intern/math_interp.c +++ b/source/blender/blenlib/intern/math_interp.c @@ -284,16 +284,19 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f if (x1 < 0) x1 = width - 1; if (x2 >= width) x2 = 0; } + else if (x2 < 0 || x1 >= width) { + copy_vn_fl(float_output, components, 0.0f); + return; + } + if (wrap_y) { if (y1 < 0) y1 = height - 1; if (y2 >= height) y2 = 0; } - - CLAMP(x1, 0, width - 1); - CLAMP(x2, 0, width - 1); - - CLAMP(y1, 0, height - 1); - CLAMP(y2, 0, height - 1); + else if (y2 < 0 || y1 >= height) { + copy_vn_fl(float_output, components, 0.0f); + return; + } /* sample including outside of edges of image */ if (x1 < 0 || y1 < 0) row1 = empty; @@ -331,8 +334,21 @@ BLI_INLINE void bilinear_interpolation(const unsigned char *byte_buffer, const f const unsigned char *row1, *row2, *row3, *row4; unsigned char empty[4] = {0, 0, 0, 0}; - /* sample area entirely outside image? */ - if (x2 < 0 || x1 > width - 1 || y2 < 0 || y1 > height - 1) { + /* pixel value must be already wrapped, however values at boundaries may flip */ + if (wrap_x) { + if (x1 < 0) x1 = width - 1; + if (x2 >= width) x2 = 0; + } + else if (x2 < 0 || x1 >= width) { + copy_vn_uchar(byte_output, components, 0); + return; + } + + if (wrap_y) { + if (y1 < 0) y1 = height - 1; + if (y2 >= height) y2 = 0; + } + else if (y2 < 0 || y1 >= height) { copy_vn_uchar(byte_output, components, 0); return; } diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index 0e3f905ef16..c9c61d5c878 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -587,6 +587,15 @@ void mul_v3_m3v3(float r[3], float M[3][3], const float a[3]) r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; } +void mul_v3_m3v3_db(double r[3], double M[3][3], const double a[3]) +{ + BLI_assert(r != a); + + r[0] = M[0][0] * a[0] + M[1][0] * a[1] + M[2][0] * a[2]; + r[1] = M[0][1] * a[0] + M[1][1] * a[1] + M[2][1] * a[2]; + r[2] = M[0][2] * a[0] + M[1][2] * a[1] + M[2][2] * a[2]; +} + void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) { BLI_assert(r != a); @@ -597,10 +606,12 @@ void mul_v2_m3v3(float r[2], float M[3][3], const float a[3]) void mul_m3_v3(float M[3][3], float r[3]) { - float tmp[3]; + mul_v3_m3v3(r, M, (const float[3]){UNPACK3(r)}); +} - mul_v3_m3v3(tmp, M, r); - copy_v3_v3(r, tmp); +void mul_m3_v3_db(double M[3][3], double r[3]) +{ + mul_v3_m3v3_db(r, M, (const double[3]){UNPACK3(r)}); } void mul_transposed_m3_v3(float mat[3][3], float vec[3]) diff --git a/source/blender/blenlib/intern/math_rotation.c b/source/blender/blenlib/intern/math_rotation.c index d962e4f0fa7..b285a74b8ac 100644 --- a/source/blender/blenlib/intern/math_rotation.c +++ b/source/blender/blenlib/intern/math_rotation.c @@ -200,8 +200,7 @@ void mul_fac_qt_fl(float q[4], const float fac) const float co = cosf(angle); const float si = sinf(angle); q[0] = co; - normalize_v3(q + 1); - mul_v3_fl(q + 1, si); + normalize_v3_length(q + 1, si); } /* skip error check, currently only needed by mat3_to_quat_is_ok */ diff --git a/source/blender/blenlib/intern/math_vector.c b/source/blender/blenlib/intern/math_vector.c index 988034349e0..95d5c9fde87 100644 --- a/source/blender/blenlib/intern/math_vector.c +++ b/source/blender/blenlib/intern/math_vector.c @@ -164,6 +164,27 @@ void interp_v2_v2v2_slerp_safe(float target[2], const float a[2], const float b[ } } +/** \name Cubic curve interpolation (bezier spline). + * \{ */ + +void interp_v2_v2v2v2v2_cubic( + float p[2], const float v1[2], const float v2[2], const float v3[2], const float v4[2], + const float u) +{ + float q0[2], q1[2], q2[2], r0[2], r1[2]; + + interp_v2_v2v2(q0, v1, v2, u); + interp_v2_v2v2(q1, v2, v3, u); + interp_v2_v2v2(q2, v3, v4, u); + + interp_v2_v2v2(r0, q0, q1, u); + interp_v2_v2v2(r1, q1, q2, u); + + interp_v2_v2v2(p, r0, r1, u); +} + +/** \} */ + /* weight 3 vectors, * 'w' must be unit length but is not a vector, just 3 weights */ void interp_v3_v3v3v3(float p[3], const float v1[3], const float v2[3], const float v3[3], const float w[3]) diff --git a/source/blender/blenlib/intern/math_vector_inline.c b/source/blender/blenlib/intern/math_vector_inline.c index b43fb6e986c..e9fb77f6302 100644 --- a/source/blender/blenlib/intern/math_vector_inline.c +++ b/source/blender/blenlib/intern/math_vector_inline.c @@ -633,6 +633,13 @@ MINLINE void negate_v3_short(short r[3]) r[2] = (short)-r[2]; } +MINLINE void negate_v3_db(double r[3]) +{ + r[0] = -r[0]; + r[1] = -r[1]; + r[2] = -r[2]; +} + MINLINE void invert_v2(float r[2]) { BLI_assert(!ELEM(0.0f, r[0], r[1])); @@ -852,13 +859,13 @@ MINLINE float len_v3v3(const float a[3], const float b[3]) return len_v3(d); } -MINLINE float normalize_v2_v2(float r[2], const float a[2]) +MINLINE float normalize_v2_v2_length(float r[2], const float a[2], const float unit_length) { float d = dot_v2v2(a, a); if (d > 1.0e-35f) { d = sqrtf(d); - mul_v2_v2fl(r, a, 1.0f / d); + mul_v2_v2fl(r, a, unit_length / d); } else { zero_v2(r); @@ -867,13 +874,22 @@ MINLINE float normalize_v2_v2(float r[2], const float a[2]) return d; } +MINLINE float normalize_v2_v2(float r[2], const float a[2]) +{ + return normalize_v2_v2_length(r, a, 1.0f); +} MINLINE float normalize_v2(float n[2]) { return normalize_v2_v2(n, n); } -MINLINE float normalize_v3_v3(float r[3], const float a[3]) +MINLINE float normalize_v2_length(float n[2], const float unit_length) +{ + return normalize_v2_v2_length(n, n, unit_length); +} + +MINLINE float normalize_v3_v3_length(float r[3], const float a[3], const float unit_length) { float d = dot_v3v3(a, a); @@ -881,7 +897,7 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]) * scaled down models with camera extreme close */ if (d > 1.0e-35f) { d = sqrtf(d); - mul_v3_v3fl(r, a, 1.0f / d); + mul_v3_v3fl(r, a, unit_length / d); } else { zero_v3(r); @@ -890,8 +906,12 @@ MINLINE float normalize_v3_v3(float r[3], const float a[3]) return d; } +MINLINE float normalize_v3_v3(float r[3], const float a[3]) +{ + return normalize_v3_v3_length(r, a, 1.0f); +} -MINLINE double normalize_v3_d(double n[3]) +MINLINE double normalize_v3_length_d(double n[3], const double unit_length) { double d = n[0] * n[0] + n[1] * n[1] + n[2] * n[2]; @@ -901,7 +921,7 @@ MINLINE double normalize_v3_d(double n[3]) double mul; d = sqrt(d); - mul = 1.0 / d; + mul = unit_length / d; n[0] *= mul; n[1] *= mul; @@ -914,6 +934,15 @@ MINLINE double normalize_v3_d(double n[3]) return d; } +MINLINE double normalize_v3_d(double n[3]) +{ + return normalize_v3_length_d(n, 1.0); +} + +MINLINE float normalize_v3_length(float n[3], const float unit_length) +{ + return normalize_v3_v3_length(n, n, unit_length); +} MINLINE float normalize_v3(float n[3]) { diff --git a/source/blender/blenlib/intern/path_util.c b/source/blender/blenlib/intern/path_util.c index 2b793841c38..ded10ad7713 100644 --- a/source/blender/blenlib/intern/path_util.c +++ b/source/blender/blenlib/intern/path_util.c @@ -310,7 +310,7 @@ static int BLI_path_unc_prefix_len(const char *path); /* defined below in same f /** * Remove redundant characters from \a path and optionally make absolute. * - * \param relbase: The path this is relative to, or ignored when NULL. + * \param relabase: The path this is relative to, or ignored when NULL. * \param path: Can be any input, and this function converts it to a regular full path. * Also removes garbage from directory paths, like `/../` or double slashes etc. * diff --git a/source/blender/blenlib/intern/quadric.c b/source/blender/blenlib/intern/quadric.c index 588cd9c2cb5..c9d27494455 100644 --- a/source/blender/blenlib/intern/quadric.c +++ b/source/blender/blenlib/intern/quadric.c @@ -63,26 +63,68 @@ void BLI_quadric_from_plane(Quadric *q, const double v[4]) q->d2 = v[3] * v[3]; } -void BLI_quadric_to_tensor_m3(const Quadric *q, float m[3][3]) +#if 0 /* UNUSED */ + +static void quadric_to_tensor_m3(const Quadric *q, double m[3][3]) { - m[0][0] = (float)q->a2; - m[0][1] = (float)q->ab; - m[0][2] = (float)q->ac; + m[0][0] = q->a2; + m[0][1] = q->ab; + m[0][2] = q->ac; - m[1][0] = (float)q->ab; - m[1][1] = (float)q->b2; - m[1][2] = (float)q->bc; + m[1][0] = q->ab; + m[1][1] = q->b2; + m[1][2] = q->bc; - m[2][0] = (float)q->ac; - m[2][1] = (float)q->bc; - m[2][2] = (float)q->c2; + m[2][0] = q->ac; + m[2][1] = q->bc; + m[2][2] = q->c2; } -void BLI_quadric_to_vector_v3(const Quadric *q, float v[3]) +#endif + +/** + * Inline inverse matrix creation. + * Equivalent of: + * + * \code{.c} + * quadric_to_tensor_m3(q, m); + * invert_m3_db(m, eps); + * \endcode + */ +static bool quadric_to_tensor_m3_inverse(const Quadric *q, double m[3][3], double epsilon) { - v[0] = (float)q->ad; - v[1] = (float)q->bd; - v[2] = (float)q->cd; + const double det = + (q->a2 * (q->b2 * q->c2 - q->bc * q->bc) - + q->ab * (q->ab * q->c2 - q->ac * q->bc) + + q->ac * (q->ab * q->bc - q->ac * q->b2)); + + if (fabs(det) > epsilon) { + const double invdet = 1.0 / det; + + m[0][0] = (q->b2 * q->c2 - q->bc * q->bc) * invdet; + m[1][0] = (q->bc * q->ac - q->ab * q->c2) * invdet; + m[2][0] = (q->ab * q->bc - q->b2 * q->ac) * invdet; + + m[0][1] = (q->ac * q->bc - q->ab * q->c2) * invdet; + m[1][1] = (q->a2 * q->c2 - q->ac * q->ac) * invdet; + m[2][1] = (q->ab * q->ac - q->a2 * q->bc) * invdet; + + m[0][2] = (q->ab * q->bc - q->ac * q->b2) * invdet; + m[1][2] = (q->ac * q->ab - q->a2 * q->bc) * invdet; + m[2][2] = (q->a2 * q->b2 - q->ab * q->ab) * invdet; + + return true; + } + else { + return false; + } +} + +void BLI_quadric_to_vector_v3(const Quadric *q, double v[3]) +{ + v[0] = q->ad; + v[1] = q->bd; + v[2] = q->cd; } void BLI_quadric_clear(Quadric *q) @@ -105,26 +147,22 @@ void BLI_quadric_mul(Quadric *a, const double scalar) mul_vn_db((double *)a, QUADRIC_FLT_TOT, scalar); } -double BLI_quadric_evaluate(const Quadric *q, const float v_fl[3]) +double BLI_quadric_evaluate(const Quadric *q, const double v[3]) { - const double v[3] = {UNPACK3(v_fl)}; return ((q->a2 * v[0] * v[0]) + (q->ab * 2 * v[0] * v[1]) + (q->ac * 2 * v[0] * v[2]) + (q->ad * 2 * v[0]) + (q->b2 * v[1] * v[1]) + (q->bc * 2 * v[1] * v[2]) + (q->bd * 2 * v[1]) + (q->c2 * v[2] * v[2]) + (q->cd * 2 * v[2]) + (q->d2)); } -bool BLI_quadric_optimize(const Quadric *q, float v[3], const float epsilon) +bool BLI_quadric_optimize(const Quadric *q, double v[3], const double epsilon) { - float m[3][3]; + double m[3][3]; - BLI_quadric_to_tensor_m3(q, m); - - if (invert_m3_ex(m, epsilon)) { + if (quadric_to_tensor_m3_inverse(q, m, epsilon)) { BLI_quadric_to_vector_v3(q, v); - mul_m3_v3(m, v); - negate_v3(v); - + mul_m3_v3_db(m, v); + negate_v3_db(v); return true; } else { diff --git a/source/blender/blenlib/intern/storage.c b/source/blender/blenlib/intern/storage.c index aba7c9d5ee2..3edc00a8c1a 100644 --- a/source/blender/blenlib/intern/storage.c +++ b/source/blender/blenlib/intern/storage.c @@ -389,7 +389,7 @@ LinkNode *BLI_file_read_as_lines(const char *name) /* * size = because on win32 reading * all the bytes in the file will return - * less bytes because of crnl changes. + * less bytes because of `CRNL` changes. */ size = fread(buf, 1, size, fp); for (i = 0; i <= size; i++) { diff --git a/source/blender/blenlib/intern/task.c b/source/blender/blenlib/intern/task.c index 58475b7f835..bd7b7f9cdbd 100644 --- a/source/blender/blenlib/intern/task.c +++ b/source/blender/blenlib/intern/task.c @@ -928,7 +928,7 @@ static void task_parallel_range_ex( func_finalize(userdata, userdata_chunk_local); } } - MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks); + MALLOCA_FREE(userdata_chunk_array, userdata_chunk_size * num_tasks); } } @@ -992,7 +992,8 @@ void BLI_task_parallel_range( * (similar to OpenMP's firstprivate). * \param userdata_chunk_size Memory size of \a userdata_chunk. * \param func_ex Callback function (advanced version). - * \param func_finalize Callback function, called after all workers have finisehd, useful to finalize accumulative tasks. + * \param func_finalize Callback function, called after all workers have finished, + * useful to finalize accumulative tasks. * \param use_threading If \a true, actually split-execute loop in threads, else just do a sequential forloop * (allows caller to use any kind of test to switch on parallelization or not). * \param use_dynamic_scheduling If \a true, the whole range is divided in a lot of small chunks (of size 32 currently), diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index bf47682297d..c85cf128643 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -100,7 +100,8 @@ struct ID *BLO_library_link_named_part(struct Main *mainl, BlendHandle **bh, con struct ID *BLO_library_link_named_part_ex( struct Main *mainl, BlendHandle **bh, const short idcode, const char *name, const short flag, - struct Scene *scene, struct View3D *v3d); + struct Scene *scene, struct View3D *v3d, + const bool use_placeholders, const bool force_indirect); void BLO_library_link_end(struct Main *mainl, BlendHandle **bh, short flag, struct Scene *scene, struct View3D *v3d); void BLO_library_link_copypaste(struct Main *mainl, BlendHandle *bh); diff --git a/source/blender/blenloader/CMakeLists.txt b/source/blender/blenloader/CMakeLists.txt index 8364df38208..479d3a15e6c 100644 --- a/source/blender/blenloader/CMakeLists.txt +++ b/source/blender/blenloader/CMakeLists.txt @@ -35,6 +35,10 @@ set(INC ../nodes ../render/extern/include ../../../intern/guardedalloc + + # for writefile.c: dna_type_offsets.h + ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern + ) set(INC_SYS @@ -74,3 +78,6 @@ if(WITH_CODEC_FFMPEG) endif() blender_add_lib(bf_blenloader "${SRC}" "${INC}" "${INC_SYS}") + +# needed so writefile.c can use dna_type_offsets.h +add_dependencies(bf_blenloader bf_dna) diff --git a/source/blender/blenloader/intern/readblenentry.c b/source/blender/blenloader/intern/readblenentry.c index 3cae95d418e..be893177b3b 100644 --- a/source/blender/blenloader/intern/readblenentry.c +++ b/source/blender/blenloader/intern/readblenentry.c @@ -411,22 +411,23 @@ BlendFileData *BLO_read_from_memfile(Main *oldmain, const char *filename, MemFil /* Even though directly used libs have been already moved to new main, indirect ones have not. * This is a bit annoying, but we have no choice but to keep them all for now - means some now unused * data may remain in memory, but think we'll have to live with it. */ - Main *libmain; + Main *libmain, *libmain_next; Main *newmain = bfd->main; ListBase new_mainlist = {newmain, newmain}; - for (libmain = oldmain->next; libmain; libmain = libmain->next) { + for (libmain = oldmain->next; libmain; libmain = libmain_next) { + libmain_next = libmain->next; /* Note that LIB_INDIRECT does not work with libraries themselves, so we use non-NULL parent * to detect indirect-linked ones... */ if (libmain->curlib && (libmain->curlib->parent != NULL)) { BLI_remlink(&old_mainlist, libmain); BLI_addtail(&new_mainlist, libmain); } -#if 0 else { +#ifdef PRINT_DEBUG printf("Dropped Main for lib: %s\n", libmain->curlib->id.name); - } #endif + } } /* In any case, we need to move all lib datablocks themselves - those are 'first level data', * getting rid of them would imply updating spaces & co to prevent invalid pointers access. */ diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index a0303e53be4..35903961b72 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -160,53 +160,54 @@ #include <errno.h> -/* - * Remark: still a weak point is the newaddress() function, that doesnt solve reading from - * multiple files at the same time - * - * (added remark: oh, i thought that was solved? will look at that... (ton) - * +/** * READ - * - Existing Library (Main) push or free - * - allocate new Main + * ==== + * + * - Existing Library (#Main) push or free + * - allocate new #Main * - load file - * - read SDNA + * - read #SDNA * - for each LibBlock - * - read LibBlock - * - if a Library - * - make a new Main - * - attach ID's to it - * - else - * - read associated 'direct data' - * - link direct data (internal and to LibBlock) - * - read FileGlobal - * - read USER data, only when indicated (file is ~/X.XX/startup.blend) + * - read LibBlock + * - if a Library + * - make a new #Main + * - attach ID's to it + * - else + * - read associated 'direct data' + * - link direct data (internal and to LibBlock) + * - read #FileGlobal + * - read #USER data, only when indicated (file is ``~/X.XX/startup.blend``) * - free file - * - per Library (per Main) - * - read file - * - read SDNA - * - find LibBlocks and attach IDs to Main - * - if external LibBlock - * - search all Main's - * - or it's already read, - * - or not read yet - * - or make new Main - * - per LibBlock - * - read recursive - * - read associated direct data - * - link direct data (internal and to LibBlock) - * - free file + * - per Library (per #Main) + * - read file + * - read #SDNA + * - find LibBlocks and attach #ID's to #Main + * - if external LibBlock + * - search all #Main's + * - or it's already read, + * - or not read yet + * - or make new #Main + * - per LibBlock + * - read recursive + * - read associated direct data + * - link direct data (internal and to LibBlock) + * - free file * - per Library with unread LibBlocks - * - read file - * - read SDNA - * - per LibBlock - * - read recursive - * - read associated direct data - * - link direct data (internal and to LibBlock) - * - free file - * - join all Mains + * - read file + * - read #SDNA + * - per LibBlock + * - read recursive + * - read associated direct data + * - link direct data (internal and to LibBlock) + * - free file + * - join all #Main's * - link all LibBlocks and indirect pointers to libblocks - * - initialize FileGlobal and copy pointers to Global + * - initialize #FileGlobal and copy pointers to #Global + * + * \note Still a weak point is the new-address function, that doesnt solve reading from + * multiple files at the same time. + * (added remark: oh, i thought that was solved? will look at that... (ton). */ /* use GHash for BHead name-based lookups (speeds up linking) */ @@ -878,8 +879,6 @@ static void decode_blender_header(FileData *fd) if (readsize == sizeof(header)) { if (STREQLEN(header, "BLENDER", 7)) { - int remove_this_endian_test = 1; - fd->flags |= FD_FLAGS_FILE_OK; /* what size are pointers in the file ? */ @@ -898,7 +897,7 @@ static void decode_blender_header(FileData *fd) /* is the file saved in a different endian * than we need ? */ - if (((((char *)&remove_this_endian_test)[0] == 1) ? L_ENDIAN : B_ENDIAN) != ((header[8] == 'v') ? L_ENDIAN : B_ENDIAN)) { + if (((header[8] == 'v') ? L_ENDIAN : B_ENDIAN) != ENDIAN_ORDER) { fd->flags |= FD_FLAGS_SWITCH_ENDIAN; } @@ -910,7 +909,10 @@ static void decode_blender_header(FileData *fd) } } -static int read_file_dna(FileData *fd) +/** + * \return Success if the file is read correctly, else set \a r_error_message. + */ +static bool read_file_dna(FileData *fd, const char **r_error_message) { BHead *bhead; @@ -918,20 +920,25 @@ static int read_file_dna(FileData *fd) if (bhead->code == DNA1) { const bool do_endian_swap = (fd->flags & FD_FLAGS_SWITCH_ENDIAN) != 0; - fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap); + fd->filesdna = DNA_sdna_from_data(&bhead[1], bhead->len, do_endian_swap, true, r_error_message); if (fd->filesdna) { fd->compflags = DNA_struct_get_compareflags(fd->filesdna, fd->memsdna); /* used to retrieve ID names from (bhead+1) */ fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); + + return true; + } + else { + return false; } - return 1; } else if (bhead->code == ENDB) break; } - return 0; + *r_error_message = "Missing DNA block"; + return false; } static int *read_file_thumbnail(FileData *fd) @@ -1073,13 +1080,9 @@ static FileData *filedata_new(void) fd->filedes = -1; fd->gzfiledes = NULL; - - /* XXX, this doesn't need to be done all the time, - * but it keeps us re-entrant, remove once we have - * a lib that provides a nice lock. - zr - */ - fd->memsdna = DNA_sdna_from_data(DNAstr, DNAlen, false); - + + fd->memsdna = DNA_sdna_current_get(); + fd->datamap = oldnewmap_new(); fd->globmap = oldnewmap_new(); fd->libmap = oldnewmap_new(); @@ -1092,8 +1095,11 @@ static FileData *blo_decode_and_check(FileData *fd, ReportList *reports) decode_blender_header(fd); if (fd->flags & FD_FLAGS_FILE_OK) { - if (!read_file_dna(fd)) { - BKE_reportf(reports, RPT_ERROR, "Failed to read blend file '%s', incomplete", fd->relabase); + const char *error_message = NULL; + if (read_file_dna(fd, &error_message) == false) { + BKE_reportf(reports, RPT_ERROR, + "Failed to read blend file '%s': %s", + fd->relabase, error_message); blo_freefiledata(fd); fd = NULL; } @@ -1258,7 +1264,7 @@ void blo_freefiledata(FileData *fd) } if (fd->strm.next_in) { - if (inflateEnd (&fd->strm) != Z_OK) { + if (inflateEnd(&fd->strm) != Z_OK) { printf("close gzip stream error\n"); } } @@ -1270,9 +1276,7 @@ void blo_freefiledata(FileData *fd) // Free all BHeadN data blocks BLI_freelistN(&fd->listbase); - - if (fd->memsdna) - DNA_sdna_free(fd->memsdna); + if (fd->filesdna) DNA_sdna_free(fd->filesdna); if (fd->compflags) @@ -1324,6 +1328,7 @@ bool BLO_has_bfile_extension(const char *str) * * \param path the full path to explode. * \param r_dir the string that'll contain path up to blend file itself ('library' path). + * WARNING! Must be FILE_MAX_LIBEXTRA long (it also stores group and name strings)! * \param r_group the string that'll contain 'group' part of the path, if any. May be NULL. * \param r_name the string that'll contain data's name part of the path, if any. May be NULL. * \return true if path contains a blend file. @@ -1514,6 +1519,15 @@ void *blo_do_versions_newlibadr_us(FileData *fd, const void *lib, const void *ad return newlibadr_us(fd, lib, adr); } +static void *newlibadr_real_us(FileData *fd, const void *lib, const void *adr) /* ensures real user */ +{ + ID *id = newlibadr(fd, lib, adr); + + id_us_ensure_real(id); + + return id; +} + static void change_idid_adr_fd(FileData *fd, const void *old, void *new) { int i; @@ -1835,7 +1849,7 @@ void blo_add_library_pointer_map(ListBase *old_mainlist, FileData *fd) /* ********** END OLD POINTERS ****************** */ /* ********** READ FILE ****************** */ -static void switch_endian_structs(struct SDNA *filesdna, BHead *bhead) +static void switch_endian_structs(const struct SDNA *filesdna, BHead *bhead) { int blocksize, nblocks; char *data; @@ -2130,6 +2144,7 @@ static PreviewImage *direct_link_preview_image(FileData *fd, PreviewImage *old_p } prv->gputexture[i] = NULL; } + prv->icon_id = 0; } return prv; @@ -2175,9 +2190,10 @@ static void lib_link_brush(FileData *fd, Main *main) if (brush->id.tag & LIB_TAG_NEED_LINK) { brush->id.tag &= ~LIB_TAG_NEED_LINK; + /* brush->(mask_)mtex.obj is ignored on purpose? */ brush->mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mtex.tex); brush->mask_mtex.tex = newlibadr_us(fd, brush->id.lib, brush->mask_mtex.tex); - brush->clone.image = newlibadr_us(fd, brush->id.lib, brush->clone.image); + brush->clone.image = newlibadr(fd, brush->id.lib, brush->clone.image); brush->toggle_brush = newlibadr(fd, brush->id.lib, brush->toggle_brush); brush->paint_curve = newlibadr_us(fd, brush->id.lib, brush->paint_curve); } @@ -2697,7 +2713,7 @@ static void lib_link_node_socket(FileData *fd, ID *UNUSED(id), bNodeSocket *sock IDP_LibLinkProperty(sock->prop, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); } -/* singe node tree (also used for material/scene trees), ntree is not NULL */ +/* Single node tree (also used for material/scene trees), ntree is not NULL */ static void lib_link_ntree(FileData *fd, ID *id, bNodeTree *ntree) { bNode *node; @@ -2740,22 +2756,6 @@ static void lib_link_nodetree(FileData *fd, Main *main) } } -/* get node tree stored locally in other IDs */ -static bNodeTree *nodetree_from_id(ID *id) -{ - if (!id) - return NULL; - switch (GS(id->name)) { - case ID_SCE: return ((Scene *)id)->nodetree; - case ID_MA: return ((Material *)id)->nodetree; - case ID_WO: return ((World *)id)->nodetree; - case ID_LA: return ((Lamp *)id)->nodetree; - case ID_TE: return ((Tex *)id)->nodetree; - case ID_LS: return ((FreestyleLineStyle *)id)->nodetree; - } - return NULL; -} - /* updates group node socket identifier so that * external links to/from the group node are preserved. */ @@ -3801,7 +3801,7 @@ static void lib_link_texture(FileData *fd, Main *main) lib_link_animdata(fd, &tex->id, tex->adt); tex->ima = newlibadr_us(fd, tex->id.lib, tex->ima); - tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); + tex->ipo = newlibadr_us(fd, tex->id.lib, tex->ipo); // XXX deprecated - old animation system if (tex->env) tex->env->object = newlibadr(fd, tex->id.lib, tex->env->object); if (tex->pd) @@ -3885,7 +3885,7 @@ static void lib_link_material(FileData *fd, Main *main) * of library blocks that implement this.*/ IDP_LibLinkProperty(ma->id.properties, (fd->flags & FD_FLAGS_SWITCH_ENDIAN), fd); - ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); + ma->ipo = newlibadr_us(fd, ma->id.lib, ma->ipo); // XXX deprecated - old animation system ma->group = newlibadr_us(fd, ma->id.lib, ma->group); for (a = 0; a < MAX_MTEX; a++) { @@ -3954,7 +3954,7 @@ static void direct_link_pointcache_cb(FileData *fd, void *data) /* the cache saves non-struct data without DNA */ if (pm->data[i] && ptcache_data_struct[i][0]=='\0' && (fd->flags & FD_FLAGS_SWITCH_ENDIAN)) { - int tot = (BKE_ptcache_data_size (i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */ + int tot = (BKE_ptcache_data_size(i) * pm->totpoint) / sizeof(int); /* data_size returns bytes */ int *poin = pm->data[i]; BLI_endian_switch_int32_array(poin, tot); @@ -4038,9 +4038,13 @@ static void lib_link_particlesettings(FileData *fd, Main *main) lib_link_partdeflect(fd, &part->id, part->pd); lib_link_partdeflect(fd, &part->id, part->pd2); - if (part->effector_weights) + if (part->effector_weights) { part->effector_weights->group = newlibadr(fd, part->id.lib, part->effector_weights->group); - + } + else { + part->effector_weights = BKE_add_effector_weights(part->eff_group); + } + if (part->dupliweights.first && part->dup_group) { int index_ok = 0; /* check for old files without indices (all indexes 0) */ @@ -4288,8 +4292,7 @@ static void lib_link_mtface(FileData *fd, Mesh *me, MTFace *mtface, int totface) * little bogus; it would be better if each mesh consistently added one ref * to each image it used. - z0r */ for (i = 0; i < totface; i++, tf++) { - tf->tpage= newlibadr(fd, me->id.lib, tf->tpage); - id_us_ensure_real(&tf->tpage->id); + tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage); } } @@ -4317,8 +4320,7 @@ static void lib_link_customdata_mtpoly(FileData *fd, Mesh *me, CustomData *pdata int j; for (j = 0; j < totface; j++, tf++) { - tf->tpage = newlibadr(fd, me->id.lib, tf->tpage); - id_us_ensure_real((ID *)tf->tpage); + tf->tpage = newlibadr_real_us(fd, me->id.lib, tf->tpage); } } } @@ -4868,7 +4870,7 @@ static void lib_link_object(FileData *fd, Main *main) FluidsimModifierData *fluidmd = (FluidsimModifierData *)modifiers_findByType(ob, eModifierType_Fluidsim); if (fluidmd && fluidmd->fss) - fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); + fluidmd->fss->ipo = newlibadr_us(fd, ob->id.lib, fluidmd->fss->ipo); // XXX deprecated - old animation system } { @@ -5608,7 +5610,6 @@ static void lib_link_scene(FileData *fd, Main *main) for (base = sce->base.first; base; base = next) { next = base->next; - /* base->object= newlibadr_us(fd, sce->id.lib, base->object); */ base->object = newlibadr_us(fd, sce->id.lib, base->object); if (base->object == NULL) { @@ -5622,7 +5623,7 @@ static void lib_link_scene(FileData *fd, Main *main) SEQ_BEGIN (sce->ed, seq) { - if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); + if (seq->ipo) seq->ipo = newlibadr_us(fd, sce->id.lib, seq->ipo); // XXX deprecated - old animation system seq->scene_sound = NULL; if (seq->scene) { seq->scene = newlibadr(fd, sce->id.lib, seq->scene); @@ -6262,8 +6263,8 @@ static void lib_link_screen(FileData *fd, Main *main) else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - sima->image = newlibadr_us(fd, sc->id.lib, sima->image); - sima->mask_info.mask = newlibadr_us(fd, sc->id.lib, sima->mask_info.mask); + sima->image = newlibadr_real_us(fd, sc->id.lib, sima->image); + sima->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sima->mask_info.mask); /* NOTE: pre-2.5, this was local data not lib data, but now we need this as lib data * so fingers crossed this works fine! @@ -6330,11 +6331,9 @@ static void lib_link_screen(FileData *fd, Main *main) snode->id = newlibadr(fd, sc->id.lib, snode->id); snode->from = newlibadr(fd, sc->id.lib, snode->from); - ntree = nodetree_from_id(snode->id); - if (ntree) - snode->nodetree = ntree; - else { - snode->nodetree = newlibadr_us(fd, sc->id.lib, snode->nodetree); + if (snode->id) { + ntree = ntreeFromID(snode->id); + snode->nodetree = ntree ? ntree : newlibadr_us(fd, sc->id.lib, snode->nodetree); } for (path = snode->treepath.first; path; path = path->next) { @@ -6369,8 +6368,8 @@ static void lib_link_screen(FileData *fd, Main *main) else if (sl->spacetype == SPACE_CLIP) { SpaceClip *sclip = (SpaceClip *)sl; - sclip->clip = newlibadr_us(fd, sc->id.lib, sclip->clip); - sclip->mask_info.mask = newlibadr_us(fd, sc->id.lib, sclip->mask_info.mask); + sclip->clip = newlibadr_real_us(fd, sc->id.lib, sclip->clip); + sclip->mask_info.mask = newlibadr_real_us(fd, sc->id.lib, sclip->mask_info.mask); } else if (sl->spacetype == SPACE_LOGIC) { SpaceLogic *slogic = (SpaceLogic *)sl; @@ -6435,7 +6434,7 @@ static void *restore_pointer_by_name_main(Main *mainp, ID *id, ePointerUserMode * - USER_IGNORE: no usercount change * - USER_REAL: ensure a real user (even if a fake one is set) * \param id_map: lookup table, use when performing many lookups. - * this could be made an optional agument (falling back to a full lookup), + * this could be made an optional argument (falling back to a full lookup), * however at the moment it's always available. */ static void *restore_pointer_by_name(struct IDNameLib_Map *id_map, ID *id, ePointerUserMode user) @@ -6714,11 +6713,11 @@ void blo_lib_link_screen_restore(Main *newmain, bScreen *curscreen, Scene *cursc snode->id = restore_pointer_by_name(id_map, snode->id, USER_REAL); snode->from = restore_pointer_by_name(id_map, snode->from, USER_IGNORE); - ntree = nodetree_from_id(snode->id); - if (ntree) - snode->nodetree = ntree; - else - snode->nodetree = restore_pointer_by_name(id_map, (ID*)snode->nodetree, USER_REAL); + if (snode->id) { + ntree = ntreeFromID(snode->id); + snode->nodetree = ntree ? ntree : + restore_pointer_by_name(id_map, (ID *)snode->nodetree, USER_REAL); + } for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { @@ -7023,11 +7022,7 @@ static bool direct_link_screen(FileData *fd, bScreen *sc) } else if (sl->spacetype == SPACE_IMAGE) { SpaceImage *sima = (SpaceImage *)sl; - - sima->cumap = newdataadr(fd, sima->cumap); - if (sima->cumap) - direct_link_curvemapping(fd, sima->cumap); - + sima->iuser.scene = NULL; sima->iuser.ok = 1; sima->scopes.waveform_1 = NULL; @@ -7342,12 +7337,11 @@ static void lib_link_group(FileData *fd, Main *main) add_us = false; for (go = group->gobject.first; go; go = go->next) { - go->ob= newlibadr(fd, group->id.lib, go->ob); + go->ob = newlibadr_real_us(fd, group->id.lib, go->ob); if (go->ob) { go->ob->flag |= OB_FROMGROUP; /* if group has an object, it increments user... */ add_us = true; - id_us_ensure_real(&go->ob->id); } } if (add_us) { @@ -7936,16 +7930,22 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short if (fd->memfile && ELEM(bhead->code, ID_LI, ID_ID)) { const char *idname = bhead_id_name(fd, bhead); - /* printf("Checking %s...\n", idname); */ +#ifdef PRINT_DEBUG + printf("Checking %s...\n", idname); +#endif if (bhead->code == ID_LI) { Main *libmain = fd->old_mainlist->first; /* Skip oldmain itself... */ for (libmain = libmain->next; libmain; libmain = libmain->next) { - /* printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); */ +#ifdef PRINT_DEBUG + printf("... against %s: ", libmain->curlib ? libmain->curlib->id.name : "<NULL>"); +#endif if (libmain->curlib && STREQ(idname, libmain->curlib->id.name)) { Main *oldmain = fd->old_mainlist->first; - /* printf("FOUND!\n"); */ +#ifdef PRINT_DEBUG + printf("FOUND!\n"); +#endif /* In case of a library, we need to re-add its main to fd->mainlist, because if we have later * a missing ID_ID, we need to get the correct lib it is linked to! * Order is crucial, we cannot bulk-add it in BLO_read_from_memfile() like it used to be... */ @@ -7959,13 +7959,19 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short } return blo_nextbhead(fd, bhead); } - /* printf("nothing...\n"); */ +#ifdef PRINT_DEBUG + printf("nothing...\n"); +#endif } } else { - /* printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); */ +#ifdef PRINT_DEBUG + printf("... in %s (%s): ", main->curlib ? main->curlib->id.name : "<NULL>", main->curlib ? main->curlib->name : "<NULL>"); +#endif if ((id = BKE_libblock_find_name_ex(main, GS(idname), idname + 2))) { - /* printf("FOUND!\n"); */ +#ifdef PRINT_DEBUG + printf("FOUND!\n"); +#endif /* Even though we found our linked ID, there is no guarantee its address is still the same... */ if (id != bhead->old) { oldnewmap_insert(fd->libmap, bhead->old, id, GS(id->name)); @@ -7977,7 +7983,9 @@ static BHead *read_libblock(FileData *fd, Main *main, BHead *bhead, const short } return blo_nextbhead(fd, bhead); } - /* printf("nothing...\n"); */ +#ifdef PRINT_DEBUG + printf("nothing...\n"); +#endif } } @@ -8491,7 +8499,7 @@ BlendFileData *blo_read_file_internal(FileData *fd, const char *filepath) struct BHeadSort { BHead *bhead; - void *old; + const void *old; }; static int verg_bheadsort(const void *v1, const void *v2) @@ -9686,13 +9694,13 @@ static void give_base_to_groups( } } -static ID *create_placeholder(Main *mainvar, const char *idname, const short tag) +static ID *create_placeholder(Main *mainvar, const short idcode, const char *idname, const short tag) { - const short idcode = GS(idname); ListBase *lb = which_libbase(mainvar, idcode); ID *ph_id = BKE_libblock_alloc_notest(idcode); - memcpy(ph_id->name, idname, sizeof(ph_id->name)); + *((short *)ph_id->name) = idcode; + BLI_strncpy(ph_id->name + 2, idname, sizeof(ph_id->name) - 2); BKE_libblock_init_empty(ph_id); ph_id->lib = mainvar->curlib; ph_id->tag = tag | LIB_TAG_MISSING; @@ -9707,7 +9715,9 @@ static ID *create_placeholder(Main *mainvar, const char *idname, const short tag /* returns true if the item was found * but it may already have already been appended/linked */ -static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const char *name) +static ID *link_named_part( + Main *mainl, FileData *fd, const short idcode, const char *name, + const bool use_placeholders, const bool force_indirect) { BHead *bhead = find_bhead_from_code_name(fd, idcode, name); ID *id; @@ -9718,7 +9728,7 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const id = is_yet_read(fd, mainl, bhead); if (id == NULL) { /* not read yet */ - read_libblock(fd, mainl, bhead, LIB_TAG_TESTEXT, &id); + read_libblock(fd, mainl, bhead, force_indirect ? LIB_TAG_TESTIND : LIB_TAG_TESTEXT, &id); if (id) { /* sort by name in list */ @@ -9731,18 +9741,22 @@ static ID *link_named_part(Main *mainl, FileData *fd, const short idcode, const if (G.debug) printf("append: already linked\n"); oldnewmap_insert(fd->libmap, bhead->old, id, bhead->code); - if (id->tag & LIB_TAG_INDIRECT) { + if (!force_indirect && (id->tag & LIB_TAG_INDIRECT)) { id->tag &= ~LIB_TAG_INDIRECT; id->tag |= LIB_TAG_EXTERN; } } } + else if (use_placeholders) { + /* XXX flag part is weak! */ + id = create_placeholder(mainl, idcode, name, force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN); + } else { id = NULL; } /* if we found the id but the id is NULL, this is really bad */ - BLI_assert((bhead != NULL) == (id != NULL)); + BLI_assert(!((bhead != NULL) && (id == NULL))); return id; } @@ -9814,9 +9828,9 @@ void BLO_library_link_copypaste(Main *mainl, BlendHandle *bh) static ID *link_named_part_ex( Main *mainl, FileData *fd, const short idcode, const char *name, const short flag, - Scene *scene, View3D *v3d) + Scene *scene, View3D *v3d, const bool use_placeholders, const bool force_indirect) { - ID *id = link_named_part(mainl, fd, idcode, name); + ID *id = link_named_part(mainl, fd, idcode, name, use_placeholders, force_indirect); if (id && (GS(id->name) == ID_OB)) { /* loose object: give a base */ link_object_postprocess(id, scene, v3d, flag); @@ -9842,7 +9856,7 @@ static ID *link_named_part_ex( ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcode, const char *name) { FileData *fd = (FileData*)(*bh); - return link_named_part(mainl, fd, idcode, name); + return link_named_part(mainl, fd, idcode, name, false, false); } /** @@ -9856,15 +9870,18 @@ ID *BLO_library_link_named_part(Main *mainl, BlendHandle **bh, const short idcod * \param flag Options for linking, used for instantiating. * \param scene The scene in which to instantiate objects/groups (if NULL, no instantiation is done). * \param v3d The active View3D (only to define active layers for instantiated objects & groups, can be NULL). + * \param use_placeholders If true, generate a placeholder (empty ID) if not found in current lib file. + * \param force_indirect If true, force loaded ID to be tagged as LIB_TAG_INDIRECT (used in reload context only). * \return the linked ID when found. */ ID *BLO_library_link_named_part_ex( Main *mainl, BlendHandle **bh, const short idcode, const char *name, const short flag, - Scene *scene, View3D *v3d) + Scene *scene, View3D *v3d, + const bool use_placeholders, const bool force_indirect) { FileData *fd = (FileData*)(*bh); - return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d); + return link_named_part_ex(mainl, fd, idcode, name, flag, scene, v3d, use_placeholders, force_indirect); } static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *id, ID **r_id) @@ -9904,7 +9921,7 @@ static void link_id_part(ReportList *reports, FileData *fd, Main *mainvar, ID *i /* Generate a placeholder for this ID (simplified version of read_libblock actually...). */ if (r_id) { - *r_id = is_valid ? create_placeholder(mainvar, id->name, id->tag) : NULL; + *r_id = is_valid ? create_placeholder(mainvar, GS(id->name), id->name + 2, id->tag) : NULL; } } } diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index 42728fd406f..b054cd0031d 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -74,7 +74,7 @@ typedef struct FileData { // general reading variables struct SDNA *filesdna; - struct SDNA *memsdna; + const struct SDNA *memsdna; char *compflags; /* array of eSDNA_StructCompare */ int fileversion; diff --git a/source/blender/blenloader/intern/undofile.c b/source/blender/blenloader/intern/undofile.c index d0dc9a88cc0..c191e48a143 100644 --- a/source/blender/blenloader/intern/undofile.c +++ b/source/blender/blenloader/intern/undofile.c @@ -80,20 +80,6 @@ void BLO_memfile_merge(MemFile *first, MemFile *second) BLO_memfile_free(first); } -static int my_memcmp(const int *mem1, const int *mem2, const int len) -{ - register int a = len; - register const int *mema = mem1; - register const int *memb = mem2; - - while (a--) { - if (*mema != *memb) return 1; - mema++; - memb++; - } - return 0; -} - void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsigned int size) { static MemFileChunk *compchunk = NULL; @@ -118,7 +104,7 @@ void memfile_chunk_add(MemFile *compare, MemFile *current, const char *buf, unsi /* we compare compchunk with buf */ if (compchunk) { if (compchunk->size == curchunk->size) { - if (my_memcmp((int *)compchunk->buf, (const int *)buf, size / 4) == 0) { + if (memcmp(compchunk->buf, buf, size) == 0) { curchunk->buf = compchunk->buf; curchunk->ident = 1; } diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index aa18859fa4c..dbbdc30c23e 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -1101,6 +1101,8 @@ void blo_do_versions_250(FileData *fd, Library *lib, Main *main) sce->gm.flag |= GAME_GLSL_NO_NODES; if (fd->fileflags & G_FILE_GLSL_NO_EXTRA_TEX) sce->gm.flag |= GAME_GLSL_NO_EXTRA_TEX; + if (fd->fileflags & G_FILE_GLSL_NO_ENV_LIGHTING) + sce->gm.flag |= GAME_GLSL_NO_ENV_LIGHTING; if (fd->fileflags & G_FILE_IGNORE_DEPRECATION_WARNINGS) sce->gm.flag |= GAME_IGNORE_DEPRECATION_WARNINGS; diff --git a/source/blender/blenloader/intern/versioning_270.c b/source/blender/blenloader/intern/versioning_270.c index b7b6ace3c1a..ac2811aeb06 100644 --- a/source/blender/blenloader/intern/versioning_270.c +++ b/source/blender/blenloader/intern/versioning_270.c @@ -1212,5 +1212,18 @@ void blo_do_versions_270(FileData *fd, Library *UNUSED(lib), Main *main) } } } + + if (!DNA_struct_elem_find(fd->filesdna, "BooleanModifierData", "float", "double_threshold")) { + Object *ob; + for (ob = main->object.first; ob; ob = ob->id.next) { + ModifierData *md; + for (md = ob->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Boolean) { + BooleanModifierData *bmd = (BooleanModifierData *)md; + bmd->double_threshold = 1e-6f; + } + } + } + } } } diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 45f4e59f86d..379e52c925b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -29,15 +29,22 @@ */ -/* - * FILEFORMAT: IFF-style structure (but not IFF compatible!) +/** + * + * FILE FORMAT + * =========== + * + * IFF-style structure (but not IFF compatible!) * * start file: + * <pre> * BLENDER_V100 12 bytes (versie 1.00) * V = big endian, v = little endian * _ = 4 byte pointer, - = 8 byte pointer + * </pre> * - * datablocks: also see struct BHead + * datablocks: (also see struct #BHead). + * <pre> * <bh.code> 4 chars * <bh.len> int, len data after BHead * <bh.old> void, old pointer @@ -46,29 +53,32 @@ * data * ... * ... + * </pre> * * Almost all data in Blender are structures. Each struct saved * gets a BHead header. With BHead the struct can be linked again * and compared with StructDNA . * + * * WRITE + * ===== * * Preferred writing order: (not really a must, but why would you do it random?) * Any case: direct data is ALWAYS after the lib block * * (Local file data) * - for each LibBlock - * - write LibBlock - * - write associated direct data + * - write LibBlock + * - write associated direct data * (External file data) * - per library - * - write library block - * - per LibBlock - * - write the ID of LibBlock - * - write TEST (128x128, blend file preview, optional) - * - write FileGlobal (some global vars) - * - write SDNA - * - write USER if filename is ~/X.XX/config/startup.blend + * - write library block + * - per LibBlock + * - write the ID of LibBlock + * - write #TEST (#RenderInfo struct. 128x128 blend file preview is optional). + * - write #GLOB (#FileGlobal struct) (some global vars). + * - write #DNA1 (#SDNA struct) + * - write #USER (#UserDef struct) if filename is ``~/X.XX/config/startup.blend``. */ @@ -163,7 +173,7 @@ #include "BKE_mesh.h" #ifdef USE_NODE_COMPAT_CUSTOMNODES -#include "NOD_socket.h" /* for sock->default_value data */ +#include "NOD_socket.h" /* for sock->default_value data */ #endif @@ -174,13 +184,16 @@ #include "readfile.h" +/* for SDNA_TYPE_FROM_STRUCT() macro */ +#include "dna_type_offsets.h" + #include <errno.h> /* ********* my write, buffered writing with minimum size chunks ************ */ -#define MYWRITE_BUFFER_SIZE 100000 -#define MYWRITE_MAX_CHUNK 32768 - +/* Use optimal allocation since blocks of this size are kept in memory for undo. */ +#define MYWRITE_BUFFER_SIZE (MEM_SIZE_OPTIMAL(1 << 17)) /* 128kb */ +#define MYWRITE_MAX_CHUNK (MEM_SIZE_OPTIMAL(1 << 15)) /* ~32kb */ /** \name Small API to handle compression. @@ -290,12 +303,13 @@ static void ww_handle_init(eWriteWrapType ww_type, WriteWrap *r_ww) typedef struct { - struct SDNA *sdna; + const struct SDNA *sdna; unsigned char *buf; MemFile *compare, *current; - - int tot, count, error; + + int tot, count; + bool error; /* Wrap writing, so we can use zlib or * other compression types later, see: G_FILE_COMPRESS @@ -303,33 +317,32 @@ typedef struct { WriteWrap *ww; #ifdef USE_BMESH_SAVE_AS_COMPAT - char use_mesh_compat; /* option to save with older mesh format */ + bool use_mesh_compat; /* option to save with older mesh format */ #endif } WriteData; static WriteData *writedata_new(WriteWrap *ww) { - WriteData *wd= MEM_callocN(sizeof(*wd), "writedata"); - - /* XXX, see note about this in readfile.c, remove - * once we have an xp lock - zr - */ + WriteData *wd = MEM_callocN(sizeof(*wd), "writedata"); - if (wd == NULL) return NULL; - - wd->sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); + wd->sdna = DNA_sdna_current_get(); wd->ww = ww; - wd->buf= MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf"); + wd->buf = MEM_mallocN(MYWRITE_BUFFER_SIZE, "wd->buf"); return wd; } static void writedata_do_write(WriteData *wd, const void *mem, int memlen) { - if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) return; - if (wd->error) return; + if ((wd == NULL) || wd->error || (mem == NULL) || memlen < 1) { + return; + } + + if (UNLIKELY(wd->error)) { + return; + } /* memory based save */ if (wd->current) { @@ -337,15 +350,13 @@ static void writedata_do_write(WriteData *wd, const void *mem, int memlen) } else { if (wd->ww->write(wd->ww, mem, memlen) != memlen) { - wd->error = 1; + wd->error = true; } } } static void writedata_free(WriteData *wd) { - DNA_sdna_free(wd->sdna); - MEM_freeN(wd->buf); MEM_freeN(wd); } @@ -353,39 +364,46 @@ static void writedata_free(WriteData *wd) /***/ /** + * Flush helps the de-duplicating memory for undo-save by logically segmenting data, + * so differences in one part of memory won't cause unrelated data to be duplicated. + */ +static void mywrite_flush(WriteData *wd) +{ + if (wd->count) { + writedata_do_write(wd, wd->buf, wd->count); + wd->count = 0; + } +} + +/** * Low level WRITE(2) wrapper that buffers data * \param adr Pointer to new chunk of data * \param len Length of new chunk of data * \warning Talks to other functions with global parameters */ - -#define MYWRITE_FLUSH NULL - static void mywrite(WriteData *wd, const void *adr, int len) { - if (wd->error) return; + if (UNLIKELY(wd->error)) { + return; + } - /* flush helps compression for undo-save */ - if (adr==MYWRITE_FLUSH) { - if (wd->count) { - writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; - } + if (adr == NULL) { + BLI_assert(0); return; } - wd->tot+= len; - + wd->tot += len; + /* if we have a single big chunk, write existing data in * buffer and write out big chunk in smaller pieces */ - if (len>MYWRITE_MAX_CHUNK) { + if (len > MYWRITE_MAX_CHUNK) { if (wd->count) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } do { - int writelen= MIN2(len, MYWRITE_MAX_CHUNK); + int writelen = MIN2(len, MYWRITE_MAX_CHUNK); writedata_do_write(wd, adr, writelen); adr = (const char *)adr + writelen; len -= writelen; @@ -395,14 +413,14 @@ static void mywrite(WriteData *wd, const void *adr, int len) } /* if data would overflow buffer, write out the buffer */ - if (len+wd->count>MYWRITE_BUFFER_SIZE-1) { + if (len + wd->count > MYWRITE_BUFFER_SIZE - 1) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } /* append data at end of buffer */ memcpy(&wd->buf[wd->count], adr, len); - wd->count+= len; + wd->count += len; } /** @@ -414,15 +432,17 @@ static void mywrite(WriteData *wd, const void *adr, int len) */ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current) { - WriteData *wd= writedata_new(ww); + WriteData *wd = writedata_new(ww); - if (wd == NULL) return NULL; + if (wd == NULL) { + return NULL; + } - wd->compare= compare; - wd->current= current; + wd->compare = compare; + wd->current = current; /* this inits comparing */ memfile_chunk_add(compare, NULL, NULL, 0); - + return wd; } @@ -432,16 +452,14 @@ static WriteData *bgnwrite(WriteWrap *ww, MemFile *compare, MemFile *current) * \return unknown global variable otherwise * \warning Talks to other functions with global parameters */ -static int endwrite(WriteData *wd) +static bool endwrite(WriteData *wd) { - int err; - if (wd->count) { writedata_do_write(wd, wd->buf, wd->count); - wd->count= 0; + wd->count = 0; } - - err= wd->error; + + const bool err = wd->error; writedata_free(wd); return err; @@ -449,51 +467,82 @@ static int endwrite(WriteData *wd) /* ********** WRITE FILE ****************** */ -static void writestruct_at_address(WriteData *wd, int filecode, const char *structname, int nr, void *adr, void *data) +static void writestruct_at_address_nr( + WriteData *wd, int filecode, const int struct_nr, int nr, + const void *adr, const void *data) { BHead bh; const short *sp; - if (adr==NULL || data==NULL || nr==0) return; - - /* init BHead */ - bh.code= filecode; - bh.old= adr; - bh.nr= nr; + BLI_assert(struct_nr > 0 && struct_nr < SDNA_TYPE_MAX); - bh.SDNAnr= DNA_struct_find_nr(wd->sdna, structname); - if (bh.SDNAnr== -1) { - printf("error: can't find SDNA code <%s>\n", structname); + if (adr == NULL || data == NULL || nr == 0) { return; } - sp= wd->sdna->structs[bh.SDNAnr]; - bh.len= nr*wd->sdna->typelens[sp[0]]; + /* init BHead */ + bh.code = filecode; + bh.old = adr; + bh.nr = nr; - if (bh.len==0) return; + bh.SDNAnr = struct_nr; + sp = wd->sdna->structs[bh.SDNAnr]; + + bh.len = nr * wd->sdna->typelens[sp[0]]; + + if (bh.len == 0) { + return; + } mywrite(wd, &bh, sizeof(BHead)); mywrite(wd, data, bh.len); } -static void writestruct(WriteData *wd, int filecode, const char *structname, int nr, void *adr) +static void writestruct_at_address_id( + WriteData *wd, int filecode, const char *structname, int nr, + const void *adr, const void *data) +{ + if (adr == NULL || data == NULL || nr == 0) { + return; + } + + const int SDNAnr = DNA_struct_find_nr(wd->sdna, structname); + if (UNLIKELY(SDNAnr == -1)) { + printf("error: can't find SDNA code <%s>\n", structname); + return; + } + + writestruct_at_address_nr(wd, filecode, SDNAnr, nr, adr, data); +} + +static void writestruct_nr( + WriteData *wd, int filecode, const int struct_nr, int nr, + const void *adr) +{ + writestruct_at_address_nr(wd, filecode, struct_nr, nr, adr, adr); +} + +static void writestruct_id( + WriteData *wd, int filecode, const char *structname, int nr, + const void *adr) { - writestruct_at_address(wd, filecode, structname, nr, adr, adr); + writestruct_at_address_id(wd, filecode, structname, nr, adr, adr); } static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* do not use for structs */ { BHead bh; - if (adr==NULL) return; - if (len==0) return; + if (adr == NULL || len == 0) { + return; + } /* align to 4 (writes uninitialized bytes in some cases) */ len = (len + 3) & ~3; /* init BHead */ bh.code = filecode; - bh.old = (void *)adr; /* this is safe to cast from const */ + bh.old = adr; bh.nr = 1; bh.SDNAnr = 0; bh.len = len; @@ -503,68 +552,99 @@ static void writedata(WriteData *wd, int filecode, int len, const void *adr) /* } /* use this to force writing of lists in same order as reading (using link_list) */ -static void writelist(WriteData *wd, int filecode, const char *structname, ListBase *lb) +static void writelist_nr(WriteData *wd, int filecode, const int struct_nr, const ListBase *lb) { - Link *link = lb->first; - + const Link *link = lb->first; + while (link) { - writestruct(wd, filecode, structname, 1, link); + writestruct_nr(wd, filecode, struct_nr, 1, link); link = link->next; } } +#if 0 +static void writelist_id(WriteData *wd, int filecode, const char *structname, const ListBase *lb) +{ + const Link *link = lb->first; + if (link) { + + const int struct_nr = DNA_struct_find_nr(wd->sdna, structname); + if (struct_nr == -1) { + printf("error: can't find SDNA code <%s>\n", structname); + return; + } + + while (link) { + writestruct_nr(wd, filecode, struct_nr, 1, link); + link = link->next; + } + } +} +#endif + +#define writestruct_at_address(wd, filecode, struct_id, nr, adr, data) \ + writestruct_at_address_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr, data) + +#define writestruct(wd, filecode, struct_id, nr, adr) \ + writestruct_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), nr, adr) + +#define writelist(wd, filecode, struct_id, lb) \ + writelist_nr(wd, filecode, SDNA_TYPE_FROM_STRUCT(struct_id), lb) + /* *************** writing some direct data structs used in more code parts **************** */ /*These functions are used by blender's .blend system for file saving/loading.*/ -void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd); -void IDP_WriteProperty(IDProperty *prop, void *wd); +void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd); +void IDP_WriteProperty(const IDProperty *prop, void *wd); -static void IDP_WriteArray(IDProperty *prop, void *wd) +static void IDP_WriteArray(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { writedata(wd, DATA, MEM_allocN_len(prop->data.pointer), prop->data.pointer); if (prop->subtype == IDP_GROUP) { - IDProperty **array= prop->data.pointer; + IDProperty **array = prop->data.pointer; int a; - for (a=0; a<prop->len; a++) + for (a = 0; a < prop->len; a++) { IDP_WriteProperty(array[a], wd); + } } } } -static void IDP_WriteIDPArray(IDProperty *prop, void *wd) +static void IDP_WriteIDPArray(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { - IDProperty *array = prop->data.pointer; + const IDProperty *array = prop->data.pointer; int a; - writestruct(wd, DATA, "IDProperty", prop->len, array); + writestruct(wd, DATA, IDProperty, prop->len, array); - for (a=0; a<prop->len; a++) + for (a = 0; a < prop->len; a++) { IDP_WriteProperty_OnlyData(&array[a], wd); + } } } -static void IDP_WriteString(IDProperty *prop, void *wd) +static void IDP_WriteString(const IDProperty *prop, void *wd) { /*REMEMBER to set totalen to len in the linking code!!*/ writedata(wd, DATA, prop->len, prop->data.pointer); } -static void IDP_WriteGroup(IDProperty *prop, void *wd) +static void IDP_WriteGroup(const IDProperty *prop, void *wd) { IDProperty *loop; - for (loop=prop->data.group.first; loop; loop=loop->next) { + for (loop = prop->data.group.first; loop; loop = loop->next) { IDP_WriteProperty(loop, wd); } } /* Functions to read/write ID Properties */ -void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd) +void IDP_WriteProperty_OnlyData(const IDProperty *prop, void *wd) { switch (prop->type) { case IDP_GROUP: @@ -582,13 +662,13 @@ void IDP_WriteProperty_OnlyData(IDProperty *prop, void *wd) } } -void IDP_WriteProperty(IDProperty *prop, void *wd) +void IDP_WriteProperty(const IDProperty *prop, void *wd) { - writestruct(wd, DATA, "IDProperty", 1, prop); + writestruct(wd, DATA, IDProperty, 1, prop); IDP_WriteProperty_OnlyData(prop, wd); } -static void write_iddata(void *wd, ID *id) +static void write_iddata(void *wd, const ID *id) { /* ID_WM's id->properties are considered runtime only, and never written in .blend file. */ if (id->properties && !ELEM(GS(id->name), ID_WM)) { @@ -596,29 +676,24 @@ static void write_iddata(void *wd, ID *id) } } -static void write_previews(WriteData *wd, PreviewImage *prv) +static void write_previews(WriteData *wd, const PreviewImage *prv_orig) { /* Never write previews when doing memsave (i.e. undo/redo)! */ - if (prv && !wd->current) { - short w = prv->w[1]; - short h = prv->h[1]; - unsigned int *rect = prv->rect[1]; + if (prv_orig && !wd->current) { + PreviewImage prv = *prv_orig; /* don't write out large previews if not requested */ if (!(U.flag & USER_SAVE_PREVIEWS)) { - prv->w[1] = 0; - prv->h[1] = 0; - prv->rect[1] = NULL; + prv.w[1] = 0; + prv.h[1] = 0; + prv.rect[1] = NULL; } - writestruct(wd, DATA, "PreviewImage", 1, prv); - if (prv->rect[0]) writedata(wd, DATA, prv->w[0] * prv->h[0] * sizeof(unsigned int), prv->rect[0]); - if (prv->rect[1]) writedata(wd, DATA, prv->w[1] * prv->h[1] * sizeof(unsigned int), prv->rect[1]); - - /* restore preview, we still want to keep it in memory even if not saved to file */ - if (!(U.flag & USER_SAVE_PREVIEWS) ) { - prv->w[1] = w; - prv->h[1] = h; - prv->rect[1] = rect; + writestruct_at_address(wd, DATA, PreviewImage, 1, prv_orig, &prv); + if (prv.rect[0]) { + writedata(wd, DATA, prv.w[0] * prv.h[0] * sizeof(unsigned int), prv.rect[0]); + } + if (prv.rect[1]) { + writedata(wd, DATA, prv.w[1] * prv.h[1] * sizeof(unsigned int), prv.rect[1]); } } } @@ -626,45 +701,47 @@ static void write_previews(WriteData *wd, PreviewImage *prv) static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) { FModifier *fcm; - + /* Write all modifiers first (for faster reloading) */ - writelist(wd, DATA, "FModifier", fmodifiers); - + writelist(wd, DATA, FModifier, fmodifiers); + /* Modifiers */ - for (fcm= fmodifiers->first; fcm; fcm= fcm->next) { - const FModifierTypeInfo *fmi= fmodifier_get_typeinfo(fcm); - + for (fcm = fmodifiers->first; fcm; fcm = fcm->next) { + const FModifierTypeInfo *fmi = fmodifier_get_typeinfo(fcm); + /* Write the specific data */ if (fmi && fcm->data) { /* firstly, just write the plain fmi->data struct */ - writestruct(wd, DATA, fmi->structName, 1, fcm->data); - + writestruct_id(wd, DATA, fmi->structName, 1, fcm->data); + /* do any modifier specific stuff */ switch (fcm->type) { case FMODIFIER_TYPE_GENERATOR: { - FMod_Generator *data= (FMod_Generator *)fcm->data; - + FMod_Generator *data = fcm->data; + /* write coefficients array */ - if (data->coefficients) - writedata(wd, DATA, sizeof(float)*(data->arraysize), data->coefficients); + if (data->coefficients) { + writedata(wd, DATA, sizeof(float) * (data->arraysize), data->coefficients); + } break; } case FMODIFIER_TYPE_ENVELOPE: { - FMod_Envelope *data= (FMod_Envelope *)fcm->data; - + FMod_Envelope *data = fcm->data; + /* write envelope data */ - if (data->data) - writestruct(wd, DATA, "FCM_EnvelopeData", data->totvert, data->data); + if (data->data) { + writestruct(wd, DATA, FCM_EnvelopeData, data->totvert, data->data); + } break; } case FMODIFIER_TYPE_PYTHON: { - FMod_Python *data = (FMod_Python *)fcm->data; - + FMod_Python *data = fcm->data; + /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ IDP_WriteProperty(data->prop, wd); @@ -679,37 +756,41 @@ static void write_fmodifiers(WriteData *wd, ListBase *fmodifiers) static void write_fcurves(WriteData *wd, ListBase *fcurves) { FCurve *fcu; - - writelist(wd, DATA, "FCurve", fcurves); - for (fcu=fcurves->first; fcu; fcu=fcu->next) { + + writelist(wd, DATA, FCurve, fcurves); + for (fcu = fcurves->first; fcu; fcu = fcu->next) { /* curve data */ - if (fcu->bezt) - writestruct(wd, DATA, "BezTriple", fcu->totvert, fcu->bezt); - if (fcu->fpt) - writestruct(wd, DATA, "FPoint", fcu->totvert, fcu->fpt); - - if (fcu->rna_path) - writedata(wd, DATA, strlen(fcu->rna_path)+1, fcu->rna_path); - + if (fcu->bezt) { + writestruct(wd, DATA, BezTriple, fcu->totvert, fcu->bezt); + } + if (fcu->fpt) { + writestruct(wd, DATA, FPoint, fcu->totvert, fcu->fpt); + } + + if (fcu->rna_path) { + writedata(wd, DATA, strlen(fcu->rna_path) + 1, fcu->rna_path); + } + /* driver data */ if (fcu->driver) { - ChannelDriver *driver= fcu->driver; + ChannelDriver *driver = fcu->driver; DriverVar *dvar; - - writestruct(wd, DATA, "ChannelDriver", 1, driver); - + + writestruct(wd, DATA, ChannelDriver, 1, driver); + /* variables */ - writelist(wd, DATA, "DriverVar", &driver->variables); - for (dvar= driver->variables.first; dvar; dvar= dvar->next) { + writelist(wd, DATA, DriverVar, &driver->variables); + for (dvar = driver->variables.first; dvar; dvar = dvar->next) { DRIVER_TARGETS_USED_LOOPER(dvar) { - if (dtar->rna_path) - writedata(wd, DATA, strlen(dtar->rna_path)+1, dtar->rna_path); + if (dtar->rna_path) { + writedata(wd, DATA, strlen(dtar->rna_path) + 1, dtar->rna_path); + } } DRIVER_TARGETS_LOOPER_END } } - + /* write F-Modifiers */ write_fmodifiers(wd, &fcu->modifiers); } @@ -717,47 +798,47 @@ static void write_fcurves(WriteData *wd, ListBase *fcurves) static void write_actions(WriteData *wd, ListBase *idbase) { - bAction *act; + bAction *act; bActionGroup *grp; TimeMarker *marker; - - for (act=idbase->first; act; act= act->id.next) { - if (act->id.us>0 || wd->current) { - writestruct(wd, ID_AC, "bAction", 1, act); + + for (act = idbase->first; act; act = act->id.next) { + if (act->id.us > 0 || wd->current) { + writestruct(wd, ID_AC, bAction, 1, act); write_iddata(wd, &act->id); write_fcurves(wd, &act->curves); - - for (grp=act->groups.first; grp; grp=grp->next) { - writestruct(wd, DATA, "bActionGroup", 1, grp); + + for (grp = act->groups.first; grp; grp = grp->next) { + writestruct(wd, DATA, bActionGroup, 1, grp); } - - for (marker=act->markers.first; marker; marker=marker->next) { - writestruct(wd, DATA, "TimeMarker", 1, marker); + + for (marker = act->markers.first; marker; marker = marker->next) { + writestruct(wd, DATA, TimeMarker, 1, marker); } } } - - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + + mywrite_flush(wd); } static void write_keyingsets(WriteData *wd, ListBase *list) { KeyingSet *ks; KS_Path *ksp; - - for (ks= list->first; ks; ks= ks->next) { + + for (ks = list->first; ks; ks = ks->next) { /* KeyingSet */ - writestruct(wd, DATA, "KeyingSet", 1, ks); - + writestruct(wd, DATA, KeyingSet, 1, ks); + /* Paths */ - for (ksp= ks->paths.first; ksp; ksp= ksp->next) { + for (ksp = ks->paths.first; ksp; ksp = ksp->next) { /* Path */ - writestruct(wd, DATA, "KS_Path", 1, ksp); - - if (ksp->rna_path) - writedata(wd, DATA, strlen(ksp->rna_path)+1, ksp->rna_path); + writestruct(wd, DATA, KS_Path, 1, ksp); + + if (ksp->rna_path) { + writedata(wd, DATA, strlen(ksp->rna_path) + 1, ksp->rna_path); + } } } } @@ -765,13 +846,13 @@ static void write_keyingsets(WriteData *wd, ListBase *list) static void write_nlastrips(WriteData *wd, ListBase *strips) { NlaStrip *strip; - - writelist(wd, DATA, "NlaStrip", strips); - for (strip= strips->first; strip; strip= strip->next) { + + writelist(wd, DATA, NlaStrip, strips); + for (strip = strips->first; strip; strip = strip->next) { /* write the strip's F-Curves and modifiers */ write_fcurves(wd, &strip->fcurves); write_fmodifiers(wd, &strip->modifiers); - + /* write the strip's children */ write_nlastrips(wd, &strip->strips); } @@ -780,12 +861,12 @@ static void write_nlastrips(WriteData *wd, ListBase *strips) static void write_nladata(WriteData *wd, ListBase *nlabase) { NlaTrack *nlt; - + /* write all the tracks */ - for (nlt= nlabase->first; nlt; nlt= nlt->next) { + for (nlt = nlabase->first; nlt; nlt = nlt->next) { /* write the track first */ - writestruct(wd, DATA, "NlaTrack", 1, nlt); - + writestruct(wd, DATA, NlaTrack, 1, nlt); + /* write the track's strips */ write_nlastrips(wd, &nlt->strips); } @@ -794,38 +875,37 @@ static void write_nladata(WriteData *wd, ListBase *nlabase) static void write_animdata(WriteData *wd, AnimData *adt) { AnimOverride *aor; - + /* firstly, just write the AnimData block */ - writestruct(wd, DATA, "AnimData", 1, adt); - + writestruct(wd, DATA, AnimData, 1, adt); + /* write drivers */ write_fcurves(wd, &adt->drivers); - + /* write overrides */ // FIXME: are these needed? - for (aor= adt->overrides.first; aor; aor= aor->next) { + for (aor = adt->overrides.first; aor; aor = aor->next) { /* overrides consist of base data + rna_path */ - writestruct(wd, DATA, "AnimOverride", 1, aor); - writedata(wd, DATA, strlen(aor->rna_path)+1, aor->rna_path); + writestruct(wd, DATA, AnimOverride, 1, aor); + writedata(wd, DATA, strlen(aor->rna_path) + 1, aor->rna_path); } - + // TODO write the remaps (if they are needed) - + /* write NLA data */ write_nladata(wd, &adt->nla_tracks); } static void write_curvemapping_curves(WriteData *wd, CurveMapping *cumap) { - int a; - - for (a = 0; a < CM_TOT; a++) - writestruct(wd, DATA, "CurveMapPoint", cumap->cm[a].totpoint, cumap->cm[a].curve); + for (int a = 0; a < CM_TOT; a++) { + writestruct(wd, DATA, CurveMapPoint, cumap->cm[a].totpoint, cumap->cm[a].curve); + } } static void write_curvemapping(WriteData *wd, CurveMapping *cumap) { - writestruct(wd, DATA, "CurveMapping", 1, cumap); + writestruct(wd, DATA, CurveMapping, 1, cumap); write_curvemapping_curves(wd, cumap); } @@ -835,14 +915,14 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no #ifdef USE_NODE_COMPAT_CUSTOMNODES /* forward compatibility code, so older blenders still open */ sock->stack_type = 1; - + if (node->type == NODE_GROUP) { bNodeTree *ngroup = (bNodeTree *)node->id; if (ngroup) { /* for node groups: look up the deprecated groupsock pointer */ sock->groupsock = ntreeFindSocketInterface(ngroup, sock->in_out, sock->identifier); BLI_assert(sock->groupsock != NULL); - + /* node group sockets now use the generic identifier string to verify group nodes, * old blender uses the own_index. */ @@ -852,20 +932,22 @@ static void write_node_socket(WriteData *wd, bNodeTree *UNUSED(ntree), bNode *no #endif /* actual socket writing */ - writestruct(wd, DATA, "bNodeSocket", 1, sock); + writestruct(wd, DATA, bNodeSocket, 1, sock); - if (sock->prop) + if (sock->prop) { IDP_WriteProperty(sock->prop, wd); - - if (sock->default_value) + } + + if (sock->default_value) { writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value); + } } static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), bNodeSocket *sock) { #ifdef USE_NODE_COMPAT_CUSTOMNODES /* forward compatibility code, so older blenders still open */ sock->stack_type = 1; - + /* Reconstruct the deprecated default_value structs in socket interface DNA. */ if (sock->default_value == NULL && sock->typeinfo) { node_socket_init_default_value(sock); @@ -873,13 +955,15 @@ static void write_node_socket_interface(WriteData *wd, bNodeTree *UNUSED(ntree), #endif /* actual socket writing */ - writestruct(wd, DATA, "bNodeSocket", 1, sock); + writestruct(wd, DATA, bNodeSocket, 1, sock); - if (sock->prop) + if (sock->prop) { IDP_WriteProperty(sock->prop, wd); - - if (sock->default_value) + } + + if (sock->default_value) { writedata(wd, DATA, MEM_allocN_len(sock->default_value), sock->default_value); + } } /* this is only direct data, tree itself should have been written */ static void write_nodetree(WriteData *wd, bNodeTree *ntree) @@ -887,62 +971,86 @@ static void write_nodetree(WriteData *wd, bNodeTree *ntree) bNode *node; bNodeSocket *sock; bNodeLink *link; - + /* for link_list() speed, we write per list */ - - if (ntree->adt) write_animdata(wd, ntree->adt); - + + if (ntree->adt) { + write_animdata(wd, ntree->adt); + } + for (node = ntree->nodes.first; node; node = node->next) { - writestruct(wd, DATA, "bNode", 1, node); + writestruct(wd, DATA, bNode, 1, node); - if (node->prop) + if (node->prop) { IDP_WriteProperty(node->prop, wd); + } - for (sock= node->inputs.first; sock; sock= sock->next) + for (sock = node->inputs.first; sock; sock = sock->next) { write_node_socket(wd, ntree, node, sock); - for (sock= node->outputs.first; sock; sock= sock->next) + } + for (sock = node->outputs.first; sock; sock = sock->next) { write_node_socket(wd, ntree, node, sock); - - for (link = node->internal_links.first; link; link = link->next) - writestruct(wd, DATA, "bNodeLink", 1, link); + } + + for (link = node->internal_links.first; link; link = link->next) { + writestruct(wd, DATA, bNodeLink, 1, link); + } + if (node->storage) { /* could be handlerized at some point, now only 1 exception still */ - if (ntree->type==NTREE_SHADER && (node->type==SH_NODE_CURVE_VEC || node->type==SH_NODE_CURVE_RGB)) + if ((ntree->type == NTREE_SHADER) && + ELEM(node->type, SH_NODE_CURVE_VEC, SH_NODE_CURVE_RGB)) + { write_curvemapping(wd, node->storage); - else if (ntree->type==NTREE_SHADER && node->type==SH_NODE_SCRIPT) { + } + else if (ntree->type == NTREE_SHADER && + (node->type == SH_NODE_SCRIPT)) + { NodeShaderScript *nss = (NodeShaderScript *)node->storage; - if (nss->bytecode) - writedata(wd, DATA, strlen(nss->bytecode)+1, nss->bytecode); - writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); + if (nss->bytecode) { + writedata(wd, DATA, strlen(nss->bytecode) + 1, nss->bytecode); + } + writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); } - else if (ntree->type==NTREE_COMPOSIT && ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + else if ((ntree->type == NTREE_COMPOSIT) && + ELEM(node->type, CMP_NODE_TIME, CMP_NODE_CURVE_VEC, CMP_NODE_CURVE_RGB, CMP_NODE_HUECORRECT)) + { write_curvemapping(wd, node->storage); - else if (ntree->type==NTREE_COMPOSIT && node->type==CMP_NODE_MOVIEDISTORTION) { + } + else if ((ntree->type == NTREE_COMPOSIT) && + (node->type == CMP_NODE_MOVIEDISTORTION)) + { /* pass */ } - else - writestruct(wd, DATA, node->typeinfo->storagename, 1, node->storage); + else { + writestruct_id(wd, DATA, node->typeinfo->storagename, 1, node->storage); + } } - - if (node->type==CMP_NODE_OUTPUT_FILE) { + + if (node->type == CMP_NODE_OUTPUT_FILE) { /* inputs have own storage data */ - for (sock = node->inputs.first; sock; sock = sock->next) - writestruct(wd, DATA, "NodeImageMultiFileSocket", 1, sock->storage); + for (sock = node->inputs.first; sock; sock = sock->next) { + writestruct(wd, DATA, NodeImageMultiFileSocket, 1, sock->storage); + } } - if (node->type==CMP_NODE_IMAGE) { + if (node->type == CMP_NODE_IMAGE) { /* write extra socket info */ - for (sock = node->outputs.first; sock; sock = sock->next) - writestruct(wd, DATA, "NodeImageLayer", 1, sock->storage); + for (sock = node->outputs.first; sock; sock = sock->next) { + writestruct(wd, DATA, NodeImageLayer, 1, sock->storage); + } } } - - for (link= ntree->links.first; link; link= link->next) - writestruct(wd, DATA, "bNodeLink", 1, link); - - for (sock = ntree->inputs.first; sock; sock = sock->next) + + for (link = ntree->links.first; link; link = link->next) { + writestruct(wd, DATA, bNodeLink, 1, link); + } + + for (sock = ntree->inputs.first; sock; sock = sock->next) { write_node_socket_interface(wd, ntree, sock); - for (sock = ntree->outputs.first; sock; sock = sock->next) + } + for (sock = ntree->outputs.first; sock; sock = sock->next) { write_node_socket_interface(wd, ntree, sock); + } } /** @@ -997,9 +1105,11 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) /* XXX in future, handle multiple windows with multiple screens? */ current_screen_compat(mainvar, &curscreen, false); - if (curscreen) curscene = curscreen->scene; - - for (sce= mainvar->scene.first; sce; sce= sce->id.next) { + if (curscreen) { + curscene = curscreen->scene; + } + + for (sce = mainvar->scene.first; sce; sce = sce->id.next) { if (sce->id.lib == NULL && (sce == curscene || (sce->r.scemode & R_BG_RENDER))) { data.sfra = sce->r.sfra; data.efra = sce->r.efra; @@ -1014,9 +1124,10 @@ static void write_renderinfo(WriteData *wd, Main *mainvar) static void write_keymapitem(WriteData *wd, wmKeyMapItem *kmi) { - writestruct(wd, DATA, "wmKeyMapItem", 1, kmi); - if (kmi->properties) + writestruct(wd, DATA, wmKeyMapItem, 1, kmi); + if (kmi->properties) { IDP_WriteProperty(kmi->properties, wd); + } } static void write_userdef(WriteData *wd) @@ -1028,75 +1139,82 @@ static void write_userdef(WriteData *wd) bAddon *bext; bPathCompare *path_cmp; uiStyle *style; - - writestruct(wd, USER, "UserDef", 1, &U); - for (btheme= U.themes.first; btheme; btheme=btheme->next) - writestruct(wd, DATA, "bTheme", 1, btheme); + writestruct(wd, USER, UserDef, 1, &U); + + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + writestruct(wd, DATA, bTheme, 1, btheme); + } - for (keymap= U.user_keymaps.first; keymap; keymap=keymap->next) { - writestruct(wd, DATA, "wmKeyMap", 1, keymap); + for (keymap = U.user_keymaps.first; keymap; keymap = keymap->next) { + writestruct(wd, DATA, wmKeyMap, 1, keymap); - for (kmdi=keymap->diff_items.first; kmdi; kmdi=kmdi->next) { - writestruct(wd, DATA, "wmKeyMapDiffItem", 1, kmdi); - if (kmdi->remove_item) + for (kmdi = keymap->diff_items.first; kmdi; kmdi = kmdi->next) { + writestruct(wd, DATA, wmKeyMapDiffItem, 1, kmdi); + if (kmdi->remove_item) { write_keymapitem(wd, kmdi->remove_item); - if (kmdi->add_item) + } + if (kmdi->add_item) { write_keymapitem(wd, kmdi->add_item); + } } - for (kmi=keymap->items.first; kmi; kmi=kmi->next) + for (kmi = keymap->items.first; kmi; kmi = kmi->next) { write_keymapitem(wd, kmi); + } } - for (bext= U.addons.first; bext; bext=bext->next) { - writestruct(wd, DATA, "bAddon", 1, bext); + for (bext = U.addons.first; bext; bext = bext->next) { + writestruct(wd, DATA, bAddon, 1, bext); if (bext->prop) { IDP_WriteProperty(bext->prop, wd); } } for (path_cmp = U.autoexec_paths.first; path_cmp; path_cmp = path_cmp->next) { - writestruct(wd, DATA, "bPathCompare", 1, path_cmp); + writestruct(wd, DATA, bPathCompare, 1, path_cmp); } - - for (style= U.uistyles.first; style; style= style->next) { - writestruct(wd, DATA, "uiStyle", 1, style); + + for (style = U.uistyles.first; style; style = style->next) { + writestruct(wd, DATA, uiStyle, 1, style); } } static void write_boid_state(WriteData *wd, BoidState *state) { BoidRule *rule = state->rules.first; - //BoidCondition *cond = state->conditions.first; - writestruct(wd, DATA, "BoidState", 1, state); + writestruct(wd, DATA, BoidState, 1, state); - for (; rule; rule=rule->next) { + for (; rule; rule = rule->next) { switch (rule->type) { case eBoidRuleType_Goal: case eBoidRuleType_Avoid: - writestruct(wd, DATA, "BoidRuleGoalAvoid", 1, rule); + writestruct(wd, DATA, BoidRuleGoalAvoid, 1, rule); break; case eBoidRuleType_AvoidCollision: - writestruct(wd, DATA, "BoidRuleAvoidCollision", 1, rule); + writestruct(wd, DATA, BoidRuleAvoidCollision, 1, rule); break; case eBoidRuleType_FollowLeader: - writestruct(wd, DATA, "BoidRuleFollowLeader", 1, rule); + writestruct(wd, DATA, BoidRuleFollowLeader, 1, rule); break; case eBoidRuleType_AverageSpeed: - writestruct(wd, DATA, "BoidRuleAverageSpeed", 1, rule); + writestruct(wd, DATA, BoidRuleAverageSpeed, 1, rule); break; case eBoidRuleType_Fight: - writestruct(wd, DATA, "BoidRuleFight", 1, rule); + writestruct(wd, DATA, BoidRuleFight, 1, rule); break; default: - writestruct(wd, DATA, "BoidRule", 1, rule); + writestruct(wd, DATA, BoidRule, 1, rule); break; } } - //for (; cond; cond=cond->next) - // writestruct(wd, DATA, "BoidCondition", 1, cond); +#if 0 + BoidCondition *cond = state->conditions.first; + for (; cond; cond = cond->next) { + writestruct(wd, DATA, BoidCondition, 1, cond); + } +#endif } /* update this also to readfile.c */ @@ -1119,31 +1237,34 @@ static void write_pointcaches(WriteData *wd, ListBase *ptcaches) PointCache *cache = ptcaches->first; int i; - for (; cache; cache=cache->next) { - writestruct(wd, DATA, "PointCache", 1, cache); + for (; cache; cache = cache->next) { + writestruct(wd, DATA, PointCache, 1, cache); - if ((cache->flag & PTCACHE_DISK_CACHE)==0) { + if ((cache->flag & PTCACHE_DISK_CACHE) == 0) { PTCacheMem *pm = cache->mem_cache.first; - for (; pm; pm=pm->next) { + for (; pm; pm = pm->next) { PTCacheExtra *extra = pm->extradata.first; - writestruct(wd, DATA, "PTCacheMem", 1, pm); - - for (i=0; i<BPHYS_TOT_DATA; i++) { - if (pm->data[i] && pm->data_types & (1<<i)) { - if (ptcache_data_struct[i][0] == '\0') + writestruct(wd, DATA, PTCacheMem, 1, pm); + + for (i = 0; i < BPHYS_TOT_DATA; i++) { + if (pm->data[i] && pm->data_types & (1 << i)) { + if (ptcache_data_struct[i][0] == '\0') { writedata(wd, DATA, MEM_allocN_len(pm->data[i]), pm->data[i]); - else - writestruct(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]); + } + else { + writestruct_id(wd, DATA, ptcache_data_struct[i], pm->totpoint, pm->data[i]); + } } } - for (; extra; extra=extra->next) { - if (ptcache_extra_struct[extra->type][0] == '\0') + for (; extra; extra = extra->next) { + if (ptcache_extra_struct[extra->type][0] == '\0') { continue; - writestruct(wd, DATA, "PTCacheExtra", 1, extra); - writestruct(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data); + } + writestruct(wd, DATA, PTCacheExtra, 1, extra); + writestruct_id(wd, DATA, ptcache_extra_struct[extra->type], extra->totdata, extra->data); } } } @@ -1156,91 +1277,109 @@ static void write_particlesettings(WriteData *wd, ListBase *idbase) GroupObject *go; int a; - part= idbase->first; + part = idbase->first; while (part) { - if (part->id.us>0 || wd->current) { + if (part->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_PA, "ParticleSettings", 1, part); + writestruct(wd, ID_PA, ParticleSettings, 1, part); write_iddata(wd, &part->id); - if (part->adt) write_animdata(wd, part->adt); - writestruct(wd, DATA, "PartDeflect", 1, part->pd); - writestruct(wd, DATA, "PartDeflect", 1, part->pd2); - writestruct(wd, DATA, "EffectorWeights", 1, part->effector_weights); + if (part->adt) { + write_animdata(wd, part->adt); + } + writestruct(wd, DATA, PartDeflect, 1, part->pd); + writestruct(wd, DATA, PartDeflect, 1, part->pd2); + writestruct(wd, DATA, EffectorWeights, 1, part->effector_weights); - if (part->clumpcurve) + if (part->clumpcurve) { write_curvemapping(wd, part->clumpcurve); - if (part->roughcurve) + } + if (part->roughcurve) { write_curvemapping(wd, part->roughcurve); - + } + dw = part->dupliweights.first; - for (; dw; dw=dw->next) { + for (; dw; dw = dw->next) { /* update indices */ dw->index = 0; if (part->dup_group) { /* can be NULL if lining fails or set to None */ go = part->dup_group->gobject.first; while (go && go->ob != dw->ob) { - go=go->next; + go = go->next; dw->index++; } } - writestruct(wd, DATA, "ParticleDupliWeight", 1, dw); + writestruct(wd, DATA, ParticleDupliWeight, 1, dw); } if (part->boids && part->phystype == PART_PHYS_BOIDS) { BoidState *state = part->boids->states.first; - writestruct(wd, DATA, "BoidSettings", 1, part->boids); + writestruct(wd, DATA, BoidSettings, 1, part->boids); - for (; state; state=state->next) + for (; state; state = state->next) { write_boid_state(wd, state); + } } if (part->fluid && part->phystype == PART_PHYS_FLUID) { - writestruct(wd, DATA, "SPHFluidSettings", 1, part->fluid); + writestruct(wd, DATA, SPHFluidSettings, 1, part->fluid); } - for (a=0; a<MAX_MTEX; a++) { - if (part->mtex[a]) writestruct(wd, DATA, "MTex", 1, part->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (part->mtex[a]) { + writestruct(wd, DATA, MTex, 1, part->mtex[a]); + } } } - part= part->id.next; + part = part->id.next; } } static void write_particlesystems(WriteData *wd, ListBase *particles) { - ParticleSystem *psys= particles->first; + ParticleSystem *psys = particles->first; ParticleTarget *pt; int a; - for (; psys; psys=psys->next) { - writestruct(wd, DATA, "ParticleSystem", 1, psys); + for (; psys; psys = psys->next) { + writestruct(wd, DATA, ParticleSystem, 1, psys); if (psys->particles) { - writestruct(wd, DATA, "ParticleData", psys->totpart, psys->particles); + writestruct(wd, DATA, ParticleData, psys->totpart, psys->particles); if (psys->particles->hair) { ParticleData *pa = psys->particles; - for (a=0; a<psys->totpart; a++, pa++) - writestruct(wd, DATA, "HairKey", pa->totkey, pa->hair); + for (a = 0; a < psys->totpart; a++, pa++) { + writestruct(wd, DATA, HairKey, pa->totkey, pa->hair); + } } - if (psys->particles->boid && psys->part->phystype == PART_PHYS_BOIDS) - writestruct(wd, DATA, "BoidParticle", psys->totpart, psys->particles->boid); + if (psys->particles->boid && + (psys->part->phystype == PART_PHYS_BOIDS)) + { + writestruct(wd, DATA, BoidParticle, psys->totpart, psys->particles->boid); + } - if (psys->part->fluid && psys->part->phystype == PART_PHYS_FLUID && (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) - writestruct(wd, DATA, "ParticleSpring", psys->tot_fluidsprings, psys->fluid_springs); + if (psys->part->fluid && + (psys->part->phystype == PART_PHYS_FLUID) && + (psys->part->fluid->flag & SPH_VISCOELASTIC_SPRINGS)) + { + writestruct(wd, DATA, ParticleSpring, psys->tot_fluidsprings, psys->fluid_springs); + } } pt = psys->targets.first; - for (; pt; pt=pt->next) - writestruct(wd, DATA, "ParticleTarget", 1, pt); + for (; pt; pt = pt->next) { + writestruct(wd, DATA, ParticleTarget, 1, pt); + } - if (psys->child) writestruct(wd, DATA, "ChildParticle", psys->totchild, psys->child); + if (psys->child) { + writestruct(wd, DATA, ChildParticle, psys->totchild, psys->child); + } if (psys->clmd) { - writestruct(wd, DATA, "ClothModifierData", 1, psys->clmd); - writestruct(wd, DATA, "ClothSimSettings", 1, psys->clmd->sim_parms); - writestruct(wd, DATA, "ClothCollSettings", 1, psys->clmd->coll_parms); + writestruct(wd, DATA, ClothModifierData, 1, psys->clmd); + writestruct(wd, DATA, ClothSimSettings, 1, psys->clmd->sim_parms); + writestruct(wd, DATA, ClothCollSettings, 1, psys->clmd->coll_parms); } write_pointcaches(wd, &psys->ptcaches); @@ -1251,14 +1390,15 @@ static void write_properties(WriteData *wd, ListBase *lb) { bProperty *prop; - prop= lb->first; + prop = lb->first; while (prop) { - writestruct(wd, DATA, "bProperty", 1, prop); + writestruct(wd, DATA, bProperty, 1, prop); - if (prop->poin && prop->poin != &prop->data) + if (prop->poin && prop->poin != &prop->data) { writedata(wd, DATA, MEM_allocN_len(prop->poin), prop->poin); + } - prop= prop->next; + prop = prop->next; } } @@ -1266,57 +1406,57 @@ static void write_sensors(WriteData *wd, ListBase *lb) { bSensor *sens; - sens= lb->first; + sens = lb->first; while (sens) { - writestruct(wd, DATA, "bSensor", 1, sens); + writestruct(wd, DATA, bSensor, 1, sens); - writedata(wd, DATA, sizeof(void *)*sens->totlinks, sens->links); + writedata(wd, DATA, sizeof(void *) * sens->totlinks, sens->links); switch (sens->type) { - case SENS_NEAR: - writestruct(wd, DATA, "bNearSensor", 1, sens->data); - break; - case SENS_MOUSE: - writestruct(wd, DATA, "bMouseSensor", 1, sens->data); - break; - case SENS_KEYBOARD: - writestruct(wd, DATA, "bKeyboardSensor", 1, sens->data); - break; - case SENS_PROPERTY: - writestruct(wd, DATA, "bPropertySensor", 1, sens->data); - break; - case SENS_ARMATURE: - writestruct(wd, DATA, "bArmatureSensor", 1, sens->data); - break; - case SENS_ACTUATOR: - writestruct(wd, DATA, "bActuatorSensor", 1, sens->data); - break; - case SENS_DELAY: - writestruct(wd, DATA, "bDelaySensor", 1, sens->data); - break; - case SENS_COLLISION: - writestruct(wd, DATA, "bCollisionSensor", 1, sens->data); - break; - case SENS_RADAR: - writestruct(wd, DATA, "bRadarSensor", 1, sens->data); - break; - case SENS_RANDOM: - writestruct(wd, DATA, "bRandomSensor", 1, sens->data); - break; - case SENS_RAY: - writestruct(wd, DATA, "bRaySensor", 1, sens->data); - break; - case SENS_MESSAGE: - writestruct(wd, DATA, "bMessageSensor", 1, sens->data); - break; - case SENS_JOYSTICK: - writestruct(wd, DATA, "bJoystickSensor", 1, sens->data); - break; - default: - ; /* error: don't know how to write this file */ + case SENS_NEAR: + writestruct(wd, DATA, bNearSensor, 1, sens->data); + break; + case SENS_MOUSE: + writestruct(wd, DATA, bMouseSensor, 1, sens->data); + break; + case SENS_KEYBOARD: + writestruct(wd, DATA, bKeyboardSensor, 1, sens->data); + break; + case SENS_PROPERTY: + writestruct(wd, DATA, bPropertySensor, 1, sens->data); + break; + case SENS_ARMATURE: + writestruct(wd, DATA, bArmatureSensor, 1, sens->data); + break; + case SENS_ACTUATOR: + writestruct(wd, DATA, bActuatorSensor, 1, sens->data); + break; + case SENS_DELAY: + writestruct(wd, DATA, bDelaySensor, 1, sens->data); + break; + case SENS_COLLISION: + writestruct(wd, DATA, bCollisionSensor, 1, sens->data); + break; + case SENS_RADAR: + writestruct(wd, DATA, bRadarSensor, 1, sens->data); + break; + case SENS_RANDOM: + writestruct(wd, DATA, bRandomSensor, 1, sens->data); + break; + case SENS_RAY: + writestruct(wd, DATA, bRaySensor, 1, sens->data); + break; + case SENS_MESSAGE: + writestruct(wd, DATA, bMessageSensor, 1, sens->data); + break; + case SENS_JOYSTICK: + writestruct(wd, DATA, bJoystickSensor, 1, sens->data); + break; + default: + ; /* error: don't know how to write this file */ } - sens= sens->next; + sens = sens->next; } } @@ -1324,24 +1464,24 @@ static void write_controllers(WriteData *wd, ListBase *lb) { bController *cont; - cont= lb->first; + cont = lb->first; while (cont) { - writestruct(wd, DATA, "bController", 1, cont); + writestruct(wd, DATA, bController, 1, cont); - writedata(wd, DATA, sizeof(void *)*cont->totlinks, cont->links); + writedata(wd, DATA, sizeof(void *) * cont->totlinks, cont->links); switch (cont->type) { - case CONT_EXPRESSION: - writestruct(wd, DATA, "bExpressionCont", 1, cont->data); - break; - case CONT_PYTHON: - writestruct(wd, DATA, "bPythonCont", 1, cont->data); - break; - default: - ; /* error: don't know how to write this file */ + case CONT_EXPRESSION: + writestruct(wd, DATA, bExpressionCont, 1, cont->data); + break; + case CONT_PYTHON: + writestruct(wd, DATA, bPythonCont, 1, cont->data); + break; + default: + ; /* error: don't know how to write this file */ } - cont= cont->next; + cont = cont->next; } } @@ -1349,133 +1489,135 @@ static void write_actuators(WriteData *wd, ListBase *lb) { bActuator *act; - act= lb->first; + act = lb->first; while (act) { - writestruct(wd, DATA, "bActuator", 1, act); + writestruct(wd, DATA, bActuator, 1, act); switch (act->type) { - case ACT_ACTION: - case ACT_SHAPEACTION: - writestruct(wd, DATA, "bActionActuator", 1, act->data); - break; - case ACT_SOUND: - writestruct(wd, DATA, "bSoundActuator", 1, act->data); - break; - case ACT_OBJECT: - writestruct(wd, DATA, "bObjectActuator", 1, act->data); - break; - case ACT_PROPERTY: - writestruct(wd, DATA, "bPropertyActuator", 1, act->data); - break; - case ACT_CAMERA: - writestruct(wd, DATA, "bCameraActuator", 1, act->data); - break; - case ACT_CONSTRAINT: - writestruct(wd, DATA, "bConstraintActuator", 1, act->data); - break; - case ACT_EDIT_OBJECT: - writestruct(wd, DATA, "bEditObjectActuator", 1, act->data); - break; - case ACT_SCENE: - writestruct(wd, DATA, "bSceneActuator", 1, act->data); - break; - case ACT_GROUP: - writestruct(wd, DATA, "bGroupActuator", 1, act->data); - break; - case ACT_RANDOM: - writestruct(wd, DATA, "bRandomActuator", 1, act->data); - break; - case ACT_MESSAGE: - writestruct(wd, DATA, "bMessageActuator", 1, act->data); - break; - case ACT_GAME: - writestruct(wd, DATA, "bGameActuator", 1, act->data); - break; - case ACT_VISIBILITY: - writestruct(wd, DATA, "bVisibilityActuator", 1, act->data); - break; - case ACT_2DFILTER: - writestruct(wd, DATA, "bTwoDFilterActuator", 1, act->data); - break; - case ACT_PARENT: - writestruct(wd, DATA, "bParentActuator", 1, act->data); - break; - case ACT_STATE: - writestruct(wd, DATA, "bStateActuator", 1, act->data); - break; - case ACT_ARMATURE: - writestruct(wd, DATA, "bArmatureActuator", 1, act->data); - break; - case ACT_STEERING: - writestruct(wd, DATA, "bSteeringActuator", 1, act->data); - break; - case ACT_MOUSE: - writestruct(wd, DATA, "bMouseActuator", 1, act->data); - break; - default: - ; /* error: don't know how to write this file */ + case ACT_ACTION: + case ACT_SHAPEACTION: + writestruct(wd, DATA, bActionActuator, 1, act->data); + break; + case ACT_SOUND: + writestruct(wd, DATA, bSoundActuator, 1, act->data); + break; + case ACT_OBJECT: + writestruct(wd, DATA, bObjectActuator, 1, act->data); + break; + case ACT_PROPERTY: + writestruct(wd, DATA, bPropertyActuator, 1, act->data); + break; + case ACT_CAMERA: + writestruct(wd, DATA, bCameraActuator, 1, act->data); + break; + case ACT_CONSTRAINT: + writestruct(wd, DATA, bConstraintActuator, 1, act->data); + break; + case ACT_EDIT_OBJECT: + writestruct(wd, DATA, bEditObjectActuator, 1, act->data); + break; + case ACT_SCENE: + writestruct(wd, DATA, bSceneActuator, 1, act->data); + break; + case ACT_GROUP: + writestruct(wd, DATA, bGroupActuator, 1, act->data); + break; + case ACT_RANDOM: + writestruct(wd, DATA, bRandomActuator, 1, act->data); + break; + case ACT_MESSAGE: + writestruct(wd, DATA, bMessageActuator, 1, act->data); + break; + case ACT_GAME: + writestruct(wd, DATA, bGameActuator, 1, act->data); + break; + case ACT_VISIBILITY: + writestruct(wd, DATA, bVisibilityActuator, 1, act->data); + break; + case ACT_2DFILTER: + writestruct(wd, DATA, bTwoDFilterActuator, 1, act->data); + break; + case ACT_PARENT: + writestruct(wd, DATA, bParentActuator, 1, act->data); + break; + case ACT_STATE: + writestruct(wd, DATA, bStateActuator, 1, act->data); + break; + case ACT_ARMATURE: + writestruct(wd, DATA, bArmatureActuator, 1, act->data); + break; + case ACT_STEERING: + writestruct(wd, DATA, bSteeringActuator, 1, act->data); + break; + case ACT_MOUSE: + writestruct(wd, DATA, bMouseActuator, 1, act->data); + break; + default: + ; /* error: don't know how to write this file */ } - act= act->next; + act = act->next; } } static void write_motionpath(WriteData *wd, bMotionPath *mpath) { /* sanity checks */ - if (mpath == NULL) + if (mpath == NULL) { return; - + } + /* firstly, just write the motionpath struct */ - writestruct(wd, DATA, "bMotionPath", 1, mpath); - + writestruct(wd, DATA, bMotionPath, 1, mpath); + /* now write the array of data */ - writestruct(wd, DATA, "bMotionPathVert", mpath->length, mpath->points); + writestruct(wd, DATA, bMotionPathVert, mpath->length, mpath->points); } static void write_constraints(WriteData *wd, ListBase *conlist) { bConstraint *con; - for (con=conlist->first; con; con=con->next) { - const bConstraintTypeInfo *cti= BKE_constraint_typeinfo_get(con); - + for (con = conlist->first; con; con = con->next) { + const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con); + /* Write the specific data */ if (cti && con->data) { /* firstly, just write the plain con->data struct */ - writestruct(wd, DATA, cti->structName, 1, con->data); - + writestruct_id(wd, DATA, cti->structName, 1, con->data); + /* do any constraint specific stuff */ switch (con->type) { case CONSTRAINT_TYPE_PYTHON: { - bPythonConstraint *data = (bPythonConstraint *)con->data; + bPythonConstraint *data = con->data; bConstraintTarget *ct; - + /* write targets */ - for (ct= data->targets.first; ct; ct= ct->next) - writestruct(wd, DATA, "bConstraintTarget", 1, ct); - + for (ct = data->targets.first; ct; ct = ct->next) { + writestruct(wd, DATA, bConstraintTarget, 1, ct); + } + /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ IDP_WriteProperty(data->prop, wd); break; } - case CONSTRAINT_TYPE_SPLINEIK: + case CONSTRAINT_TYPE_SPLINEIK: { - bSplineIKConstraint *data = (bSplineIKConstraint *)con->data; - + bSplineIKConstraint *data = con->data; + /* write points array */ - writedata(wd, DATA, sizeof(float)*(data->numpoints), data->points); + writedata(wd, DATA, sizeof(float) * (data->numpoints), data->points); break; } } } - + /* Write the constraint */ - writestruct(wd, DATA, "bConstraint", 1, con); + writestruct(wd, DATA, bConstraint, 1, con); } } @@ -1485,176 +1627,191 @@ static void write_pose(WriteData *wd, bPose *pose) bActionGroup *grp; /* Write each channel */ - if (!pose) + if (pose == NULL) { return; + } /* Write channels */ - for (chan=pose->chanbase.first; chan; chan=chan->next) { + for (chan = pose->chanbase.first; chan; chan = chan->next) { /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (chan->prop) + if (chan->prop) { IDP_WriteProperty(chan->prop, wd); - + } + write_constraints(wd, &chan->constraints); - + write_motionpath(wd, chan->mpath); - - /* prevent crashes with autosave, when a bone duplicated in editmode has not yet been assigned to its posechannel */ - if (chan->bone) - chan->selectflag= chan->bone->flag & BONE_SELECTED; /* gets restored on read, for library armatures */ - - writestruct(wd, DATA, "bPoseChannel", 1, chan); - } - + + /* prevent crashes with autosave, + * when a bone duplicated in editmode has not yet been assigned to its posechannel */ + if (chan->bone) { + /* gets restored on read, for library armatures */ + chan->selectflag = chan->bone->flag & BONE_SELECTED; + } + + writestruct(wd, DATA, bPoseChannel, 1, chan); + } + /* Write groups */ - for (grp=pose->agroups.first; grp; grp=grp->next) - writestruct(wd, DATA, "bActionGroup", 1, grp); + for (grp = pose->agroups.first; grp; grp = grp->next) { + writestruct(wd, DATA, bActionGroup, 1, grp); + } /* write IK param */ if (pose->ikparam) { const char *structname = BKE_pose_ikparam_get_name(pose); - if (structname) - writestruct(wd, DATA, structname, 1, pose->ikparam); + if (structname) { + writestruct_id(wd, DATA, structname, 1, pose->ikparam); + } } /* Write this pose */ - writestruct(wd, DATA, "bPose", 1, pose); + writestruct(wd, DATA, bPose, 1, pose); } static void write_defgroups(WriteData *wd, ListBase *defbase) { - bDeformGroup *defgroup; - - for (defgroup=defbase->first; defgroup; defgroup=defgroup->next) - writestruct(wd, DATA, "bDeformGroup", 1, defgroup); + for (bDeformGroup *defgroup = defbase->first; defgroup; defgroup = defgroup->next) { + writestruct(wd, DATA, bDeformGroup, 1, defgroup); + } } static void write_modifiers(WriteData *wd, ListBase *modbase) { ModifierData *md; - if (modbase == NULL) return; - for (md=modbase->first; md; md= md->next) { + if (modbase == NULL) { + return; + } + + for (md = modbase->first; md; md = md->next) { const ModifierTypeInfo *mti = modifierType_getInfo(md->type); - if (mti == NULL) return; - - writestruct(wd, DATA, mti->structName, 1, md); - - if (md->type==eModifierType_Hook) { - HookModifierData *hmd = (HookModifierData*) md; - + if (mti == NULL) { + return; + } + + writestruct_id(wd, DATA, mti->structName, 1, md); + + if (md->type == eModifierType_Hook) { + HookModifierData *hmd = (HookModifierData *)md; + if (hmd->curfalloff) { write_curvemapping(wd, hmd->curfalloff); } - writedata(wd, DATA, sizeof(int)*hmd->totindex, hmd->indexar); + writedata(wd, DATA, sizeof(int) * hmd->totindex, hmd->indexar); } - else if (md->type==eModifierType_Cloth) { - ClothModifierData *clmd = (ClothModifierData*) md; - - writestruct(wd, DATA, "ClothSimSettings", 1, clmd->sim_parms); - writestruct(wd, DATA, "ClothCollSettings", 1, clmd->coll_parms); - writestruct(wd, DATA, "EffectorWeights", 1, clmd->sim_parms->effector_weights); + else if (md->type == eModifierType_Cloth) { + ClothModifierData *clmd = (ClothModifierData *)md; + + writestruct(wd, DATA, ClothSimSettings, 1, clmd->sim_parms); + writestruct(wd, DATA, ClothCollSettings, 1, clmd->coll_parms); + writestruct(wd, DATA, EffectorWeights, 1, clmd->sim_parms->effector_weights); write_pointcaches(wd, &clmd->ptcaches); } - else if (md->type==eModifierType_Smoke) { - SmokeModifierData *smd = (SmokeModifierData*) md; - + else if (md->type == eModifierType_Smoke) { + SmokeModifierData *smd = (SmokeModifierData *)md; + if (smd->type & MOD_SMOKE_TYPE_DOMAIN) { if (smd->domain) { write_pointcaches(wd, &(smd->domain->ptcaches[0])); /* create fake pointcache so that old blender versions can read it */ smd->domain->point_cache[1] = BKE_ptcache_add(&smd->domain->ptcaches[1]); - smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE|PTCACHE_FAKE_SMOKE; + smd->domain->point_cache[1]->flag |= PTCACHE_DISK_CACHE | PTCACHE_FAKE_SMOKE; smd->domain->point_cache[1]->step = 1; write_pointcaches(wd, &(smd->domain->ptcaches[1])); } - - writestruct(wd, DATA, "SmokeDomainSettings", 1, smd->domain); + + writestruct(wd, DATA, SmokeDomainSettings, 1, smd->domain); if (smd->domain) { /* cleanup the fake pointcache */ BKE_ptcache_free_list(&smd->domain->ptcaches[1]); smd->domain->point_cache[1] = NULL; - - writestruct(wd, DATA, "EffectorWeights", 1, smd->domain->effector_weights); + + writestruct(wd, DATA, EffectorWeights, 1, smd->domain->effector_weights); } } - else if (smd->type & MOD_SMOKE_TYPE_FLOW) - writestruct(wd, DATA, "SmokeFlowSettings", 1, smd->flow); - else if (smd->type & MOD_SMOKE_TYPE_COLL) - writestruct(wd, DATA, "SmokeCollSettings", 1, smd->coll); + else if (smd->type & MOD_SMOKE_TYPE_FLOW) { + writestruct(wd, DATA, SmokeFlowSettings, 1, smd->flow); + } + else if (smd->type & MOD_SMOKE_TYPE_COLL) { + writestruct(wd, DATA, SmokeCollSettings, 1, smd->coll); + } } - else if (md->type==eModifierType_Fluidsim) { - FluidsimModifierData *fluidmd = (FluidsimModifierData*) md; - - writestruct(wd, DATA, "FluidsimSettings", 1, fluidmd->fss); + else if (md->type == eModifierType_Fluidsim) { + FluidsimModifierData *fluidmd = (FluidsimModifierData *)md; + + writestruct(wd, DATA, FluidsimSettings, 1, fluidmd->fss); } - else if (md->type==eModifierType_DynamicPaint) { - DynamicPaintModifierData *pmd = (DynamicPaintModifierData*) md; - + else if (md->type == eModifierType_DynamicPaint) { + DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md; + if (pmd->canvas) { DynamicPaintSurface *surface; - writestruct(wd, DATA, "DynamicPaintCanvasSettings", 1, pmd->canvas); - + writestruct(wd, DATA, DynamicPaintCanvasSettings, 1, pmd->canvas); + /* write surfaces */ - for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) - writestruct(wd, DATA, "DynamicPaintSurface", 1, surface); + for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { + writestruct(wd, DATA, DynamicPaintSurface, 1, surface); + } /* write caches and effector weights */ - for (surface=pmd->canvas->surfaces.first; surface; surface=surface->next) { + for (surface = pmd->canvas->surfaces.first; surface; surface = surface->next) { write_pointcaches(wd, &(surface->ptcaches)); - writestruct(wd, DATA, "EffectorWeights", 1, surface->effector_weights); + writestruct(wd, DATA, EffectorWeights, 1, surface->effector_weights); } } if (pmd->brush) { - writestruct(wd, DATA, "DynamicPaintBrushSettings", 1, pmd->brush); - writestruct(wd, DATA, "ColorBand", 1, pmd->brush->paint_ramp); - writestruct(wd, DATA, "ColorBand", 1, pmd->brush->vel_ramp); + writestruct(wd, DATA, DynamicPaintBrushSettings, 1, pmd->brush); + writestruct(wd, DATA, ColorBand, 1, pmd->brush->paint_ramp); + writestruct(wd, DATA, ColorBand, 1, pmd->brush->vel_ramp); } } - else if (md->type==eModifierType_Collision) { - + else if (md->type == eModifierType_Collision) { + #if 0 - CollisionModifierData *collmd = (CollisionModifierData*) md; - // TODO: CollisionModifier should use pointcache + CollisionModifierData *collmd = (CollisionModifierData *)md; + // TODO: CollisionModifier should use pointcache // + have proper reset events before enabling this - writestruct(wd, DATA, "MVert", collmd->numverts, collmd->x); - writestruct(wd, DATA, "MVert", collmd->numverts, collmd->xnew); - writestruct(wd, DATA, "MFace", collmd->numfaces, collmd->mfaces); + writestruct(wd, DATA, MVert, collmd->numverts, collmd->x); + writestruct(wd, DATA, MVert, collmd->numverts, collmd->xnew); + writestruct(wd, DATA, MFace, collmd->numfaces, collmd->mfaces); #endif } - else if (md->type==eModifierType_MeshDeform) { - MeshDeformModifierData *mmd = (MeshDeformModifierData*) md; + else if (md->type == eModifierType_MeshDeform) { + MeshDeformModifierData *mmd = (MeshDeformModifierData *)md; int size = mmd->dyngridsize; - writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->bindinfluences); + writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->bindinfluences); writedata(wd, DATA, sizeof(int) * (mmd->totvert + 1), mmd->bindoffsets); writedata(wd, DATA, sizeof(float) * 3 * mmd->totcagevert, - mmd->bindcagecos); - writestruct(wd, DATA, "MDefCell", size*size*size, mmd->dyngrid); - writestruct(wd, DATA, "MDefInfluence", mmd->totinfluence, mmd->dyninfluences); - writedata(wd, DATA, sizeof(int)*mmd->totvert, mmd->dynverts); + mmd->bindcagecos); + writestruct(wd, DATA, MDefCell, size * size * size, mmd->dyngrid); + writestruct(wd, DATA, MDefInfluence, mmd->totinfluence, mmd->dyninfluences); + writedata(wd, DATA, sizeof(int) * mmd->totvert, mmd->dynverts); } - else if (md->type==eModifierType_Warp) { - WarpModifierData *tmd = (WarpModifierData*) md; + else if (md->type == eModifierType_Warp) { + WarpModifierData *tmd = (WarpModifierData *)md; if (tmd->curfalloff) { write_curvemapping(wd, tmd->curfalloff); } } - else if (md->type==eModifierType_WeightVGEdit) { - WeightVGEditModifierData *wmd = (WeightVGEditModifierData*) md; + else if (md->type == eModifierType_WeightVGEdit) { + WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md; - if (wmd->cmap_curve) + if (wmd->cmap_curve) { write_curvemapping(wd, wmd->cmap_curve); + } } - else if (md->type==eModifierType_LaplacianDeform) { - LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData*) md; + else if (md->type == eModifierType_LaplacianDeform) { + LaplacianDeformModifierData *lmd = (LaplacianDeformModifierData *)md; - writedata(wd, DATA, sizeof(float)*lmd->total_verts * 3, lmd->vertexco); + writedata(wd, DATA, sizeof(float) * lmd->total_verts * 3, lmd->vertexco); } else if (md->type == eModifierType_CorrectiveSmooth) { CorrectiveSmoothModifierData *csmd = (CorrectiveSmoothModifierData *)md; @@ -1669,19 +1826,21 @@ static void write_modifiers(WriteData *wd, ListBase *modbase) static void write_objects(WriteData *wd, ListBase *idbase) { Object *ob; - - ob= idbase->first; + + ob = idbase->first; while (ob) { - if (ob->id.us>0 || wd->current) { + if (ob->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_OB, "Object", 1, ob); + writestruct(wd, ID_OB, Object, 1, ob); write_iddata(wd, &ob->id); - if (ob->adt) write_animdata(wd, ob->adt); - + if (ob->adt) { + write_animdata(wd, ob->adt); + } + /* direct data */ - writedata(wd, DATA, sizeof(void *)*ob->totcol, ob->mat); - writedata(wd, DATA, sizeof(char)*ob->totcol, ob->matbits); + writedata(wd, DATA, sizeof(void *) * ob->totcol, ob->mat); + writedata(wd, DATA, sizeof(char) * ob->totcol, ob->matbits); /* write_effects(wd, &ob->effect); */ /* not used anymore */ write_properties(wd, &ob->prop); write_sensors(wd, &ob->sensors); @@ -1699,67 +1858,68 @@ static void write_objects(WriteData *wd, ListBase *idbase) write_defgroups(wd, &ob->defbase); write_constraints(wd, &ob->constraints); write_motionpath(wd, ob->mpath); - - writestruct(wd, DATA, "PartDeflect", 1, ob->pd); - writestruct(wd, DATA, "SoftBody", 1, ob->soft); + + writestruct(wd, DATA, PartDeflect, 1, ob->pd); + writestruct(wd, DATA, SoftBody, 1, ob->soft); if (ob->soft) { write_pointcaches(wd, &ob->soft->ptcaches); - writestruct(wd, DATA, "EffectorWeights", 1, ob->soft->effector_weights); + writestruct(wd, DATA, EffectorWeights, 1, ob->soft->effector_weights); } - writestruct(wd, DATA, "BulletSoftBody", 1, ob->bsoft); - + writestruct(wd, DATA, BulletSoftBody, 1, ob->bsoft); + if (ob->rigidbody_object) { - // TODO: if any extra data is added to handle duplis, will need separate function then - writestruct(wd, DATA, "RigidBodyOb", 1, ob->rigidbody_object); + /* TODO: if any extra data is added to handle duplis, will need separate function then */ + writestruct(wd, DATA, RigidBodyOb, 1, ob->rigidbody_object); } if (ob->rigidbody_constraint) { - writestruct(wd, DATA, "RigidBodyCon", 1, ob->rigidbody_constraint); + writestruct(wd, DATA, RigidBodyCon, 1, ob->rigidbody_constraint); } if (ob->type == OB_EMPTY && ob->empty_drawtype == OB_EMPTY_IMAGE) { - writestruct(wd, DATA, "ImageUser", 1, ob->iuser); + writestruct(wd, DATA, ImageUser, 1, ob->iuser); } write_particlesystems(wd, &ob->particlesystem); write_modifiers(wd, &ob->modifiers); - writelist(wd, DATA, "LinkData", &ob->pc_ids); - writelist(wd, DATA, "LodLevel", &ob->lodlevels); + writelist(wd, DATA, LinkData, &ob->pc_ids); + writelist(wd, DATA, LodLevel, &ob->lodlevels); } write_previews(wd, ob->preview); - ob= ob->id.next; + ob = ob->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_vfonts(WriteData *wd, ListBase *idbase) { VFont *vf; - PackedFile * pf; + PackedFile *pf; - vf= idbase->first; + vf = idbase->first; while (vf) { - if (vf->id.us>0 || wd->current) { + if (vf->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_VF, "VFont", 1, vf); + writestruct(wd, ID_VF, VFont, 1, vf); write_iddata(wd, &vf->id); /* direct data */ if (vf->packedfile) { pf = vf->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - vf= vf->id.next; + vf = vf->id.next; } + + mywrite_flush(wd); } @@ -1768,45 +1928,51 @@ static void write_keys(WriteData *wd, ListBase *idbase) Key *key; KeyBlock *kb; - key= idbase->first; + key = idbase->first; while (key) { - if (key->id.us>0 || wd->current) { + if (key->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_KE, "Key", 1, key); + writestruct(wd, ID_KE, Key, 1, key); write_iddata(wd, &key->id); - if (key->adt) write_animdata(wd, key->adt); - + if (key->adt) { + write_animdata(wd, key->adt); + } + /* direct data */ - kb= key->block.first; + kb = key->block.first; while (kb) { - writestruct(wd, DATA, "KeyBlock", 1, kb); - if (kb->data) writedata(wd, DATA, kb->totelem*key->elemsize, kb->data); - kb= kb->next; + writestruct(wd, DATA, KeyBlock, 1, kb); + if (kb->data) { + writedata(wd, DATA, kb->totelem * key->elemsize, kb->data); + } + kb = kb->next; } } - key= key->id.next; + key = key->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + + mywrite_flush(wd); } static void write_cameras(WriteData *wd, ListBase *idbase) { Camera *cam; - cam= idbase->first; + cam = idbase->first; while (cam) { - if (cam->id.us>0 || wd->current) { + if (cam->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_CA, "Camera", 1, cam); + writestruct(wd, ID_CA, Camera, 1, cam); write_iddata(wd, &cam->id); - if (cam->adt) write_animdata(wd, cam->adt); + if (cam->adt) { + write_animdata(wd, cam->adt); + } } - cam= cam->id.next; + cam = cam->id.next; } } @@ -1815,24 +1981,26 @@ static void write_mballs(WriteData *wd, ListBase *idbase) MetaBall *mb; MetaElem *ml; - mb= idbase->first; + mb = idbase->first; while (mb) { - if (mb->id.us>0 || wd->current) { + if (mb->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_MB, "MetaBall", 1, mb); + writestruct(wd, ID_MB, MetaBall, 1, mb); write_iddata(wd, &mb->id); /* direct data */ - writedata(wd, DATA, sizeof(void *)*mb->totcol, mb->mat); - if (mb->adt) write_animdata(wd, mb->adt); + writedata(wd, DATA, sizeof(void *) * mb->totcol, mb->mat); + if (mb->adt) { + write_animdata(wd, mb->adt); + } - ml= mb->elems.first; + ml = mb->elems.first; while (ml) { - writestruct(wd, DATA, "MetaElem", 1, ml); - ml= ml->next; + writestruct(wd, DATA, MetaElem, 1, ml); + ml = ml->next; } } - mb= mb->id.next; + mb = mb->id.next; } } @@ -1841,61 +2009,67 @@ static void write_curves(WriteData *wd, ListBase *idbase) Curve *cu; Nurb *nu; - cu= idbase->first; + cu = idbase->first; while (cu) { - if (cu->id.us>0 || wd->current) { + if (cu->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_CU, "Curve", 1, cu); + writestruct(wd, ID_CU, Curve, 1, cu); write_iddata(wd, &cu->id); /* direct data */ - writedata(wd, DATA, sizeof(void *)*cu->totcol, cu->mat); - if (cu->adt) write_animdata(wd, cu->adt); - + writedata(wd, DATA, sizeof(void *) * cu->totcol, cu->mat); + if (cu->adt) { + write_animdata(wd, cu->adt); + } + if (cu->vfont) { writedata(wd, DATA, cu->len + 1, cu->str); - writestruct(wd, DATA, "CharInfo", cu->len_wchar + 1, cu->strinfo); - writestruct(wd, DATA, "TextBox", cu->totbox, cu->tb); + writestruct(wd, DATA, CharInfo, cu->len_wchar + 1, cu->strinfo); + writestruct(wd, DATA, TextBox, cu->totbox, cu->tb); } else { /* is also the order of reading */ - nu= cu->nurb.first; + nu = cu->nurb.first; while (nu) { - writestruct(wd, DATA, "Nurb", 1, nu); - nu= nu->next; + writestruct(wd, DATA, Nurb, 1, nu); + nu = nu->next; } - nu= cu->nurb.first; + nu = cu->nurb.first; while (nu) { - if (nu->type == CU_BEZIER) - writestruct(wd, DATA, "BezTriple", nu->pntsu, nu->bezt); + if (nu->type == CU_BEZIER) { + writestruct(wd, DATA, BezTriple, nu->pntsu, nu->bezt); + } else { - writestruct(wd, DATA, "BPoint", nu->pntsu*nu->pntsv, nu->bp); - if (nu->knotsu) writedata(wd, DATA, KNOTSU(nu)*sizeof(float), nu->knotsu); - if (nu->knotsv) writedata(wd, DATA, KNOTSV(nu)*sizeof(float), nu->knotsv); + writestruct(wd, DATA, BPoint, nu->pntsu * nu->pntsv, nu->bp); + if (nu->knotsu) { + writedata(wd, DATA, KNOTSU(nu) * sizeof(float), nu->knotsu); + } + if (nu->knotsv) { + writedata(wd, DATA, KNOTSV(nu) * sizeof(float), nu->knotsv); + } } - nu= nu->next; + nu = nu->next; } } } - cu= cu->id.next; + cu = cu->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_dverts(WriteData *wd, int count, MDeformVert *dvlist) { if (dvlist) { - int i; - + /* Write the dvert list */ - writestruct(wd, DATA, "MDeformVert", count, dvlist); - + writestruct(wd, DATA, MDeformVert, count, dvlist); + /* Write deformation data for each dvert */ - for (i=0; i<count; i++) { - if (dvlist[i].dw) - writestruct(wd, DATA, "MDeformWeight", dvlist[i].totweight, dvlist[i].dw); + for (int i = 0; i < count; i++) { + if (dvlist[i].dw) { + writestruct(wd, DATA, MDeformWeight, dvlist[i].totweight, dvlist[i].dw); + } } } } @@ -1904,17 +2078,19 @@ static void write_mdisps(WriteData *wd, int count, MDisps *mdlist, int external) { if (mdlist) { int i; - - writestruct(wd, DATA, "MDisps", count, mdlist); + + writestruct(wd, DATA, MDisps, count, mdlist); for (i = 0; i < count; ++i) { MDisps *md = &mdlist[i]; if (md->disps) { - if (!external) + if (!external) { writedata(wd, DATA, sizeof(float) * 3 * md->totdisp, md->disps); + } } - - if (md->hidden) + + if (md->hidden) { writedata(wd, DATA, BLI_BITMAP_SIZE(md->totdisp), md->hidden); + } } } } @@ -1923,8 +2099,8 @@ static void write_grid_paint_mask(WriteData *wd, int count, GridPaintMask *grid_ { if (grid_paint_mask) { int i; - - writestruct(wd, DATA, "GridPaintMask", count, grid_paint_mask); + + writestruct(wd, DATA, GridPaintMask, count, grid_paint_mask); for (i = 0; i < count; ++i) { GridPaintMask *gpm = &grid_paint_mask[i]; if (gpm->data) { @@ -1944,11 +2120,12 @@ static void write_customdata( int i; /* write external customdata (not for undo) */ - if (data->external && !wd->current) + if (data->external && !wd->current) { CustomData_external_write(data, id, CD_MASK_MESH, count, 0); + } + + writestruct_at_address(wd, DATA, CustomDataLayer, data->totlayer, data->layers, layers); - writestruct_at_address(wd, DATA, "CustomDataLayer", data->totlayer, data->layers, layers); - for (i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &layers[i]; const char *structname; @@ -1974,10 +2151,14 @@ static void write_customdata( /* when using partial visibility, the MEdge and MFace layers * are smaller than the original, so their type and count is * passed to make this work */ - if (layer->type != partial_type) datasize= structnum*count; - else datasize= structnum*partial_count; + if (layer->type != partial_type) { + datasize = structnum * count; + } + else { + datasize = structnum * partial_count; + } - writestruct(wd, DATA, structname, datasize, layer->data); + writestruct_id(wd, DATA, structname, datasize, layer->data); } else { printf("%s error: layer '%s':%d - can't be written to file\n", @@ -1986,20 +2167,21 @@ static void write_customdata( } } - if (data->external) - writestruct(wd, DATA, "CustomDataExternal", 1, data->external); + if (data->external) { + writestruct(wd, DATA, CustomDataExternal, 1, data->external); + } } static void write_meshes(WriteData *wd, ListBase *idbase) { Mesh *mesh; - int save_for_old_blender= 0; + bool save_for_old_blender = false; #ifdef USE_BMESH_SAVE_AS_COMPAT save_for_old_blender = wd->use_mesh_compat; /* option to save with older mesh format */ #endif - mesh= idbase->first; + mesh = idbase->first; while (mesh) { CustomDataLayer *vlayers = NULL, vlayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *elayers = NULL, elayers_buff[CD_TEMP_CHUNK_SIZE]; @@ -2007,7 +2189,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomDataLayer *llayers = NULL, llayers_buff[CD_TEMP_CHUNK_SIZE]; CustomDataLayer *players = NULL, players_buff[CD_TEMP_CHUNK_SIZE]; - if (mesh->id.us>0 || wd->current) { + if (mesh->id.us > 0 || wd->current) { /* write LibData */ if (!save_for_old_blender) { /* write a copy of the mesh, don't modify in place because it is @@ -2040,13 +2222,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomData_file_write_prepare(&mesh->ldata, &llayers, llayers_buff, ARRAY_SIZE(llayers_buff)); CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); - writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh); + writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); write_iddata(wd, &mesh->id); /* direct data */ - if (mesh->adt) write_animdata(wd, mesh->adt); + if (mesh->adt) { + write_animdata(wd, mesh->adt); + } - writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); + writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0); @@ -2079,7 +2263,7 @@ static void write_meshes(WriteData *wd, ListBase *idbase) mesh->edit_btmesh = NULL; /* now fill in polys to mfaces */ - /* XXX This breaks writing desing, by using temp allocated memory, which will likely generate + /* XXX This breaks writing design, by using temp allocated memory, which will likely generate * duplicates in stored 'old' addresses. * This is very bad, but do not see easy way to avoid this, aside from generating those data * outside of save process itself. @@ -2098,13 +2282,15 @@ static void write_meshes(WriteData *wd, ListBase *idbase) CustomData_file_write_prepare(&mesh->pdata, &players, players_buff, ARRAY_SIZE(players_buff)); #endif - writestruct_at_address(wd, ID_ME, "Mesh", 1, old_mesh, mesh); + writestruct_at_address(wd, ID_ME, Mesh, 1, old_mesh, mesh); write_iddata(wd, &mesh->id); /* direct data */ - if (mesh->adt) write_animdata(wd, mesh->adt); + if (mesh->adt) { + write_animdata(wd, mesh->adt); + } - writedata(wd, DATA, sizeof(void *)*mesh->totcol, mesh->mat); + writedata(wd, DATA, sizeof(void *) * mesh->totcol, mesh->mat); /* writedata(wd, DATA, sizeof(MSelect) * mesh->totselect, mesh->mselect); */ /* pre-bmesh NULL's */ write_customdata(wd, &mesh->id, mesh->totvert, &mesh->vdata, vlayers, -1, 0); @@ -2141,44 +2327,50 @@ static void write_meshes(WriteData *wd, ListBase *idbase) MEM_freeN(players); } - mesh= mesh->id.next; + mesh = mesh->id.next; } + + mywrite_flush(wd); } static void write_lattices(WriteData *wd, ListBase *idbase) { Lattice *lt; - - lt= idbase->first; + + lt = idbase->first; while (lt) { - if (lt->id.us>0 || wd->current) { + if (lt->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_LT, "Lattice", 1, lt); + writestruct(wd, ID_LT, Lattice, 1, lt); write_iddata(wd, <->id); /* write animdata */ - if (lt->adt) write_animdata(wd, lt->adt); - + if (lt->adt) { + write_animdata(wd, lt->adt); + } + /* direct data */ - writestruct(wd, DATA, "BPoint", lt->pntsu*lt->pntsv*lt->pntsw, lt->def); - - write_dverts(wd, lt->pntsu*lt->pntsv*lt->pntsw, lt->dvert); - + writestruct(wd, DATA, BPoint, lt->pntsu * lt->pntsv * lt->pntsw, lt->def); + + write_dverts(wd, lt->pntsu * lt->pntsv * lt->pntsw, lt->dvert); + } - lt= lt->id.next; + lt = lt->id.next; } + + mywrite_flush(wd); } static void write_images(WriteData *wd, ListBase *idbase) { Image *ima; - PackedFile * pf; + PackedFile *pf; ImageView *iv; ImagePackedFile *imapf; - ima= idbase->first; + ima = idbase->first; while (ima) { - if (ima->id.us>0 || wd->current) { + if (ima->id.us > 0 || wd->current) { /* Some trickery to keep forward compatibility of packed images. */ BLI_assert(ima->packedfile == NULL); if (ima->packedfiles.first != NULL) { @@ -2187,69 +2379,83 @@ static void write_images(WriteData *wd, ListBase *idbase) } /* write LibData */ - writestruct(wd, ID_IM, "Image", 1, ima); + writestruct(wd, ID_IM, Image, 1, ima); write_iddata(wd, &ima->id); for (imapf = ima->packedfiles.first; imapf; imapf = imapf->next) { - writestruct(wd, DATA, "ImagePackedFile", 1, imapf); + writestruct(wd, DATA, ImagePackedFile, 1, imapf); if (imapf->packedfile) { pf = imapf->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } write_previews(wd, ima->preview); - for (iv = ima->views.first; iv; iv = iv->next) - writestruct(wd, DATA, "ImageView", 1, iv); - writestruct(wd, DATA, "Stereo3dFormat", 1, ima->stereo3d_format); + for (iv = ima->views.first; iv; iv = iv->next) { + writestruct(wd, DATA, ImageView, 1, iv); + } + writestruct(wd, DATA, Stereo3dFormat, 1, ima->stereo3d_format); ima->packedfile = NULL; } - ima= ima->id.next; + ima = ima->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + + mywrite_flush(wd); } static void write_textures(WriteData *wd, ListBase *idbase) { Tex *tex; - tex= idbase->first; + tex = idbase->first; while (tex) { - if (tex->id.us>0 || wd->current) { + if (tex->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_TE, "Tex", 1, tex); + writestruct(wd, ID_TE, Tex, 1, tex); write_iddata(wd, &tex->id); - if (tex->adt) write_animdata(wd, tex->adt); + if (tex->adt) { + write_animdata(wd, tex->adt); + } /* direct data */ - if (tex->coba) writestruct(wd, DATA, "ColorBand", 1, tex->coba); - if (tex->type == TEX_ENVMAP && tex->env) writestruct(wd, DATA, "EnvMap", 1, tex->env); + if (tex->coba) { + writestruct(wd, DATA, ColorBand, 1, tex->coba); + } + if (tex->type == TEX_ENVMAP && tex->env) { + writestruct(wd, DATA, EnvMap, 1, tex->env); + } if (tex->type == TEX_POINTDENSITY && tex->pd) { - writestruct(wd, DATA, "PointDensity", 1, tex->pd); - if (tex->pd->coba) writestruct(wd, DATA, "ColorBand", 1, tex->pd->coba); - if (tex->pd->falloff_curve) write_curvemapping(wd, tex->pd->falloff_curve); + writestruct(wd, DATA, PointDensity, 1, tex->pd); + if (tex->pd->coba) { + writestruct(wd, DATA, ColorBand, 1, tex->pd->coba); + } + if (tex->pd->falloff_curve) { + write_curvemapping(wd, tex->pd->falloff_curve); + } } - if (tex->type == TEX_VOXELDATA) writestruct(wd, DATA, "VoxelData", 1, tex->vd); - if (tex->type == TEX_OCEAN && tex->ot) writestruct(wd, DATA, "OceanTex", 1, tex->ot); - + if (tex->type == TEX_VOXELDATA) { + writestruct(wd, DATA, VoxelData, 1, tex->vd); + } + if (tex->type == TEX_OCEAN && tex->ot) { + writestruct(wd, DATA, OceanTex, 1, tex->ot); + } + /* nodetree is integral part of texture, no libdata */ if (tex->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, tex->nodetree); + writestruct(wd, DATA, bNodeTree, 1, tex->nodetree); write_nodetree(wd, tex->nodetree); } - + write_previews(wd, tex->preview); } - tex= tex->id.next; + tex = tex->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_materials(WriteData *wd, ListBase *idbase) @@ -2257,31 +2463,39 @@ static void write_materials(WriteData *wd, ListBase *idbase) Material *ma; int a; - ma= idbase->first; + ma = idbase->first; while (ma) { - if (ma->id.us>0 || wd->current) { + if (ma->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_MA, "Material", 1, ma); + writestruct(wd, ID_MA, Material, 1, ma); write_iddata(wd, &ma->id); - if (ma->adt) write_animdata(wd, ma->adt); + if (ma->adt) { + write_animdata(wd, ma->adt); + } + + for (a = 0; a < MAX_MTEX; a++) { + if (ma->mtex[a]) { + writestruct(wd, DATA, MTex, 1, ma->mtex[a]); + } + } - for (a=0; a<MAX_MTEX; a++) { - if (ma->mtex[a]) writestruct(wd, DATA, "MTex", 1, ma->mtex[a]); + if (ma->ramp_col) { + writestruct(wd, DATA, ColorBand, 1, ma->ramp_col); } - - if (ma->ramp_col) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_col); - if (ma->ramp_spec) writestruct(wd, DATA, "ColorBand", 1, ma->ramp_spec); - + if (ma->ramp_spec) { + writestruct(wd, DATA, ColorBand, 1, ma->ramp_spec); + } + /* nodetree is integral part of material, no libdata */ if (ma->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, ma->nodetree); + writestruct(wd, DATA, bNodeTree, 1, ma->nodetree); write_nodetree(wd, ma->nodetree); } write_previews(wd, ma->preview); } - ma= ma->id.next; + ma = ma->id.next; } } @@ -2290,28 +2504,32 @@ static void write_worlds(WriteData *wd, ListBase *idbase) World *wrld; int a; - wrld= idbase->first; + wrld = idbase->first; while (wrld) { - if (wrld->id.us>0 || wd->current) { + if (wrld->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_WO, "World", 1, wrld); + writestruct(wd, ID_WO, World, 1, wrld); write_iddata(wd, &wrld->id); - if (wrld->adt) write_animdata(wd, wrld->adt); - - for (a=0; a<MAX_MTEX; a++) { - if (wrld->mtex[a]) writestruct(wd, DATA, "MTex", 1, wrld->mtex[a]); + if (wrld->adt) { + write_animdata(wd, wrld->adt); + } + + for (a = 0; a < MAX_MTEX; a++) { + if (wrld->mtex[a]) { + writestruct(wd, DATA, MTex, 1, wrld->mtex[a]); + } } /* nodetree is integral part of world, no libdata */ if (wrld->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, wrld->nodetree); + writestruct(wd, DATA, bNodeTree, 1, wrld->nodetree); write_nodetree(wd, wrld->nodetree); } - + write_previews(wd, wrld->preview); } - wrld= wrld->id.next; + wrld = wrld->id.next; } } @@ -2320,34 +2538,41 @@ static void write_lamps(WriteData *wd, ListBase *idbase) Lamp *la; int a; - la= idbase->first; + la = idbase->first; while (la) { - if (la->id.us>0 || wd->current) { + if (la->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_LA, "Lamp", 1, la); + writestruct(wd, ID_LA, Lamp, 1, la); write_iddata(wd, &la->id); - if (la->adt) write_animdata(wd, la->adt); - + if (la->adt) { + write_animdata(wd, la->adt); + } + /* direct data */ - for (a=0; a<MAX_MTEX; a++) { - if (la->mtex[a]) writestruct(wd, DATA, "MTex", 1, la->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (la->mtex[a]) { + writestruct(wd, DATA, MTex, 1, la->mtex[a]); + } } - - if (la->curfalloff) + + if (la->curfalloff) { write_curvemapping(wd, la->curfalloff); - + } + /* nodetree is integral part of lamps, no libdata */ if (la->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, la->nodetree); + writestruct(wd, DATA, bNodeTree, 1, la->nodetree); write_nodetree(wd, la->nodetree); } write_previews(wd, la->preview); - + } - la= la->id.next; + la = la->id.next; } + + mywrite_flush(wd); } static void write_sequence_modifiers(WriteData *wd, ListBase *modbase) @@ -2358,21 +2583,21 @@ static void write_sequence_modifiers(WriteData *wd, ListBase *modbase) const SequenceModifierTypeInfo *smti = BKE_sequence_modifier_type_info_get(smd->type); if (smti) { - writestruct(wd, DATA, smti->struct_name, 1, smd); + writestruct_id(wd, DATA, smti->struct_name, 1, smd); if (smd->type == seqModifierType_Curves) { - CurvesModifierData *cmd = (CurvesModifierData *) smd; + CurvesModifierData *cmd = (CurvesModifierData *)smd; write_curvemapping(wd, &cmd->curve_mapping); } else if (smd->type == seqModifierType_HueCorrect) { - HueCorrectModifierData *hcmd = (HueCorrectModifierData *) smd; + HueCorrectModifierData *hcmd = (HueCorrectModifierData *)smd; write_curvemapping(wd, &hcmd->curve_mapping); } } else { - writestruct(wd, DATA, "SequenceModifierData", 1, smd); + writestruct(wd, DATA, SequenceModifierData, 1, smd); } } } @@ -2386,8 +2611,9 @@ static void write_view_settings(WriteData *wd, ColorManagedViewSettings *view_se static void write_paint(WriteData *wd, Paint *p) { - if (p->cavity_curve) + if (p->cavity_curve) { write_curvemapping(wd, p->cavity_curve); + } } static void write_scenes(WriteData *wd, ListBase *scebase) @@ -2405,106 +2631,114 @@ static void write_scenes(WriteData *wd, ListBase *scebase) ToolSettings *tos; FreestyleModuleConfig *fmc; FreestyleLineSet *fls; - - sce= scebase->first; + + sce = scebase->first; while (sce) { /* write LibData */ - writestruct(wd, ID_SCE, "Scene", 1, sce); + writestruct(wd, ID_SCE, Scene, 1, sce); write_iddata(wd, &sce->id); - if (sce->adt) write_animdata(wd, sce->adt); + if (sce->adt) { + write_animdata(wd, sce->adt); + } write_keyingsets(wd, &sce->keyingsets); - + /* direct data */ - base= sce->base.first; + base = sce->base.first; while (base) { - writestruct(wd, DATA, "Base", 1, base); - base= base->next; + writestruct(wd, DATA, Base, 1, base); + base = base->next; } - + tos = sce->toolsettings; - writestruct(wd, DATA, "ToolSettings", 1, tos); + writestruct(wd, DATA, ToolSettings, 1, tos); if (tos->vpaint) { - writestruct(wd, DATA, "VPaint", 1, tos->vpaint); - write_paint (wd, &tos->vpaint->paint); + writestruct(wd, DATA, VPaint, 1, tos->vpaint); + write_paint(wd, &tos->vpaint->paint); } if (tos->wpaint) { - writestruct(wd, DATA, "VPaint", 1, tos->wpaint); - write_paint (wd, &tos->wpaint->paint); + writestruct(wd, DATA, VPaint, 1, tos->wpaint); + write_paint(wd, &tos->wpaint->paint); } if (tos->sculpt) { - writestruct(wd, DATA, "Sculpt", 1, tos->sculpt); - write_paint (wd, &tos->sculpt->paint); + writestruct(wd, DATA, Sculpt, 1, tos->sculpt); + write_paint(wd, &tos->sculpt->paint); } if (tos->uvsculpt) { - writestruct(wd, DATA, "UvSculpt", 1, tos->uvsculpt); - write_paint (wd, &tos->uvsculpt->paint); + writestruct(wd, DATA, UvSculpt, 1, tos->uvsculpt); + write_paint(wd, &tos->uvsculpt->paint); } write_paint(wd, &tos->imapaint.paint); - ed= sce->ed; + ed = sce->ed; if (ed) { - writestruct(wd, DATA, "Editing", 1, ed); - + writestruct(wd, DATA, Editing, 1, ed); + /* reset write flags too */ - - SEQ_BEGIN (ed, seq) + + SEQ_BEGIN(ed, seq) { - if (seq->strip) seq->strip->done = false; - writestruct(wd, DATA, "Sequence", 1, seq); + if (seq->strip) { + seq->strip->done = false; + } + writestruct(wd, DATA, Sequence, 1, seq); } SEQ_END - - SEQ_BEGIN (ed, seq) + + SEQ_BEGIN(ed, seq) { - if (seq->strip && seq->strip->done==0) { + if (seq->strip && seq->strip->done == 0) { /* write strip with 'done' at 0 because readfile */ - + if (seq->effectdata) { switch (seq->type) { - case SEQ_TYPE_COLOR: - writestruct(wd, DATA, "SolidColorVars", 1, seq->effectdata); - break; - case SEQ_TYPE_SPEED: - writestruct(wd, DATA, "SpeedControlVars", 1, seq->effectdata); - break; - case SEQ_TYPE_WIPE: - writestruct(wd, DATA, "WipeVars", 1, seq->effectdata); - break; - case SEQ_TYPE_GLOW: - writestruct(wd, DATA, "GlowVars", 1, seq->effectdata); - break; - case SEQ_TYPE_TRANSFORM: - writestruct(wd, DATA, "TransformVars", 1, seq->effectdata); - break; - case SEQ_TYPE_GAUSSIAN_BLUR: - writestruct(wd, DATA, "GaussianBlurVars", 1, seq->effectdata); - break; - case SEQ_TYPE_TEXT: - writestruct(wd, DATA, "TextVars", 1, seq->effectdata); - break; + case SEQ_TYPE_COLOR: + writestruct(wd, DATA, SolidColorVars, 1, seq->effectdata); + break; + case SEQ_TYPE_SPEED: + writestruct(wd, DATA, SpeedControlVars, 1, seq->effectdata); + break; + case SEQ_TYPE_WIPE: + writestruct(wd, DATA, WipeVars, 1, seq->effectdata); + break; + case SEQ_TYPE_GLOW: + writestruct(wd, DATA, GlowVars, 1, seq->effectdata); + break; + case SEQ_TYPE_TRANSFORM: + writestruct(wd, DATA, TransformVars, 1, seq->effectdata); + break; + case SEQ_TYPE_GAUSSIAN_BLUR: + writestruct(wd, DATA, GaussianBlurVars, 1, seq->effectdata); + break; + case SEQ_TYPE_TEXT: + writestruct(wd, DATA, TextVars, 1, seq->effectdata); + break; } } - writestruct(wd, DATA, "Stereo3dFormat", 1, seq->stereo3d_format); + writestruct(wd, DATA, Stereo3dFormat, 1, seq->stereo3d_format); - strip= seq->strip; - writestruct(wd, DATA, "Strip", 1, strip); + strip = seq->strip; + writestruct(wd, DATA, Strip, 1, strip); if (seq->flag & SEQ_USE_CROP && strip->crop) { - writestruct(wd, DATA, "StripCrop", 1, strip->crop); + writestruct(wd, DATA, StripCrop, 1, strip->crop); } if (seq->flag & SEQ_USE_TRANSFORM && strip->transform) { - writestruct(wd, DATA, "StripTransform", 1, strip->transform); + writestruct(wd, DATA, StripTransform, 1, strip->transform); } if (seq->flag & SEQ_USE_PROXY && strip->proxy) { - writestruct(wd, DATA, "StripProxy", 1, strip->proxy); + writestruct(wd, DATA, StripProxy, 1, strip->proxy); + } + if (seq->type == SEQ_TYPE_IMAGE) { + writestruct(wd, DATA, StripElem, + MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), + strip->stripdata); } - if (seq->type==SEQ_TYPE_IMAGE) - writestruct(wd, DATA, "StripElem", MEM_allocN_len(strip->stripdata) / sizeof(struct StripElem), strip->stripdata); - else if (seq->type==SEQ_TYPE_MOVIE || seq->type==SEQ_TYPE_SOUND_RAM || seq->type == SEQ_TYPE_SOUND_HD) - writestruct(wd, DATA, "StripElem", 1, strip->stripdata); - + else if (ELEM(seq->type, SEQ_TYPE_MOVIE, SEQ_TYPE_SOUND_RAM, SEQ_TYPE_SOUND_HD)) { + writestruct(wd, DATA, StripElem, 1, strip->stripdata); + } + strip->done = true; } @@ -2515,70 +2749,79 @@ static void write_scenes(WriteData *wd, ListBase *scebase) write_sequence_modifiers(wd, &seq->modifiers); } SEQ_END - + /* new; meta stack too, even when its nasty restore code */ - for (ms= ed->metastack.first; ms; ms= ms->next) { - writestruct(wd, DATA, "MetaStack", 1, ms); + for (ms = ed->metastack.first; ms; ms = ms->next) { + writestruct(wd, DATA, MetaStack, 1, ms); } } - + if (sce->r.avicodecdata) { - writestruct(wd, DATA, "AviCodecData", 1, sce->r.avicodecdata); - if (sce->r.avicodecdata->lpFormat) writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); - if (sce->r.avicodecdata->lpParms) writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + writestruct(wd, DATA, AviCodecData, 1, sce->r.avicodecdata); + if (sce->r.avicodecdata->lpFormat) { + writedata(wd, DATA, sce->r.avicodecdata->cbFormat, sce->r.avicodecdata->lpFormat); + } + if (sce->r.avicodecdata->lpParms) { + writedata(wd, DATA, sce->r.avicodecdata->cbParms, sce->r.avicodecdata->lpParms); + } } if (sce->r.qtcodecdata) { - writestruct(wd, DATA, "QuicktimeCodecData", 1, sce->r.qtcodecdata); - if (sce->r.qtcodecdata->cdParms) writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); + writestruct(wd, DATA, QuicktimeCodecData, 1, sce->r.qtcodecdata); + if (sce->r.qtcodecdata->cdParms) { + writedata(wd, DATA, sce->r.qtcodecdata->cdSize, sce->r.qtcodecdata->cdParms); + } } if (sce->r.ffcodecdata.properties) { IDP_WriteProperty(sce->r.ffcodecdata.properties, wd); } /* writing dynamic list of TimeMarkers to the blend file */ - for (marker= sce->markers.first; marker; marker= marker->next) - writestruct(wd, DATA, "TimeMarker", 1, marker); - + for (marker = sce->markers.first; marker; marker = marker->next) { + writestruct(wd, DATA, TimeMarker, 1, marker); + } + /* writing dynamic list of TransformOrientations to the blend file */ - for (ts = sce->transform_spaces.first; ts; ts = ts->next) - writestruct(wd, DATA, "TransformOrientation", 1, ts); - + for (ts = sce->transform_spaces.first; ts; ts = ts->next) { + writestruct(wd, DATA, TransformOrientation, 1, ts); + } + for (srl = sce->r.layers.first; srl; srl = srl->next) { - writestruct(wd, DATA, "SceneRenderLayer", 1, srl); + writestruct(wd, DATA, SceneRenderLayer, 1, srl); for (fmc = srl->freestyleConfig.modules.first; fmc; fmc = fmc->next) { - writestruct(wd, DATA, "FreestyleModuleConfig", 1, fmc); + writestruct(wd, DATA, FreestyleModuleConfig, 1, fmc); } for (fls = srl->freestyleConfig.linesets.first; fls; fls = fls->next) { - writestruct(wd, DATA, "FreestyleLineSet", 1, fls); + writestruct(wd, DATA, FreestyleLineSet, 1, fls); } } /* writing MultiView to the blend file */ - for (srv = sce->r.views.first; srv; srv = srv->next) - writestruct(wd, DATA, "SceneRenderView", 1, srv); - + for (srv = sce->r.views.first; srv; srv = srv->next) { + writestruct(wd, DATA, SceneRenderView, 1, srv); + } + if (sce->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, sce->nodetree); + writestruct(wd, DATA, bNodeTree, 1, sce->nodetree); write_nodetree(wd, sce->nodetree); } write_view_settings(wd, &sce->view_settings); - + /* writing RigidBodyWorld data to the blend file */ if (sce->rigidbody_world) { - writestruct(wd, DATA, "RigidBodyWorld", 1, sce->rigidbody_world); - writestruct(wd, DATA, "EffectorWeights", 1, sce->rigidbody_world->effector_weights); + writestruct(wd, DATA, RigidBodyWorld, 1, sce->rigidbody_world); + writestruct(wd, DATA, EffectorWeights, 1, sce->rigidbody_world->effector_weights); write_pointcaches(wd, &(sce->rigidbody_world->ptcaches)); } - + write_previews(wd, sce->preview); write_curvemapping_curves(wd, &sce->r.mblur_shutter_curve); - sce= sce->id.next; + sce = sce->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + + mywrite_flush(wd); } static void write_gpencils(WriteData *wd, ListBase *lb) @@ -2587,65 +2830,75 @@ static void write_gpencils(WriteData *wd, ListBase *lb) bGPDlayer *gpl; bGPDframe *gpf; bGPDstroke *gps; - - for (gpd= lb->first; gpd; gpd= gpd->id.next) { - if (gpd->id.us>0 || wd->current) { + + for (gpd = lb->first; gpd; gpd = gpd->id.next) { + if (gpd->id.us > 0 || wd->current) { /* write gpd data block to file */ - writestruct(wd, ID_GD, "bGPdata", 1, gpd); + writestruct(wd, ID_GD, bGPdata, 1, gpd); write_iddata(wd, &gpd->id); - if (gpd->adt) write_animdata(wd, gpd->adt); - + if (gpd->adt) { + write_animdata(wd, gpd->adt); + } + /* write grease-pencil layers to file */ - writelist(wd, DATA, "bGPDlayer", &gpd->layers); - for (gpl= gpd->layers.first; gpl; gpl= gpl->next) { - + writelist(wd, DATA, bGPDlayer, &gpd->layers); + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + /* write this layer's frames to file */ - writelist(wd, DATA, "bGPDframe", &gpl->frames); - for (gpf= gpl->frames.first; gpf; gpf= gpf->next) { - + writelist(wd, DATA, bGPDframe, &gpl->frames); + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* write strokes */ - writelist(wd, DATA, "bGPDstroke", &gpf->strokes); - for (gps= gpf->strokes.first; gps; gps= gps->next) { - writestruct(wd, DATA, "bGPDspoint", gps->totpoints, gps->points); + writelist(wd, DATA, bGPDstroke, &gpf->strokes); + for (gps = gpf->strokes.first; gps; gps = gps->next) { + writestruct(wd, DATA, bGPDspoint, gps->totpoints, gps->points); } } } } } + + mywrite_flush(wd); } static void write_windowmanagers(WriteData *wd, ListBase *lb) { wmWindowManager *wm; wmWindow *win; - - for (wm= lb->first; wm; wm= wm->id.next) { - writestruct(wd, ID_WM, "wmWindowManager", 1, wm); + + for (wm = lb->first; wm; wm = wm->id.next) { + writestruct(wd, ID_WM, wmWindowManager, 1, wm); write_iddata(wd, &wm->id); - for (win= wm->windows.first; win; win= win->next) { - writestruct(wd, DATA, "wmWindow", 1, win); - writestruct(wd, DATA, "Stereo3dFormat", 1, win->stereo3d_format); + for (win = wm->windows.first; win; win = win->next) { + writestruct(wd, DATA, wmWindow, 1, win); + writestruct(wd, DATA, Stereo3dFormat, 1, win->stereo3d_format); } } + + /* typically flushing wouldn't be needed however this data _always_ changes, + * so flush here for more efficient undo. */ + mywrite_flush(wd); } static void write_region(WriteData *wd, ARegion *ar, int spacetype) -{ - writestruct(wd, DATA, "ARegion", 1, ar); - +{ + writestruct(wd, DATA, ARegion, 1, ar); + if (ar->regiondata) { switch (spacetype) { case SPACE_VIEW3D: - if (ar->regiontype==RGN_TYPE_WINDOW) { - RegionView3D *rv3d= ar->regiondata; - writestruct(wd, DATA, "RegionView3D", 1, rv3d); - - if (rv3d->localvd) - writestruct(wd, DATA, "RegionView3D", 1, rv3d->localvd); - if (rv3d->clipbb) - writestruct(wd, DATA, "BoundBox", 1, rv3d->clipbb); + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = ar->regiondata; + writestruct(wd, DATA, RegionView3D, 1, rv3d); + + if (rv3d->localvd) { + writestruct(wd, DATA, RegionView3D, 1, rv3d->localvd); + } + if (rv3d->clipbb) { + writestruct(wd, DATA, BoundBox, 1, rv3d->clipbb); + } } else @@ -2659,53 +2912,53 @@ static void write_region(WriteData *wd, ARegion *ar, int spacetype) static void write_uilist(WriteData *wd, uiList *ui_list) { - writestruct(wd, DATA, "uiList", 1, ui_list); + writestruct(wd, DATA, uiList, 1, ui_list); if (ui_list->properties) { IDP_WriteProperty(ui_list->properties, wd); } } -static void write_soops(WriteData *wd, SpaceOops *so, LinkNode **tmp_mem_list) +static void write_soops(WriteData *wd, SpaceOops *so) { BLI_mempool *ts = so->treestore; - + if (ts) { + SpaceOops so_flat = *so; + int elems = BLI_mempool_count(ts); /* linearize mempool to array */ TreeStoreElem *data = elems ? BLI_mempool_as_arrayN(ts, "TreeStoreElem") : NULL; if (data) { - TreeStore *ts_flat = MEM_callocN(sizeof(TreeStore), "TreeStore"); - - ts_flat->usedelem = elems; - ts_flat->totelem = elems; - ts_flat->data = data; - - /* temporarily replace mempool-treestore by flat-treestore */ - so->treestore = (BLI_mempool *)ts_flat; - writestruct(wd, DATA, "SpaceOops", 1, so); - - writestruct(wd, DATA, "TreeStore", 1, ts_flat); - writestruct(wd, DATA, "TreeStoreElem", elems, data); - - /* we do not free the pointers immediately, because if we have multiple - * outliners in a screen we might get the same address on the next - * malloc, which makes the address no longer unique and so invalid for - * lookups on file read, causing crashes or double frees */ - BLI_linklist_prepend(tmp_mem_list, ts_flat); - BLI_linklist_prepend(tmp_mem_list, data); + /* In this block we use the memory location of the treestore + * but _not_ its data, the addresses in this case are UUID's, + * since we can't rely on malloc giving us different values each time. + */ + TreeStore ts_flat = {0}; + + /* we know the treestore is at least as big as a pointer, + * so offsetting works to give us a UUID. */ + void *data_addr = (void *)POINTER_OFFSET(ts, sizeof(void *)); + + ts_flat.usedelem = elems; + ts_flat.totelem = elems; + ts_flat.data = data_addr; + + writestruct(wd, DATA, SpaceOops, 1, so); + + writestruct_at_address(wd, DATA, TreeStore, 1, ts, &ts_flat); + writestruct_at_address(wd, DATA, TreeStoreElem, elems, data_addr, data); + + MEM_freeN(data); } else { - so->treestore = NULL; - writestruct(wd, DATA, "SpaceOops", 1, so); + so_flat.treestore = NULL; + writestruct_at_address(wd, DATA, SpaceOops, 1, so, &so_flat); } - - /* restore old treestore */ - so->treestore = ts; } else { - writestruct(wd, DATA, "SpaceOops", 1, so); + writestruct(wd, DATA, SpaceOops, 1, so); } } @@ -2715,218 +2968,226 @@ static void write_screens(WriteData *wd, ListBase *scrbase) ScrArea *sa; ScrVert *sv; ScrEdge *se; - LinkNode *tmp_mem_list = NULL; - sc= scrbase->first; + sc = scrbase->first; while (sc) { - + /* write LibData */ /* in 2.50+ files, the file identifier for screens is patched, forward compatibility */ - writestruct(wd, ID_SCRN, "Screen", 1, sc); + writestruct(wd, ID_SCRN, bScreen, 1, sc); write_iddata(wd, &sc->id); /* direct data */ - for (sv= sc->vertbase.first; sv; sv= sv->next) - writestruct(wd, DATA, "ScrVert", 1, sv); - - for (se= sc->edgebase.first; se; se= se->next) - writestruct(wd, DATA, "ScrEdge", 1, se); - - for (sa= sc->areabase.first; sa; sa= sa->next) { + for (sv = sc->vertbase.first; sv; sv = sv->next) { + writestruct(wd, DATA, ScrVert, 1, sv); + } + + for (se = sc->edgebase.first; se; se = se->next) { + writestruct(wd, DATA, ScrEdge, 1, se); + } + + for (sa = sc->areabase.first; sa; sa = sa->next) { SpaceLink *sl; Panel *pa; uiList *ui_list; uiPreview *ui_preview; PanelCategoryStack *pc_act; ARegion *ar; - - writestruct(wd, DATA, "ScrArea", 1, sa); - - for (ar= sa->regionbase.first; ar; ar= ar->next) { + + writestruct(wd, DATA, ScrArea, 1, sa); + + for (ar = sa->regionbase.first; ar; ar = ar->next) { write_region(wd, ar, sa->spacetype); - - for (pa= ar->panels.first; pa; pa= pa->next) - writestruct(wd, DATA, "Panel", 1, pa); - - for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) - writestruct(wd, DATA, "PanelCategoryStack", 1, pc_act); - - for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) + + for (pa = ar->panels.first; pa; pa = pa->next) { + writestruct(wd, DATA, Panel, 1, pa); + } + + for (pc_act = ar->panels_category_active.first; pc_act; pc_act = pc_act->next) { + writestruct(wd, DATA, PanelCategoryStack, 1, pc_act); + } + + for (ui_list = ar->ui_lists.first; ui_list; ui_list = ui_list->next) { write_uilist(wd, ui_list); + } - for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) - writestruct(wd, DATA, "uiPreview", 1, ui_preview); + for (ui_preview = ar->ui_previews.first; ui_preview; ui_preview = ui_preview->next) { + writestruct(wd, DATA, uiPreview, 1, ui_preview); + } } - - sl= sa->spacedata.first; + + sl = sa->spacedata.first; while (sl) { - for (ar= sl->regionbase.first; ar; ar= ar->next) + for (ar = sl->regionbase.first; ar; ar = ar->next) { write_region(wd, ar, sl->spacetype); - - if (sl->spacetype==SPACE_VIEW3D) { - View3D *v3d= (View3D *) sl; + } + + if (sl->spacetype == SPACE_VIEW3D) { + View3D *v3d = (View3D *)sl; BGpic *bgpic; - writestruct(wd, DATA, "View3D", 1, v3d); - for (bgpic= v3d->bgpicbase.first; bgpic; bgpic= bgpic->next) - writestruct(wd, DATA, "BGpic", 1, bgpic); - if (v3d->localvd) writestruct(wd, DATA, "View3D", 1, v3d->localvd); - - if (v3d->fx_settings.ssao) - writestruct(wd, DATA, "GPUSSAOSettings", 1, v3d->fx_settings.ssao); - if (v3d->fx_settings.dof) - writestruct(wd, DATA, "GPUDOFSettings", 1, v3d->fx_settings.dof); - } - else if (sl->spacetype==SPACE_IPO) { - SpaceIpo *sipo= (SpaceIpo *)sl; + writestruct(wd, DATA, View3D, 1, v3d); + for (bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + writestruct(wd, DATA, BGpic, 1, bgpic); + } + if (v3d->localvd) { + writestruct(wd, DATA, View3D, 1, v3d->localvd); + } + + if (v3d->fx_settings.ssao) { + writestruct(wd, DATA, GPUSSAOSettings, 1, v3d->fx_settings.ssao); + } + if (v3d->fx_settings.dof) { + writestruct(wd, DATA, GPUDOFSettings, 1, v3d->fx_settings.dof); + } + } + else if (sl->spacetype == SPACE_IPO) { + SpaceIpo *sipo = (SpaceIpo *)sl; ListBase tmpGhosts = sipo->ghostCurves; - + /* temporarily disable ghost curves when saving */ - sipo->ghostCurves.first= sipo->ghostCurves.last= NULL; - - writestruct(wd, DATA, "SpaceIpo", 1, sl); - if (sipo->ads) writestruct(wd, DATA, "bDopeSheet", 1, sipo->ads); - + sipo->ghostCurves.first = sipo->ghostCurves.last = NULL; + + writestruct(wd, DATA, SpaceIpo, 1, sl); + if (sipo->ads) { + writestruct(wd, DATA, bDopeSheet, 1, sipo->ads); + } + /* reenable ghost curves */ - sipo->ghostCurves= tmpGhosts; + sipo->ghostCurves = tmpGhosts; } - else if (sl->spacetype==SPACE_BUTS) { - writestruct(wd, DATA, "SpaceButs", 1, sl); + else if (sl->spacetype == SPACE_BUTS) { + writestruct(wd, DATA, SpaceButs, 1, sl); } - else if (sl->spacetype==SPACE_FILE) { - SpaceFile *sfile= (SpaceFile *)sl; + else if (sl->spacetype == SPACE_FILE) { + SpaceFile *sfile = (SpaceFile *)sl; - writestruct(wd, DATA, "SpaceFile", 1, sl); - if (sfile->params) - writestruct(wd, DATA, "FileSelectParams", 1, sfile->params); + writestruct(wd, DATA, SpaceFile, 1, sl); + if (sfile->params) { + writestruct(wd, DATA, FileSelectParams, 1, sfile->params); + } } - else if (sl->spacetype==SPACE_SEQ) { - writestruct(wd, DATA, "SpaceSeq", 1, sl); + else if (sl->spacetype == SPACE_SEQ) { + writestruct(wd, DATA, SpaceSeq, 1, sl); } - else if (sl->spacetype==SPACE_OUTLINER) { - SpaceOops *so= (SpaceOops *)sl; - write_soops(wd, so, &tmp_mem_list); + else if (sl->spacetype == SPACE_OUTLINER) { + SpaceOops *so = (SpaceOops *)sl; + write_soops(wd, so); } - else if (sl->spacetype==SPACE_IMAGE) { - SpaceImage *sima= (SpaceImage *)sl; - - writestruct(wd, DATA, "SpaceImage", 1, sl); - if (sima->cumap) - write_curvemapping(wd, sima->cumap); + else if (sl->spacetype == SPACE_IMAGE) { + writestruct(wd, DATA, SpaceImage, 1, sl); } - else if (sl->spacetype==SPACE_TEXT) { - writestruct(wd, DATA, "SpaceText", 1, sl); + else if (sl->spacetype == SPACE_TEXT) { + writestruct(wd, DATA, SpaceText, 1, sl); } - else if (sl->spacetype==SPACE_SCRIPT) { - SpaceScript *scr = (SpaceScript*)sl; + else if (sl->spacetype == SPACE_SCRIPT) { + SpaceScript *scr = (SpaceScript *)sl; scr->but_refs = NULL; - writestruct(wd, DATA, "SpaceScript", 1, sl); + writestruct(wd, DATA, SpaceScript, 1, sl); } - else if (sl->spacetype==SPACE_ACTION) { - writestruct(wd, DATA, "SpaceAction", 1, sl); + else if (sl->spacetype == SPACE_ACTION) { + writestruct(wd, DATA, SpaceAction, 1, sl); } - else if (sl->spacetype==SPACE_NLA) { - SpaceNla *snla= (SpaceNla *)sl; - - writestruct(wd, DATA, "SpaceNla", 1, snla); - if (snla->ads) writestruct(wd, DATA, "bDopeSheet", 1, snla->ads); + else if (sl->spacetype == SPACE_NLA) { + SpaceNla *snla = (SpaceNla *)sl; + + writestruct(wd, DATA, SpaceNla, 1, snla); + if (snla->ads) { + writestruct(wd, DATA, bDopeSheet, 1, snla->ads); + } } - else if (sl->spacetype==SPACE_TIME) { - writestruct(wd, DATA, "SpaceTime", 1, sl); + else if (sl->spacetype == SPACE_TIME) { + writestruct(wd, DATA, SpaceTime, 1, sl); } - else if (sl->spacetype==SPACE_NODE) { + else if (sl->spacetype == SPACE_NODE) { SpaceNode *snode = (SpaceNode *)sl; bNodeTreePath *path; - writestruct(wd, DATA, "SpaceNode", 1, snode); - - for (path=snode->treepath.first; path; path=path->next) - writestruct(wd, DATA, "bNodeTreePath", 1, path); + writestruct(wd, DATA, SpaceNode, 1, snode); + + for (path = snode->treepath.first; path; path = path->next) { + writestruct(wd, DATA, bNodeTreePath, 1, path); + } } - else if (sl->spacetype==SPACE_LOGIC) { - writestruct(wd, DATA, "SpaceLogic", 1, sl); + else if (sl->spacetype == SPACE_LOGIC) { + writestruct(wd, DATA, SpaceLogic, 1, sl); } - else if (sl->spacetype==SPACE_CONSOLE) { - SpaceConsole *con = (SpaceConsole*)sl; + else if (sl->spacetype == SPACE_CONSOLE) { + SpaceConsole *con = (SpaceConsole *)sl; ConsoleLine *cl; - for (cl=con->history.first; cl; cl=cl->next) { + for (cl = con->history.first; cl; cl = cl->next) { /* 'len_alloc' is invalid on write, set from 'len' on read */ - writestruct(wd, DATA, "ConsoleLine", 1, cl); - writedata(wd, DATA, cl->len+1, cl->line); + writestruct(wd, DATA, ConsoleLine, 1, cl); + writedata(wd, DATA, cl->len + 1, cl->line); } - writestruct(wd, DATA, "SpaceConsole", 1, sl); + writestruct(wd, DATA, SpaceConsole, 1, sl); } - else if (sl->spacetype==SPACE_USERPREF) { - writestruct(wd, DATA, "SpaceUserPref", 1, sl); + else if (sl->spacetype == SPACE_USERPREF) { + writestruct(wd, DATA, SpaceUserPref, 1, sl); } - else if (sl->spacetype==SPACE_CLIP) { - writestruct(wd, DATA, "SpaceClip", 1, sl); + else if (sl->spacetype == SPACE_CLIP) { + writestruct(wd, DATA, SpaceClip, 1, sl); } else if (sl->spacetype == SPACE_INFO) { - writestruct(wd, DATA, "SpaceInfo", 1, sl); + writestruct(wd, DATA, SpaceInfo, 1, sl); } - sl= sl->next; + sl = sl->next; } } - sc= sc->id.next; + sc = sc->id.next; } - BLI_linklist_freeN(tmp_mem_list); - - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_bone(WriteData *wd, Bone *bone) { - Bone* cbone; - - // PATCH for upward compatibility after 2.37+ armature recode + /* PATCH for upward compatibility after 2.37+ armature recode */ bone->size[0] = bone->size[1] = bone->size[2] = 1.0f; - - // Write this bone - writestruct(wd, DATA, "Bone", 1, bone); + + /* Write this bone */ + writestruct(wd, DATA, Bone, 1, bone); /* Write ID Properties -- and copy this comment EXACTLY for easy finding * of library blocks that implement this.*/ - if (bone->prop) + if (bone->prop) { IDP_WriteProperty(bone->prop, wd); - - // Write Children - cbone= bone->childbase.first; - while (cbone) { + } + + /* Write Children */ + for (Bone *cbone = bone->childbase.first; cbone; cbone = cbone->next) { write_bone(wd, cbone); - cbone= cbone->next; } } static void write_armatures(WriteData *wd, ListBase *idbase) { - bArmature *arm; - Bone *bone; + bArmature *arm; + Bone *bone; - arm=idbase->first; + arm = idbase->first; while (arm) { - if (arm->id.us>0 || wd->current) { - writestruct(wd, ID_AR, "bArmature", 1, arm); + if (arm->id.us > 0 || wd->current) { + writestruct(wd, ID_AR, bArmature, 1, arm); write_iddata(wd, &arm->id); - if (arm->adt) write_animdata(wd, arm->adt); + if (arm->adt) { + write_animdata(wd, arm->adt); + } /* Direct data */ - bone= arm->bonebase.first; + bone = arm->bonebase.first; while (bone) { write_bone(wd, bone); - bone=bone->next; + bone = bone->next; } } - arm=arm->id.next; + arm = arm->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_texts(WriteData *wd, ListBase *idbase) @@ -2934,53 +3195,58 @@ static void write_texts(WriteData *wd, ListBase *idbase) Text *text; TextLine *tmp; - text= idbase->first; + text = idbase->first; while (text) { - if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) text->flags &= ~TXT_ISEXT; + if ( (text->flags & TXT_ISMEM) && (text->flags & TXT_ISEXT)) { + text->flags &= ~TXT_ISEXT; + } /* write LibData */ - writestruct(wd, ID_TXT, "Text", 1, text); + writestruct(wd, ID_TXT, Text, 1, text); write_iddata(wd, &text->id); - if (text->name) writedata(wd, DATA, strlen(text->name)+1, text->name); + if (text->name) { + writedata(wd, DATA, strlen(text->name) + 1, text->name); + } if (!(text->flags & TXT_ISEXT)) { /* now write the text data, in two steps for optimization in the readfunction */ - tmp= text->lines.first; + tmp = text->lines.first; while (tmp) { - writestruct(wd, DATA, "TextLine", 1, tmp); - tmp= tmp->next; + writestruct(wd, DATA, TextLine, 1, tmp); + tmp = tmp->next; } - tmp= text->lines.first; + tmp = text->lines.first; while (tmp) { - writedata(wd, DATA, tmp->len+1, tmp->line); - tmp= tmp->next; + writedata(wd, DATA, tmp->len + 1, tmp->line); + tmp = tmp->next; } } - text= text->id.next; + text = text->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_speakers(WriteData *wd, ListBase *idbase) { Speaker *spk; - spk= idbase->first; + spk = idbase->first; while (spk) { - if (spk->id.us>0 || wd->current) { + if (spk->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_SPK, "Speaker", 1, spk); + writestruct(wd, ID_SPK, Speaker, 1, spk); write_iddata(wd, &spk->id); - if (spk->adt) write_animdata(wd, spk->adt); + if (spk->adt) { + write_animdata(wd, spk->adt); + } } - spk= spk->id.next; + spk = spk->id.next; } } @@ -2988,26 +3254,25 @@ static void write_sounds(WriteData *wd, ListBase *idbase) { bSound *sound; - PackedFile * pf; + PackedFile *pf; - sound= idbase->first; + sound = idbase->first; while (sound) { - if (sound->id.us>0 || wd->current) { + if (sound->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_SO, "bSound", 1, sound); + writestruct(wd, ID_SO, bSound, 1, sound); write_iddata(wd, &sound->id); if (sound->packedfile) { pf = sound->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); } } - sound= sound->id.next; + sound = sound->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_groups(WriteData *wd, ListBase *idbase) @@ -3015,30 +3280,32 @@ static void write_groups(WriteData *wd, ListBase *idbase) Group *group; GroupObject *go; - for (group= idbase->first; group; group= group->id.next) { - if (group->id.us>0 || wd->current) { + for (group = idbase->first; group; group = group->id.next) { + if (group->id.us > 0 || wd->current) { /* write LibData */ - writestruct(wd, ID_GR, "Group", 1, group); + writestruct(wd, ID_GR, Group, 1, group); write_iddata(wd, &group->id); write_previews(wd, group->preview); - go= group->gobject.first; + go = group->gobject.first; while (go) { - writestruct(wd, DATA, "GroupObject", 1, go); - go= go->next; + writestruct(wd, DATA, GroupObject, 1, go); + go = go->next; } } } + + mywrite_flush(wd); } static void write_nodetrees(WriteData *wd, ListBase *idbase) { bNodeTree *ntree; - - for (ntree=idbase->first; ntree; ntree= ntree->id.next) { - if (ntree->id.us>0 || wd->current) { - writestruct(wd, ID_NT, "bNodeTree", 1, ntree); + + for (ntree = idbase->first; ntree; ntree = ntree->id.next) { + if (ntree->id.us > 0 || wd->current) { + writestruct(wd, ID_NT, bNodeTree, 1, ntree); /* Note that trees directly used by other IDs (materials etc.) are not 'real' ID, they cannot * be linked, etc., so we write actual id data here only, for 'real' ID trees. */ write_iddata(wd, &ntree->id); @@ -3053,11 +3320,12 @@ static void customnodes_add_deprecated_data(Main *mainvar) { FOREACH_NODETREE(mainvar, ntree, id) { bNodeLink *link, *last_link = ntree->links.last; - + /* only do this for node groups */ - if (id != &ntree->id) + if (id != &ntree->id) { continue; - + } + /* Forward compatibility for group nodes: add links to node tree interface sockets. * These links are invalid by new rules (missing node pointer)! * They will be removed again in customnodes_free_deprecated_data, @@ -3068,7 +3336,7 @@ static void customnodes_add_deprecated_data(Main *mainvar) for (link = ntree->links.first; link; link = link->next) { bNode *fromnode = link->fromnode, *tonode = link->tonode; bNodeSocket *fromsock = link->fromsock, *tosock = link->tosock; - + /* check both sides of the link, to handle direct input-to-output links */ if (fromnode->type == NODE_GROUP_INPUT) { fromnode = NULL; @@ -3079,22 +3347,23 @@ static void customnodes_add_deprecated_data(Main *mainvar) tonode = NULL; tosock = ntreeFindSocketInterface(ntree, SOCK_OUT, tosock->identifier); } - + if (!fromnode || !tonode) { /* Note: not using nodeAddLink here, it asserts existing node pointers */ bNodeLink *tlink = MEM_callocN(sizeof(bNodeLink), "group node link"); tlink->fromnode = fromnode; tlink->fromsock = fromsock; tlink->tonode = tonode; - tlink->tosock= tosock; + tlink->tosock = tosock; tosock->link = tlink; tlink->flag |= NODE_LINK_VALID; BLI_addtail(&ntree->links, tlink); } - + /* don't check newly created compatibility links */ - if (link == last_link) + if (link == last_link) { break; + } } } FOREACH_NODETREE_END @@ -3104,11 +3373,12 @@ static void customnodes_free_deprecated_data(Main *mainvar) { FOREACH_NODETREE(mainvar, ntree, id) { bNodeLink *link, *next_link; - + for (link = ntree->links.first; link; link = next_link) { next_link = link->next; - if (link->fromnode == NULL || link->tonode == NULL) + if (link->fromnode == NULL || link->tonode == NULL) { nodeRemLink(ntree, link); + } } } FOREACH_NODETREE_END @@ -3118,16 +3388,18 @@ static void customnodes_free_deprecated_data(Main *mainvar) static void write_brushes(WriteData *wd, ListBase *idbase) { Brush *brush; - - for (brush=idbase->first; brush; brush= brush->id.next) { - if (brush->id.us>0 || wd->current) { - writestruct(wd, ID_BR, "Brush", 1, brush); + + for (brush = idbase->first; brush; brush = brush->id.next) { + if (brush->id.us > 0 || wd->current) { + writestruct(wd, ID_BR, Brush, 1, brush); write_iddata(wd, &brush->id); - if (brush->curve) + if (brush->curve) { write_curvemapping(wd, brush->curve); - if (brush->gradient) - writestruct(wd, DATA, "ColorBand", 1, brush->gradient); + } + if (brush->gradient) { + writestruct(wd, DATA, ColorBand, 1, brush->gradient); + } } } } @@ -3139,11 +3411,12 @@ static void write_palettes(WriteData *wd, ListBase *idbase) for (palette = idbase->first; palette; palette = palette->id.next) { if (palette->id.us > 0 || wd->current) { PaletteColor *color; - writestruct(wd, ID_PAL, "Palette", 1, palette); + writestruct(wd, ID_PAL, Palette, 1, palette); write_iddata(wd, &palette->id); - for (color = palette->colors.first; color; color= color->next) - writestruct(wd, DATA, "PaletteColor", 1, color); + for (color = palette->colors.first; color; color = color->next) { + writestruct(wd, DATA, PaletteColor, 1, color); + } } } } @@ -3154,10 +3427,10 @@ static void write_paintcurves(WriteData *wd, ListBase *idbase) for (pc = idbase->first; pc; pc = pc->id.next) { if (pc->id.us > 0 || wd->current) { - writestruct(wd, ID_PC, "PaintCurve", 1, pc); + writestruct(wd, ID_PC, PaintCurve, 1, pc); write_iddata(wd, &pc->id); - writestruct(wd, DATA, "PaintCurvePoint", pc->tot_points, pc->points); + writestruct(wd, DATA, PaintCurvePoint, pc->tot_points, pc->points); } } } @@ -3166,14 +3439,15 @@ static void write_movieTracks(WriteData *wd, ListBase *tracks) { MovieTrackingTrack *track; - track= tracks->first; + track = tracks->first; while (track) { - writestruct(wd, DATA, "MovieTrackingTrack", 1, track); + writestruct(wd, DATA, MovieTrackingTrack, 1, track); - if (track->markers) - writestruct(wd, DATA, "MovieTrackingMarker", track->markersnr, track->markers); + if (track->markers) { + writestruct(wd, DATA, MovieTrackingMarker, track->markersnr, track->markers); + } - track= track->next; + track = track->next; } } @@ -3185,56 +3459,57 @@ static void write_moviePlaneTracks(WriteData *wd, ListBase *plane_tracks_base) plane_track; plane_track = plane_track->next) { - writestruct(wd, DATA, "MovieTrackingPlaneTrack", 1, plane_track); + writestruct(wd, DATA, MovieTrackingPlaneTrack, 1, plane_track); writedata(wd, DATA, sizeof(MovieTrackingTrack *) * plane_track->point_tracksnr, plane_track->point_tracks); - writestruct(wd, DATA, "MovieTrackingPlaneMarker", plane_track->markersnr, plane_track->markers); + writestruct(wd, DATA, MovieTrackingPlaneMarker, plane_track->markersnr, plane_track->markers); } } static void write_movieReconstruction(WriteData *wd, MovieTrackingReconstruction *reconstruction) { - if (reconstruction->camnr) - writestruct(wd, DATA, "MovieReconstructedCamera", reconstruction->camnr, reconstruction->cameras); + if (reconstruction->camnr) { + writestruct(wd, DATA, MovieReconstructedCamera, reconstruction->camnr, reconstruction->cameras); + } } static void write_movieclips(WriteData *wd, ListBase *idbase) { MovieClip *clip; - clip= idbase->first; + clip = idbase->first; while (clip) { - if (clip->id.us>0 || wd->current) { - MovieTracking *tracking= &clip->tracking; + if (clip->id.us > 0 || wd->current) { + MovieTracking *tracking = &clip->tracking; MovieTrackingObject *object; - writestruct(wd, ID_MC, "MovieClip", 1, clip); + writestruct(wd, ID_MC, MovieClip, 1, clip); write_iddata(wd, &clip->id); - if (clip->adt) + if (clip->adt) { write_animdata(wd, clip->adt); + } write_movieTracks(wd, &tracking->tracks); write_moviePlaneTracks(wd, &tracking->plane_tracks); write_movieReconstruction(wd, &tracking->reconstruction); - object= tracking->objects.first; + object = tracking->objects.first; while (object) { - writestruct(wd, DATA, "MovieTrackingObject", 1, object); + writestruct(wd, DATA, MovieTrackingObject, 1, object); write_movieTracks(wd, &object->tracks); write_moviePlaneTracks(wd, &object->plane_tracks); write_movieReconstruction(wd, &object->reconstruction); - object= object->next; + object = object->next; } } - clip= clip->id.next; + clip = clip->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_masks(WriteData *wd, ListBase *idbase) @@ -3246,17 +3521,18 @@ static void write_masks(WriteData *wd, ListBase *idbase) if (mask->id.us > 0 || wd->current) { MaskLayer *masklay; - writestruct(wd, ID_MSK, "Mask", 1, mask); + writestruct(wd, ID_MSK, Mask, 1, mask); write_iddata(wd, &mask->id); - if (mask->adt) + if (mask->adt) { write_animdata(wd, mask->adt); + } for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { MaskSpline *spline; MaskLayerShape *masklay_shape; - writestruct(wd, DATA, "MaskLayer", 1, masklay); + writestruct(wd, DATA, MaskLayer, 1, masklay); for (spline = masklay->splines.first; spline; spline = spline->next) { int i; @@ -3264,22 +3540,28 @@ static void write_masks(WriteData *wd, ListBase *idbase) void *points_deform = spline->points_deform; spline->points_deform = NULL; - writestruct(wd, DATA, "MaskSpline", 1, spline); - writestruct(wd, DATA, "MaskSplinePoint", spline->tot_point, spline->points); + writestruct(wd, DATA, MaskSpline, 1, spline); + writestruct(wd, DATA, MaskSplinePoint, spline->tot_point, spline->points); spline->points_deform = points_deform; for (i = 0; i < spline->tot_point; i++) { MaskSplinePoint *point = &spline->points[i]; - if (point->tot_uw) - writestruct(wd, DATA, "MaskSplinePointUW", point->tot_uw, point->uw); + if (point->tot_uw) { + writestruct(wd, DATA, MaskSplinePointUW, point->tot_uw, point->uw); + } } } - for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { - writestruct(wd, DATA, "MaskLayerShape", 1, masklay_shape); - writedata(wd, DATA, masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, masklay_shape->data); + for (masklay_shape = masklay->splines_shapes.first; + masklay_shape; + masklay_shape = masklay_shape->next) + { + writestruct(wd, DATA, MaskLayerShape, 1, masklay_shape); + writedata(wd, DATA, + masklay_shape->tot_vert * sizeof(float) * MASK_OBJECT_SHAPE_ELEM_SIZE, + masklay_shape->data); } } } @@ -3287,72 +3569,71 @@ static void write_masks(WriteData *wd, ListBase *idbase) mask = mask->id.next; } - /* flush helps the compression for undo-save */ - mywrite(wd, MYWRITE_FLUSH, 0); + mywrite_flush(wd); } static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleColorModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleColorModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleColorModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleColorModifier_Material"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleColorModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleColorModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleColorModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleColorModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleColorModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Material); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleColorModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp); - break; - case LS_MODIFIER_MATERIAL: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Material *)m)->color_ramp); - break; - case LS_MODIFIER_TANGENT: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp); - break; - case LS_MODIFIER_NOISE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Noise *)m)->color_ramp); - break; - case LS_MODIFIER_CREASE_ANGLE: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp); - break; - case LS_MODIFIER_CURVATURE_3D: - writestruct(wd, DATA, "ColorBand", 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp); - break; + case LS_MODIFIER_ALONG_STROKE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_AlongStroke *)m)->color_ramp); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromCamera *)m)->color_ramp); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_DistanceFromObject *)m)->color_ramp); + break; + case LS_MODIFIER_MATERIAL: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Material *)m)->color_ramp); + break; + case LS_MODIFIER_TANGENT: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Tangent *)m)->color_ramp); + break; + case LS_MODIFIER_NOISE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Noise *)m)->color_ramp); + break; + case LS_MODIFIER_CREASE_ANGLE: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_CreaseAngle *)m)->color_ramp); + break; + case LS_MODIFIER_CURVATURE_3D: + writestruct(wd, DATA, ColorBand, 1, ((LineStyleColorModifier_Curvature_3D *)m)->color_ramp); + break; } } } @@ -3360,65 +3641,65 @@ static void write_linestyle_color_modifiers(WriteData *wd, ListBase *modifiers) static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleAlphaModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleAlphaModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleAlphaModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleAlphaModifier_Material"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleAlphaModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleAlphaModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleAlphaModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleAlphaModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleAlphaModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Material); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleAlphaModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_NOISE: - write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); - break; + case LS_MODIFIER_ALONG_STROKE: + write_curvemapping(wd, ((LineStyleAlphaModifier_AlongStroke *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromCamera *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + write_curvemapping(wd, ((LineStyleAlphaModifier_DistanceFromObject *)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + write_curvemapping(wd, ((LineStyleAlphaModifier_Material *)m)->curve); + break; + case LS_MODIFIER_TANGENT: + write_curvemapping(wd, ((LineStyleAlphaModifier_Tangent *)m)->curve); + break; + case LS_MODIFIER_NOISE: + write_curvemapping(wd, ((LineStyleAlphaModifier_Noise *)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + write_curvemapping(wd, ((LineStyleAlphaModifier_CreaseAngle *)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + write_curvemapping(wd, ((LineStyleAlphaModifier_Curvature_3D *)m)->curve); + break; } } } @@ -3426,65 +3707,65 @@ static void write_linestyle_alpha_modifiers(WriteData *wd, ListBase *modifiers) static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - struct_name = "LineStyleThicknessModifier_AlongStroke"; - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - struct_name = "LineStyleThicknessModifier_DistanceFromCamera"; - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - struct_name = "LineStyleThicknessModifier_DistanceFromObject"; - break; - case LS_MODIFIER_MATERIAL: - struct_name = "LineStyleThicknessModifier_Material"; - break; - case LS_MODIFIER_CALLIGRAPHY: - struct_name = "LineStyleThicknessModifier_Calligraphy"; - break; - case LS_MODIFIER_TANGENT: - struct_name = "LineStyleThicknessModifier_Tangent"; - break; - case LS_MODIFIER_NOISE: - struct_name = "LineStyleThicknessModifier_Noise"; - break; - case LS_MODIFIER_CREASE_ANGLE: - struct_name = "LineStyleThicknessModifier_CreaseAngle"; - break; - case LS_MODIFIER_CURVATURE_3D: - struct_name = "LineStyleThicknessModifier_Curvature_3D"; - break; - default: - struct_name = "LineStyleThicknessModifier"; /* this should not happen */ + case LS_MODIFIER_ALONG_STROKE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_AlongStroke); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromCamera); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_DistanceFromObject); + break; + case LS_MODIFIER_MATERIAL: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Material); + break; + case LS_MODIFIER_CALLIGRAPHY: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Calligraphy); + break; + case LS_MODIFIER_TANGENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Tangent); + break; + case LS_MODIFIER_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Noise); + break; + case LS_MODIFIER_CREASE_ANGLE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_CreaseAngle); + break; + case LS_MODIFIER_CURVATURE_3D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleThicknessModifier_Curvature_3D); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } for (m = modifiers->first; m; m = m->next) { switch (m->type) { - case LS_MODIFIER_ALONG_STROKE: - write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_CAMERA: - write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); - break; - case LS_MODIFIER_DISTANCE_FROM_OBJECT: - write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); - break; - case LS_MODIFIER_MATERIAL: - write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve); - break; - case LS_MODIFIER_TANGENT: - write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve); - break; - case LS_MODIFIER_CREASE_ANGLE: - write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); - break; - case LS_MODIFIER_CURVATURE_3D: - write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); - break; + case LS_MODIFIER_ALONG_STROKE: + write_curvemapping(wd, ((LineStyleThicknessModifier_AlongStroke *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_CAMERA: + write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromCamera *)m)->curve); + break; + case LS_MODIFIER_DISTANCE_FROM_OBJECT: + write_curvemapping(wd, ((LineStyleThicknessModifier_DistanceFromObject *)m)->curve); + break; + case LS_MODIFIER_MATERIAL: + write_curvemapping(wd, ((LineStyleThicknessModifier_Material *)m)->curve); + break; + case LS_MODIFIER_TANGENT: + write_curvemapping(wd, ((LineStyleThicknessModifier_Tangent *)m)->curve); + break; + case LS_MODIFIER_CREASE_ANGLE: + write_curvemapping(wd, ((LineStyleThicknessModifier_CreaseAngle *)m)->curve); + break; + case LS_MODIFIER_CURVATURE_3D: + write_curvemapping(wd, ((LineStyleThicknessModifier_Curvature_3D *)m)->curve); + break; } } } @@ -3492,56 +3773,56 @@ static void write_linestyle_thickness_modifiers(WriteData *wd, ListBase *modifie static void write_linestyle_geometry_modifiers(WriteData *wd, ListBase *modifiers) { LineStyleModifier *m; - const char *struct_name; for (m = modifiers->first; m; m = m->next) { + int struct_nr; switch (m->type) { - case LS_MODIFIER_SAMPLING: - struct_name = "LineStyleGeometryModifier_Sampling"; - break; - case LS_MODIFIER_BEZIER_CURVE: - struct_name = "LineStyleGeometryModifier_BezierCurve"; - break; - case LS_MODIFIER_SINUS_DISPLACEMENT: - struct_name = "LineStyleGeometryModifier_SinusDisplacement"; - break; - case LS_MODIFIER_SPATIAL_NOISE: - struct_name = "LineStyleGeometryModifier_SpatialNoise"; - break; - case LS_MODIFIER_PERLIN_NOISE_1D: - struct_name = "LineStyleGeometryModifier_PerlinNoise1D"; - break; - case LS_MODIFIER_PERLIN_NOISE_2D: - struct_name = "LineStyleGeometryModifier_PerlinNoise2D"; - break; - case LS_MODIFIER_BACKBONE_STRETCHER: - struct_name = "LineStyleGeometryModifier_BackboneStretcher"; - break; - case LS_MODIFIER_TIP_REMOVER: - struct_name = "LineStyleGeometryModifier_TipRemover"; - break; - case LS_MODIFIER_POLYGONIZATION: - struct_name = "LineStyleGeometryModifier_Polygonalization"; - break; - case LS_MODIFIER_GUIDING_LINES: - struct_name = "LineStyleGeometryModifier_GuidingLines"; - break; - case LS_MODIFIER_BLUEPRINT: - struct_name = "LineStyleGeometryModifier_Blueprint"; - break; - case LS_MODIFIER_2D_OFFSET: - struct_name = "LineStyleGeometryModifier_2DOffset"; - break; - case LS_MODIFIER_2D_TRANSFORM: - struct_name = "LineStyleGeometryModifier_2DTransform"; - break; - case LS_MODIFIER_SIMPLIFICATION: - struct_name = "LineStyleGeometryModifier_Simplification"; - break; - default: - struct_name = "LineStyleGeometryModifier"; /* this should not happen */ + case LS_MODIFIER_SAMPLING: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Sampling); + break; + case LS_MODIFIER_BEZIER_CURVE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BezierCurve); + break; + case LS_MODIFIER_SINUS_DISPLACEMENT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SinusDisplacement); + break; + case LS_MODIFIER_SPATIAL_NOISE: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_SpatialNoise); + break; + case LS_MODIFIER_PERLIN_NOISE_1D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise1D); + break; + case LS_MODIFIER_PERLIN_NOISE_2D: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_PerlinNoise2D); + break; + case LS_MODIFIER_BACKBONE_STRETCHER: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_BackboneStretcher); + break; + case LS_MODIFIER_TIP_REMOVER: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_TipRemover); + break; + case LS_MODIFIER_POLYGONIZATION: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Polygonalization); + break; + case LS_MODIFIER_GUIDING_LINES: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_GuidingLines); + break; + case LS_MODIFIER_BLUEPRINT: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Blueprint); + break; + case LS_MODIFIER_2D_OFFSET: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DOffset); + break; + case LS_MODIFIER_2D_TRANSFORM: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_2DTransform); + break; + case LS_MODIFIER_SIMPLIFICATION: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleGeometryModifier_Simplification); + break; + default: + struct_nr = SDNA_TYPE_FROM_STRUCT(LineStyleModifier); /* this should not happen */ } - writestruct(wd, DATA, struct_name, 1, m); + writestruct_nr(wd, DATA, struct_nr, 1, m); } } @@ -3551,21 +3832,25 @@ static void write_linestyles(WriteData *wd, ListBase *idbase) int a; for (linestyle = idbase->first; linestyle; linestyle = linestyle->id.next) { - if (linestyle->id.us>0 || wd->current) { - writestruct(wd, ID_LS, "FreestyleLineStyle", 1, linestyle); + if (linestyle->id.us > 0 || wd->current) { + writestruct(wd, ID_LS, FreestyleLineStyle, 1, linestyle); write_iddata(wd, &linestyle->id); - if (linestyle->adt) + if (linestyle->adt) { write_animdata(wd, linestyle->adt); + } + write_linestyle_color_modifiers(wd, &linestyle->color_modifiers); write_linestyle_alpha_modifiers(wd, &linestyle->alpha_modifiers); write_linestyle_thickness_modifiers(wd, &linestyle->thickness_modifiers); write_linestyle_geometry_modifiers(wd, &linestyle->geometry_modifiers); - for (a=0; a<MAX_MTEX; a++) { - if (linestyle->mtex[a]) writestruct(wd, DATA, "MTex", 1, linestyle->mtex[a]); + for (a = 0; a < MAX_MTEX; a++) { + if (linestyle->mtex[a]) { + writestruct(wd, DATA, MTex, 1, linestyle->mtex[a]); + } } if (linestyle->nodetree) { - writestruct(wd, DATA, "bNodeTree", 1, linestyle->nodetree); + writestruct(wd, DATA, bNodeTree, 1, linestyle->nodetree); write_nodetree(wd, linestyle->nodetree); } } @@ -3580,23 +3865,26 @@ static void write_libraries(WriteData *wd, Main *main) int a, tot; bool found_one; - for (; main; main= main->next) { + for (; main; main = main->next) { - a=tot= set_listbasepointers(main, lbarray); + a = tot = set_listbasepointers(main, lbarray); /* test: is lib being used */ - if (main->curlib && main->curlib->packedfile) + if (main->curlib && main->curlib->packedfile) { found_one = true; + } else { found_one = false; while (tot--) { - for (id= lbarray[tot]->first; id; id= id->next) { + for (id = lbarray[tot]->first; id; id = id->next) { if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { found_one = true; break; } } - if (found_one) break; + if (found_one) { + break; + } } } @@ -3604,31 +3892,34 @@ static void write_libraries(WriteData *wd, Main *main) /* XXX needs rethink, just like save UI in undo files now - would be nice to append things only for the] * quit.blend and temp saves */ if (found_one) { - writestruct(wd, ID_LI, "Library", 1, main->curlib); + writestruct(wd, ID_LI, Library, 1, main->curlib); write_iddata(wd, &main->curlib->id); if (main->curlib->packedfile) { PackedFile *pf = main->curlib->packedfile; - writestruct(wd, DATA, "PackedFile", 1, pf); + writestruct(wd, DATA, PackedFile, 1, pf); writedata(wd, DATA, pf->size, pf->data); - if (wd->current == NULL) + if (wd->current == NULL) { printf("write packed .blend: %s\n", main->curlib->name); + } } while (a--) { - for (id= lbarray[a]->first; id; id= id->next) { + for (id = lbarray[a]->first; id; id = id->next) { if (id->us > 0 && (id->tag & LIB_TAG_EXTERN)) { if (!BKE_idcode_is_linkable(GS(id->name))) { printf("ERROR: write file: datablock '%s' from lib '%s' is not linkable " "but is flagged as directly linked", id->name, main->curlib->filepath); BLI_assert(0); } - writestruct(wd, ID_ID, "ID", 1, id); + writestruct(wd, ID_ID, ID, 1, id); } } } } } + + mywrite_flush(wd); } /* context is usually defined by WM, two cases where no WM is available: @@ -3640,7 +3931,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) FileGlobal fg; bScreen *screen; char subvstr[8]; - + /* prevent mem checkers from complaining */ memset(fg.pad, 0, sizeof(fg.pad)); memset(fg.filename, 0, sizeof(fg.filename)); @@ -3649,20 +3940,20 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) current_screen_compat(mainvar, &screen, is_undo); /* XXX still remap G */ - fg.curscreen= screen; - fg.curscene= screen ? screen->scene : NULL; + fg.curscreen = screen; + fg.curscene = screen ? screen->scene : NULL; /* prevent to save this, is not good convention, and feature with concerns... */ - fg.fileflags= (fileflags & ~G_FILE_FLAGS_RUNTIME); + fg.fileflags = (fileflags & ~G_FILE_FLAGS_RUNTIME); - fg.globalf= G.f; + fg.globalf = G.f; BLI_strncpy(fg.filename, mainvar->name, sizeof(fg.filename)); sprintf(subvstr, "%4d", BLENDER_SUBVERSION); memcpy(fg.subvstr, subvstr, 4); - - fg.subversion= BLENDER_SUBVERSION; - fg.minversion= BLENDER_MINVERSION; - fg.minsubversion= BLENDER_MINSUBVERSION; + + fg.subversion = BLENDER_SUBVERSION; + fg.minversion = BLENDER_MINVERSION; + fg.minsubversion = BLENDER_MINSUBVERSION; #ifdef WITH_BUILDINFO { extern unsigned long build_commit_timestamp; @@ -3675,7 +3966,7 @@ static void write_global(WriteData *wd, int fileflags, Main *mainvar) fg.build_commit_timestamp = 0; BLI_strncpy(fg.build_hash, "unknown", sizeof(fg.build_hash)); #endif - writestruct(wd, GLOB, "FileGlobal", 1, &fg); + writestruct(wd, GLOB, FileGlobal, 1, &fg); } /* preview image, first 2 values are width and height @@ -3690,11 +3981,11 @@ static void write_thumb(WriteData *wd, const BlendThumbnail *thumb) } /* if MemFile * there's filesave to memory */ -static int write_file_handle( +static bool write_file_handle( Main *mainvar, WriteWrap *ww, MemFile *compare, MemFile *current, - int write_user_block, int write_flags, const BlendThumbnail *thumb) + int write_flags, const BlendThumbnail *thumb) { BHead bhead; ListBase mainlist; @@ -3728,44 +4019,54 @@ static int write_file_handle( write_thumb(wd, thumb); write_global(wd, write_flags, mainvar); + /* The windowmanager and screen often change, + * avoid thumbnail detecting changes because of this. */ + mywrite_flush(wd); + write_windowmanagers(wd, &mainvar->wm); - write_screens (wd, &mainvar->screen); - write_movieclips (wd, &mainvar->movieclip); - write_masks (wd, &mainvar->mask); - write_scenes (wd, &mainvar->scene); - write_curves (wd, &mainvar->curve); - write_mballs (wd, &mainvar->mball); - write_images (wd, &mainvar->image); - write_cameras (wd, &mainvar->camera); - write_lamps (wd, &mainvar->lamp); - write_lattices (wd, &mainvar->latt); - write_vfonts (wd, &mainvar->vfont); - write_keys (wd, &mainvar->key); - write_worlds (wd, &mainvar->world); - write_texts (wd, &mainvar->text); - write_speakers (wd, &mainvar->speaker); - write_sounds (wd, &mainvar->sound); - write_groups (wd, &mainvar->group); + write_screens(wd, &mainvar->screen); + write_movieclips(wd, &mainvar->movieclip); + write_masks(wd, &mainvar->mask); + write_scenes(wd, &mainvar->scene); + write_curves(wd, &mainvar->curve); + write_mballs(wd, &mainvar->mball); + write_images(wd, &mainvar->image); + write_cameras(wd, &mainvar->camera); + write_lamps(wd, &mainvar->lamp); + write_lattices(wd, &mainvar->latt); + write_vfonts(wd, &mainvar->vfont); + write_keys(wd, &mainvar->key); + write_worlds(wd, &mainvar->world); + write_texts(wd, &mainvar->text); + write_speakers(wd, &mainvar->speaker); + write_sounds(wd, &mainvar->sound); + write_groups(wd, &mainvar->group); write_armatures(wd, &mainvar->armature); - write_actions (wd, &mainvar->action); - write_objects (wd, &mainvar->object); + write_actions(wd, &mainvar->action); + write_objects(wd, &mainvar->object); write_materials(wd, &mainvar->mat); - write_textures (wd, &mainvar->tex); - write_meshes (wd, &mainvar->mesh); + write_textures(wd, &mainvar->tex); + write_meshes(wd, &mainvar->mesh); write_particlesettings(wd, &mainvar->particle); write_nodetrees(wd, &mainvar->nodetree); - write_brushes (wd, &mainvar->brush); - write_palettes (wd, &mainvar->palettes); - write_paintcurves (wd, &mainvar->paintcurves); - write_gpencils (wd, &mainvar->gpencil); + write_brushes(wd, &mainvar->brush); + write_palettes(wd, &mainvar->palettes); + write_paintcurves(wd, &mainvar->paintcurves); + write_gpencils(wd, &mainvar->gpencil); write_linestyles(wd, &mainvar->linestyle); write_libraries(wd, mainvar->next); - if (write_user_block) { + /* So changes above don't cause a 'DNA1' to be detected as changed on undo. */ + mywrite_flush(wd); + + if (write_flags & G_FILE_USERPREFS) { write_userdef(wd); } - - /* dna as last, because (to be implemented) test for which structs are written */ + + /* Write DNA last, because (to be implemented) test for which structs are written. + * + * Note that we *borrow* the pointer to 'DNAstr', + * so writing each time uses the same address and doesn't cause unnecessary undo overhead. */ writedata(wd, DNA1, wd->sdna->datalen, wd->sdna->data); #ifdef USE_NODE_COMPAT_CUSTOMNODES @@ -3781,7 +4082,7 @@ static int write_file_handle( /* end of file */ memset(&bhead, 0, sizeof(BHead)); - bhead.code= ENDB; + bhead.code = ENDB; mywrite(wd, &bhead, sizeof(BHead)); blo_join_main(&mainlist); @@ -3794,16 +4095,19 @@ static int write_file_handle( static bool do_history(const char *name, ReportList *reports) { char tempname1[FILE_MAX], tempname2[FILE_MAX]; - int hisnr= U.versions; - - if (U.versions==0) return 0; - if (strlen(name)<2) { + int hisnr = U.versions; + + if (U.versions == 0) { + return 0; + } + + if (strlen(name) < 2) { BKE_report(reports, RPT_ERROR, "Unable to make version backup: filename too short"); return 1; } while (hisnr > 1) { - BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr-1); + BLI_snprintf(tempname1, sizeof(tempname1), "%s%d", name, hisnr - 1); if (BLI_exists(tempname1)) { BLI_snprintf(tempname2, sizeof(tempname2), "%s%d", name, hisnr); @@ -3835,8 +4139,7 @@ bool BLO_write_file( Main *mainvar, const char *filepath, int write_flags, ReportList *reports, const BlendThumbnail *thumb) { - char tempname[FILE_MAX+1]; - int err, write_user_block; + char tempname[FILE_MAX + 1]; eWriteWrapType ww_type; WriteWrap ww; @@ -3891,13 +4194,13 @@ bool BLO_write_file( } } - write_user_block= write_flags & G_FILE_USERPREFS; - - if (write_flags & G_FILE_RELATIVE_REMAP) - BKE_bpath_relative_convert(mainvar, filepath, NULL); /* note, making relative to something OTHER then G.main->name */ + if (write_flags & G_FILE_RELATIVE_REMAP) { + /* note, making relative to something OTHER then G.main->name */ + BKE_bpath_relative_convert(mainvar, filepath, NULL); + } /* actual file writing */ - err = write_file_handle(mainvar, &ww, NULL, NULL, write_user_block, write_flags, thumb); + const bool err = write_file_handle(mainvar, &ww, NULL, NULL, write_flags, thumb); ww.close(&ww); @@ -3936,9 +4239,9 @@ bool BLO_write_file( */ bool BLO_write_file_mem(Main *mainvar, MemFile *compare, MemFile *current, int write_flags) { - int err; + write_flags &= ~G_FILE_USERPREFS; - err = write_file_handle(mainvar, NULL, compare, current, 0, write_flags, NULL); + const bool err = write_file_handle(mainvar, NULL, compare, current, write_flags, NULL); return (err == 0); } diff --git a/source/blender/bmesh/bmesh_class.h b/source/blender/bmesh/bmesh_class.h index e3caeedd2c9..72ea7bd7f5d 100644 --- a/source/blender/bmesh/bmesh_class.h +++ b/source/blender/bmesh/bmesh_class.h @@ -89,7 +89,6 @@ BLI_STATIC_ASSERT((sizeof(BMHeader) <= 16), "BMHeader size has grown!"); typedef struct BMVert { BMHeader head; - struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */ float co[3]; /* vertex coordinates */ float no[3]; /* vertex normal */ @@ -102,6 +101,11 @@ typedef struct BMVert { struct BMEdge *e; } BMVert; +typedef struct BMVert_OFlag { + BMVert base; + struct BMFlagLayer *oflags; +} BMVert_OFlag; + /* disk link structure, only used by edges */ typedef struct BMDiskLink { struct BMEdge *next, *prev; @@ -109,7 +113,6 @@ typedef struct BMDiskLink { typedef struct BMEdge { BMHeader head; - struct BMFlagLayer *oflags; /* keep after header, an array of flags, mostly used by the operator stack */ struct BMVert *v1, *v2; /* vertices (unordered) */ @@ -122,6 +125,11 @@ typedef struct BMEdge { BMDiskLink v1_disk_link, v2_disk_link; } BMEdge; +typedef struct BMEdge_OFlag { + BMEdge base; + struct BMFlagLayer *oflags; +} BMEdge_OFlag; + typedef struct BMLoop { BMHeader head; /* notice no flags layer */ @@ -142,10 +150,6 @@ typedef struct BMLoop { /* can cast BMFace/BMEdge/BMVert, but NOT BMLoop, since these don't have a flag layer */ typedef struct BMElemF { BMHeader head; - - /* keep directly after header, - * optional array of flags, only used by the operator stack */ - struct BMFlagLayer *oflags; } BMElemF; /* can cast anything to this, including BMLoop */ @@ -163,7 +167,6 @@ typedef struct BMLoopList { typedef struct BMFace { BMHeader head; - struct BMFlagLayer *oflags; /* an array of flags, mostly used by the operator stack */ #ifdef USE_BMESH_HOLES int totbounds; /*total boundaries, is one plus the number of holes in the face*/ @@ -177,6 +180,11 @@ typedef struct BMFace { // short _pad[3]; } BMFace; +typedef struct BMFace_OFlag { + BMFace base; + struct BMFlagLayer *oflags; +} BMFace_OFlag; + typedef struct BMFlagLayer { short f; /* flags */ } BMFlagLayer; @@ -217,6 +225,8 @@ typedef struct BMesh { /* operator api stuff (must be all NULL or all alloc'd) */ struct BLI_mempool *vtoolflagpool, *etoolflagpool, *ftoolflagpool; + unsigned int use_toolflags : 1; + int toolflag_index; struct BMOperator *currentop; @@ -259,10 +269,12 @@ enum { /* args for _Generic */ #define _BM_GENERIC_TYPE_ELEM_NONCONST \ void *, BMVert *, BMEdge *, BMLoop *, BMFace *, \ + BMVert_OFlag *, BMEdge_OFlag *, BMFace_OFlag *, \ BMElem *, BMElemF *, BMHeader * #define _BM_GENERIC_TYPE_ELEM_CONST \ const void *, const BMVert *, const BMEdge *, const BMLoop *, const BMFace *, \ + const BMVert_OFlag *, const BMEdge_OFlag *, const BMFace_OFlag *, \ const BMElem *, const BMElemF *, const BMHeader *, \ void * const, BMVert * const, BMEdge * const, BMLoop * const, BMFace * const, \ BMElem * const, BMElemF * const, BMHeader * const @@ -276,6 +288,27 @@ enum { #define BM_CHECK_TYPE_ELEM(ele) \ CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST, _BM_GENERIC_TYPE_ELEM_CONST) +/* vert */ +#define _BM_GENERIC_TYPE_VERT_NONCONST BMVert *, BMVert_OFlag * +#define _BM_GENERIC_TYPE_VERT_CONST const BMVert *, const BMVert_OFlag * +#define BM_CHECK_TYPE_VERT_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_CONST) +#define BM_CHECK_TYPE_VERT_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_VERT(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_VERT_NONCONST, _BM_GENERIC_TYPE_VERT_CONST) +/* edge */ +#define _BM_GENERIC_TYPE_EDGE_NONCONST BMEdge *, BMEdge_OFlag * +#define _BM_GENERIC_TYPE_EDGE_CONST const BMEdge *, const BMEdge_OFlag * +#define BM_CHECK_TYPE_EDGE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_CONST) +#define BM_CHECK_TYPE_EDGE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_EDGE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_EDGE_NONCONST, _BM_GENERIC_TYPE_EDGE_CONST) +/* face */ +#define _BM_GENERIC_TYPE_FACE_NONCONST BMFace *, BMFace_OFlag * +#define _BM_GENERIC_TYPE_FACE_CONST const BMFace *, const BMFace_OFlag * +#define BM_CHECK_TYPE_FACE_CONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_CONST) +#define BM_CHECK_TYPE_FACE_NONCONST(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_ELEM_NONCONST) +#define BM_CHECK_TYPE_FACE(ele) CHECK_TYPE_ANY(ele, _BM_GENERIC_TYPE_FACE_NONCONST, _BM_GENERIC_TYPE_FACE_CONST) + + + /* Assignment from a void* to a typed pointer is not allowed in C++, * casting the LHS to void works fine though. */ diff --git a/source/blender/bmesh/intern/bmesh_construct.c b/source/blender/bmesh/intern/bmesh_construct.c index fdad93ee90d..4d92baab6eb 100644 --- a/source/blender/bmesh/intern/bmesh_construct.c +++ b/source/blender/bmesh/intern/bmesh_construct.c @@ -714,7 +714,9 @@ BMesh *BM_mesh_copy(BMesh *bm_old) const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm_old); /* allocate a bmesh */ - bm_new = BM_mesh_create(&allocsize); + bm_new = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = bm_old->use_toolflags,})); BM_mesh_copy_init_customdata(bm_new, bm_old, &allocsize); diff --git a/source/blender/bmesh/intern/bmesh_core.c b/source/blender/bmesh/intern/bmesh_core.c index 1d68cdcf28a..e83b752947c 100644 --- a/source/blender/bmesh/intern/bmesh_core.c +++ b/source/blender/bmesh/intern/bmesh_core.c @@ -81,7 +81,9 @@ BMVert *BM_vert_create( v->head.api_flag = 0; /* allocate flags */ - v->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMVert_OFlag *)v)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + } /* 'v->no' is handled by BM_elem_attrs_copy */ if (co) { @@ -174,7 +176,9 @@ BMEdge *BM_edge_create( e->head.api_flag = 0; /* allocate flags */ - e->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMEdge_OFlag *)e)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + } e->v1 = v1; e->v2 = v2; @@ -386,7 +390,9 @@ BLI_INLINE BMFace *bm_face_create__internal(BMesh *bm) f->head.api_flag = 0; /* allocate flags */ - f->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + if (bm->use_toolflags) { + ((BMFace_OFlag *)f)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + } #ifdef USE_BMESH_HOLES BLI_listbase_clear(&f->loops); @@ -758,7 +764,7 @@ static void bm_kill_only_vert(BMesh *bm, BMVert *v) CustomData_bmesh_free_block(&bm->vdata, &v->head.data); if (bm->vtoolflagpool) { - BLI_mempool_free(bm->vtoolflagpool, v->oflags); + BLI_mempool_free(bm->vtoolflagpool, ((BMVert_OFlag *)v)->oflags); } BLI_mempool_free(bm->vpool, v); } @@ -779,7 +785,7 @@ static void bm_kill_only_edge(BMesh *bm, BMEdge *e) CustomData_bmesh_free_block(&bm->edata, &e->head.data); if (bm->etoolflagpool) { - BLI_mempool_free(bm->etoolflagpool, e->oflags); + BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)e)->oflags); } BLI_mempool_free(bm->epool, e); } @@ -803,7 +809,7 @@ static void bm_kill_only_face(BMesh *bm, BMFace *f) CustomData_bmesh_free_block(&bm->pdata, &f->head.data); if (bm->ftoolflagpool) { - BLI_mempool_free(bm->ftoolflagpool, f->oflags); + BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f)->oflags); } BLI_mempool_free(bm->fpool, f); } @@ -2196,7 +2202,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) /* deallocate edge and its two loops as well as f2 */ if (bm->etoolflagpool) { - BLI_mempool_free(bm->etoolflagpool, l_f1->e->oflags); + BLI_mempool_free(bm->etoolflagpool, ((BMEdge_OFlag *)l_f1->e)->oflags); } BLI_mempool_free(bm->epool, l_f1->e); bm->totedge--; @@ -2205,7 +2211,7 @@ BMFace *bmesh_jfke(BMesh *bm, BMFace *f1, BMFace *f2, BMEdge *e) BLI_mempool_free(bm->lpool, l_f2); bm->totloop--; if (bm->ftoolflagpool) { - BLI_mempool_free(bm->ftoolflagpool, f2->oflags); + BLI_mempool_free(bm->ftoolflagpool, ((BMFace_OFlag *)f2)->oflags); } BLI_mempool_free(bm->fpool, f2); bm->totface--; diff --git a/source/blender/bmesh/intern/bmesh_delete.c b/source/blender/bmesh/intern/bmesh_delete.c index 882d78ce6b3..1449a6ef9d7 100644 --- a/source/blender/bmesh/intern/bmesh_delete.c +++ b/source/blender/bmesh/intern/bmesh_delete.c @@ -54,7 +54,7 @@ static void bmo_remove_tagged_faces(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (f, f_next, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, oflag)) { + if (BMO_face_flag_test(bm, f, oflag)) { BM_face_kill(bm, f); } } @@ -66,7 +66,7 @@ static void bmo_remove_tagged_edges(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, oflag)) { + if (BMO_edge_flag_test(bm, e, oflag)) { BM_edge_kill(bm, e); } } @@ -78,7 +78,7 @@ static void bmo_remove_tagged_verts(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag)) { + if (BMO_vert_flag_test(bm, v, oflag)) { BM_vert_kill(bm, v); } } @@ -90,7 +90,7 @@ static void bmo_remove_tagged_verts_loose(BMesh *bm, const short oflag) BMIter iter; BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag) && (v->e == NULL)) { + if (BMO_vert_flag_test(bm, v, oflag) && (v->e == NULL)) { BM_vert_kill(bm, v); } } @@ -132,9 +132,9 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) { /* flush down to vert */ BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, oflag)) { - BMO_elem_flag_enable(bm, e->v1, oflag); - BMO_elem_flag_enable(bm, e->v2, oflag); + if (BMO_edge_flag_test(bm, e, oflag)) { + BMO_vert_flag_enable(bm, e->v1, oflag); + BMO_vert_flag_enable(bm, e->v2, oflag); } } bmo_remove_tagged_edges(bm, oflag); @@ -165,27 +165,27 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) { /* go through and mark all edges and all verts of all faces for delete */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, oflag)) { + if (BMO_face_flag_test(bm, f, oflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_enable(bm, l_iter->v, oflag); - BMO_elem_flag_enable(bm, l_iter->e, oflag); + BMO_vert_flag_enable(bm, l_iter->v, oflag); + BMO_edge_flag_enable(bm, l_iter->e, oflag); } while ((l_iter = l_iter->next) != l_first); } } /* now go through and mark all remaining faces all edges for keeping */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) { + if (!BMO_face_flag_test(bm, f, oflag)) { BMLoop *l_first = BM_FACE_FIRST_LOOP(f); BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_disable(bm, l_iter->v, oflag); - BMO_elem_flag_disable(bm, l_iter->e, oflag); + BMO_vert_flag_disable(bm, l_iter->v, oflag); + BMO_edge_flag_disable(bm, l_iter->e, oflag); } while ((l_iter = l_iter->next) != l_first); } } @@ -195,13 +195,13 @@ void BMO_mesh_delete_oflag_context(BMesh *bm, const short oflag, const int type) /* Only exception to normal 'DEL_FACES' logic. */ if (type == DEL_FACES_KEEP_BOUNDARY) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_disable(bm, e, oflag); + BMO_edge_flag_disable(bm, e, oflag); } } - if (!BMO_elem_flag_test(bm, e, oflag)) { - BMO_elem_flag_disable(bm, e->v1, oflag); - BMO_elem_flag_disable(bm, e->v2, oflag); + if (!BMO_edge_flag_test(bm, e, oflag)) { + BMO_vert_flag_disable(bm, e->v1, oflag); + BMO_vert_flag_disable(bm, e->v2, oflag); } } diff --git a/source/blender/bmesh/intern/bmesh_iterators.c b/source/blender/bmesh/intern/bmesh_iterators.c index cc79e28a361..961b10d848a 100644 --- a/source/blender/bmesh/intern/bmesh_iterators.c +++ b/source/blender/bmesh/intern/bmesh_iterators.c @@ -339,16 +339,43 @@ int BMO_iter_elem_count_flag( const short oflag, const bool value) { BMIter iter; - BMElemF *ele; int count = 0; /* loops have no header flags */ BLI_assert(bm_iter_itype_htype_map[itype] != BM_LOOP); - BM_ITER_ELEM (ele, &iter, data, itype) { - if (BMO_elem_flag_test_bool(bm, ele, oflag) == value) { - count++; + switch (bm_iter_itype_htype_map[itype]) { + case BM_VERT: + { + BMVert *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_vert_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; } + case BM_EDGE: + { + BMEdge *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_edge_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; + } + case BM_FACE: + { + BMFace *ele; + BM_ITER_ELEM (ele, &iter, data, itype) { + if (BMO_face_flag_test_bool(bm, ele, oflag) == value) { + count++; + } + } + break; + } + } return count; } diff --git a/source/blender/bmesh/intern/bmesh_marking.c b/source/blender/bmesh/intern/bmesh_marking.c index d6ca7239e39..7178a8132d2 100644 --- a/source/blender/bmesh/intern/bmesh_marking.c +++ b/source/blender/bmesh/intern/bmesh_marking.c @@ -842,7 +842,7 @@ void BM_editselection_normal(BMEditSelection *ese, float r_normal[3]) /* the 2 vertex normals will be close but not at rightangles to the edge * for rotate about edge we want them to be at right angles, so we need to - * do some extra colculation to correct the vert normals, + * do some extra calculation to correct the vert normals, * we need the plane for this */ cross_v3_v3v3(vec, r_normal, plane); cross_v3_v3v3(r_normal, plane, vec); diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c index ed1bd16b2e4..57a6d8d2e1a 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.c +++ b/source/blender/bmesh/intern/bmesh_mesh.c @@ -48,16 +48,52 @@ const BMAllocTemplate bm_mesh_allocsize_default = {512, 1024, 2048, 512}; const BMAllocTemplate bm_mesh_chunksize_default = {512, 1024, 2048, 512}; -static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize) +static void bm_mempool_init_ex( + const BMAllocTemplate *allocsize, const bool use_toolflags, + BLI_mempool **r_vpool, BLI_mempool **r_epool, BLI_mempool **r_lpool, BLI_mempool **r_fpool) { - bm->vpool = BLI_mempool_create(sizeof(BMVert), allocsize->totvert, - bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER); - bm->epool = BLI_mempool_create(sizeof(BMEdge), allocsize->totedge, - bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER); - bm->lpool = BLI_mempool_create(sizeof(BMLoop), allocsize->totloop, - bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP); - bm->fpool = BLI_mempool_create(sizeof(BMFace), allocsize->totface, - bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER); + size_t vert_size, edge_size, loop_size, face_size; + + if (use_toolflags == true) { + vert_size = sizeof(BMVert_OFlag); + edge_size = sizeof(BMEdge_OFlag); + loop_size = sizeof(BMLoop); + face_size = sizeof(BMFace_OFlag); + } + else { + vert_size = sizeof(BMVert); + edge_size = sizeof(BMEdge); + loop_size = sizeof(BMLoop); + face_size = sizeof(BMFace); + } + + if (r_vpool) { + *r_vpool = BLI_mempool_create( + vert_size, allocsize->totvert, + bm_mesh_chunksize_default.totvert, BLI_MEMPOOL_ALLOW_ITER); + } + if (r_epool) { + *r_epool = BLI_mempool_create( + edge_size, allocsize->totedge, + bm_mesh_chunksize_default.totedge, BLI_MEMPOOL_ALLOW_ITER); + } + if (r_lpool) { + *r_lpool = BLI_mempool_create( + loop_size, allocsize->totloop, + bm_mesh_chunksize_default.totloop, BLI_MEMPOOL_NOP); + } + if (r_fpool) { + *r_fpool = BLI_mempool_create( + face_size, allocsize->totface, + bm_mesh_chunksize_default.totface, BLI_MEMPOOL_ALLOW_ITER); + } +} + +static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize, const bool use_toolflags) +{ + bm_mempool_init_ex( + allocsize, use_toolflags, + &bm->vpool, &bm->epool, &bm->lpool, &bm->fpool); #ifdef USE_BMESH_HOLES bm->looplistpool = BLI_mempool_create(sizeof(BMLoopList), 512, 512, BLI_MEMPOOL_NOP); @@ -66,6 +102,8 @@ static void bm_mempool_init(BMesh *bm, const BMAllocTemplate *allocsize) void BM_mesh_elem_toolflags_ensure(BMesh *bm) { + BLI_assert(bm->use_toolflags); + if (bm->vtoolflagpool && bm->etoolflagpool && bm->ftoolflagpool) { return; } @@ -80,7 +118,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->vtoolflagpool; BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -89,7 +127,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->etoolflagpool; BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -98,7 +136,7 @@ void BM_mesh_elem_toolflags_ensure(BMesh *bm) { BLI_mempool *toolflagpool = bm->ftoolflagpool; BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { ele->oflags = BLI_mempool_calloc(toolflagpool); } @@ -134,15 +172,18 @@ void BM_mesh_elem_toolflags_clear(BMesh *bm) * * \note ob is needed by multires */ -BMesh *BM_mesh_create(const BMAllocTemplate *allocsize) +BMesh *BM_mesh_create( + const BMAllocTemplate *allocsize, + const struct BMeshCreateParams *params) { /* allocate the structure */ BMesh *bm = MEM_callocN(sizeof(BMesh), __func__); /* allocate the memory pools for the mesh elements */ - bm_mempool_init(bm, allocsize); + bm_mempool_init(bm, allocsize, params->use_toolflags); /* allocate one flag pool that we don't get rid of. */ + bm->use_toolflags = params->use_toolflags; bm->toolflag_index = 0; bm->totflags = 0; @@ -239,13 +280,16 @@ void BM_mesh_data_free(BMesh *bm) */ void BM_mesh_clear(BMesh *bm) { + const bool use_toolflags = bm->use_toolflags; + /* free old mesh */ BM_mesh_data_free(bm); memset(bm, 0, sizeof(BMesh)); /* allocate the memory pools for the mesh elements */ - bm_mempool_init(bm, &bm_mesh_allocsize_default); + bm_mempool_init(bm, &bm_mesh_allocsize_default, use_toolflags); + bm->use_toolflags = use_toolflags; bm->toolflag_index = 0; bm->totflags = 0; @@ -1706,3 +1750,262 @@ void BM_mesh_remap( if (fptr_map) BLI_ghash_free(fptr_map, NULL, NULL); } + +/** + * Use new memory pools for this mesh. + * + * \note needed for re-sizing elements (adding/removing tool flags) + * but could also be used for packing fragmented bmeshes. + */ +void BM_mesh_rebuild( + BMesh *bm, const struct BMeshCreateParams *params, + BLI_mempool *vpool_dst, BLI_mempool *epool_dst, BLI_mempool *lpool_dst, BLI_mempool *fpool_dst) +{ + const char remap = + (vpool_dst ? BM_VERT : 0) | + (epool_dst ? BM_EDGE : 0) | + (lpool_dst ? BM_LOOP : 0) | + (fpool_dst ? BM_FACE : 0); + + BMVert **vtable_dst = (remap & BM_VERT) ? MEM_mallocN(bm->totvert * sizeof(BMVert *), __func__) : NULL; + BMEdge **etable_dst = (remap & BM_EDGE) ? MEM_mallocN(bm->totedge * sizeof(BMEdge *), __func__) : NULL; + BMLoop **ltable_dst = (remap & BM_LOOP) ? MEM_mallocN(bm->totloop * sizeof(BMLoop *), __func__) : NULL; + BMFace **ftable_dst = (remap & BM_FACE) ? MEM_mallocN(bm->totface * sizeof(BMFace *), __func__) : NULL; + + const bool use_toolflags = params->use_toolflags; + + if (remap & BM_VERT) { + BMIter iter; + int index; + BMVert *v_src; + BM_ITER_MESH_INDEX (v_src, &iter, bm, BM_VERTS_OF_MESH, index) { + BMVert *v_dst = BLI_mempool_alloc(vpool_dst); + memcpy(v_dst, v_src, sizeof(BMVert)); + if (use_toolflags) { + ((BMVert_OFlag *)v_dst)->oflags = bm->vtoolflagpool ? BLI_mempool_calloc(bm->vtoolflagpool) : NULL; + } + + vtable_dst[index] = v_dst; + BM_elem_index_set(v_src, index); /* set_ok */ + } + } + + if (remap & BM_EDGE) { + BMIter iter; + int index; + BMEdge *e_src; + BM_ITER_MESH_INDEX (e_src, &iter, bm, BM_EDGES_OF_MESH, index) { + BMEdge *e_dst = BLI_mempool_alloc(epool_dst); + memcpy(e_dst, e_src, sizeof(BMEdge)); + if (use_toolflags) { + ((BMEdge_OFlag *)e_dst)->oflags = bm->etoolflagpool ? BLI_mempool_calloc(bm->etoolflagpool) : NULL; + } + + etable_dst[index] = e_dst; + BM_elem_index_set(e_src, index); /* set_ok */ + } + } + + if (remap & (BM_LOOP | BM_FACE)) { + BMIter iter; + int index, index_loop = 0; + BMFace *f_src; + BM_ITER_MESH_INDEX (f_src, &iter, bm, BM_FACES_OF_MESH, index) { + + if (remap & BM_FACE) { + BMFace *f_dst = BLI_mempool_alloc(fpool_dst); + memcpy(f_dst, f_src, sizeof(BMFace)); + if (use_toolflags) { + ((BMFace_OFlag *)f_dst)->oflags = bm->ftoolflagpool ? BLI_mempool_calloc(bm->ftoolflagpool) : NULL; + } + + ftable_dst[index] = f_dst; + BM_elem_index_set(f_src, index); /* set_ok */ + } + + /* handle loops */ + if (remap & BM_LOOP) { + BMLoop *l_iter_src, *l_first_src; + l_iter_src = l_first_src = BM_FACE_FIRST_LOOP((BMFace *)f_src); + do { + BMLoop *l_dst = BLI_mempool_alloc(lpool_dst); + memcpy(l_dst, l_iter_src, sizeof(BMLoop)); + ltable_dst[index_loop] = l_dst; + BM_elem_index_set(l_iter_src, index_loop++); /* set_ok */ + } while ((l_iter_src = l_iter_src->next) != l_first_src); + } + } + } + +#define MAP_VERT(ele) vtable_dst[BM_elem_index_get(ele)] +#define MAP_EDGE(ele) etable_dst[BM_elem_index_get(ele)] +#define MAP_LOOP(ele) ltable_dst[BM_elem_index_get(ele)] +#define MAP_FACE(ele) ftable_dst[BM_elem_index_get(ele)] + +#define REMAP_VERT(ele) { if (remap & BM_VERT) { ele = MAP_VERT(ele); }} ((void)0) +#define REMAP_EDGE(ele) { if (remap & BM_EDGE) { ele = MAP_EDGE(ele); }} ((void)0) +#define REMAP_LOOP(ele) { if (remap & BM_LOOP) { ele = MAP_LOOP(ele); }} ((void)0) +#define REMAP_FACE(ele) { if (remap & BM_FACE) { ele = MAP_FACE(ele); }} ((void)0) + + /* verts */ + { + for (int i = 0; i < bm->totvert; i++) { + BMVert *v = vtable_dst[i]; + if (v->e) { + REMAP_EDGE(v->e); + } + } + } + + /* edges */ + { + for (int i = 0; i < bm->totedge; i++) { + BMEdge *e = etable_dst[i]; + REMAP_VERT(e->v1); + REMAP_VERT(e->v2); + REMAP_EDGE(e->v1_disk_link.next); + REMAP_EDGE(e->v1_disk_link.prev); + REMAP_EDGE(e->v2_disk_link.next); + REMAP_EDGE(e->v2_disk_link.prev); + if (e->l) { + REMAP_LOOP(e->l); + } + } + } + + /* faces */ + { + for (int i = 0; i < bm->totface; i++) { + BMFace *f = ftable_dst[i]; + REMAP_LOOP(f->l_first); + + { + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP((BMFace *)f); + do { + REMAP_VERT(l_iter->v); + REMAP_EDGE(l_iter->e); + REMAP_FACE(l_iter->f); + + REMAP_LOOP(l_iter->radial_next); + REMAP_LOOP(l_iter->radial_prev); + REMAP_LOOP(l_iter->next); + REMAP_LOOP(l_iter->prev); + } while ((l_iter = l_iter->next) != l_first); + } + } + } + + for (BMEditSelection *ese = bm->selected.first; ese; ese = ese->next) { + switch (ese->htype) { + case BM_VERT: + if (remap & BM_VERT) { + ese->ele = (BMElem *)MAP_VERT(ese->ele); + } + break; + case BM_EDGE: + if (remap & BM_EDGE) { + ese->ele = (BMElem *)MAP_EDGE(ese->ele); + } + break; + case BM_FACE: + if (remap & BM_FACE) { + ese->ele = (BMElem *)MAP_FACE(ese->ele); + } + break; + } + } + + if (bm->act_face) { + REMAP_FACE(bm->act_face); + } + +#undef MAP_VERT +#undef MAP_EDGE +#undef MAP_LOOP +#undef MAP_EDGE + +#undef REMAP_VERT +#undef REMAP_EDGE +#undef REMAP_LOOP +#undef REMAP_EDGE + + /* Cleanup, re-use local tables if the current mesh had tables allocated. + * could use irrespective but it may use more memory then the caller wants (and not be needed). */ + if (remap & BM_VERT) { + if (bm->vtable) { + SWAP(BMVert **, vtable_dst, bm->vtable); + bm->vtable_tot = bm->totvert; + bm->elem_table_dirty &= ~BM_VERT; + } + MEM_freeN(vtable_dst); + BLI_mempool_destroy(bm->vpool); + bm->vpool = vpool_dst; + } + + if (remap & BM_EDGE) { + if (bm->etable) { + SWAP(BMEdge **, etable_dst, bm->etable); + bm->etable_tot = bm->totedge; + bm->elem_table_dirty &= ~BM_EDGE; + } + MEM_freeN(etable_dst); + BLI_mempool_destroy(bm->epool); + bm->epool = epool_dst; + } + + if (remap & BM_LOOP) { + /* no loop table */ + MEM_freeN(ltable_dst); + BLI_mempool_destroy(bm->lpool); + bm->lpool = lpool_dst; + } + + if (remap & BM_FACE) { + if (bm->ftable) { + SWAP(BMFace **, ftable_dst, bm->ftable); + bm->ftable_tot = bm->totface; + bm->elem_table_dirty &= ~BM_FACE; + } + MEM_freeN(ftable_dst); + BLI_mempool_destroy(bm->fpool); + bm->fpool = fpool_dst; + } +} + +/** + * Re-allocates mesh data with/without toolflags. + */ +void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags) +{ + if (bm->use_toolflags == use_toolflags) { + return; + } + + const BMAllocTemplate allocsize = BMALLOC_TEMPLATE_FROM_BM(bm); + + BLI_mempool *vpool_dst = NULL; + BLI_mempool *epool_dst = NULL; + BLI_mempool *fpool_dst = NULL; + + bm_mempool_init_ex( + &allocsize, use_toolflags, + &vpool_dst, &epool_dst, NULL, &fpool_dst); + + if (use_toolflags == false) { + BLI_mempool_destroy(bm->vtoolflagpool); + BLI_mempool_destroy(bm->etoolflagpool); + BLI_mempool_destroy(bm->ftoolflagpool); + + bm->vtoolflagpool = NULL; + bm->etoolflagpool = NULL; + bm->ftoolflagpool = NULL; + } + + BM_mesh_rebuild( + bm, + &((struct BMeshCreateParams){.use_toolflags = use_toolflags,}), + vpool_dst, epool_dst, NULL, fpool_dst); + + bm->use_toolflags = use_toolflags; +}
\ No newline at end of file diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h index b9cdc4ccf66..6a9540c3b60 100644 --- a/source/blender/bmesh/intern/bmesh_mesh.h +++ b/source/blender/bmesh/intern/bmesh_mesh.h @@ -32,7 +32,14 @@ struct MLoopNorSpaceArray; void BM_mesh_elem_toolflags_ensure(BMesh *bm); void BM_mesh_elem_toolflags_clear(BMesh *bm); -BMesh *BM_mesh_create(const struct BMAllocTemplate *allocsize); + +struct BMeshCreateParams { + unsigned int use_toolflags : 1; +}; + +BMesh *BM_mesh_create( + const struct BMAllocTemplate *allocsize, + const struct BMeshCreateParams *params); void BM_mesh_free(BMesh *bm); void BM_mesh_data_free(BMesh *bm); @@ -53,6 +60,8 @@ void BM_mesh_elem_index_validate( BMesh *bm, const char *location, const char *func, const char *msg_a, const char *msg_b); +void BM_mesh_toolflags_set(BMesh *bm, bool use_toolflags); + #ifndef NDEBUG bool BM_mesh_elem_table_check(BMesh *bm); #endif @@ -83,6 +92,10 @@ void BM_mesh_remap( const unsigned int *edge_idx, const unsigned int *face_idx); +void BM_mesh_rebuild( + BMesh *bm, const struct BMeshCreateParams *params, + struct BLI_mempool *vpool, struct BLI_mempool *epool, struct BLI_mempool *lpool, struct BLI_mempool *fpool); + typedef struct BMAllocTemplate { int totvert, totedge, totloop, totface; } BMAllocTemplate; @@ -113,10 +126,4 @@ extern const BMAllocTemplate bm_mesh_chunksize_default; #define BMALLOC_TEMPLATE_FROM_DM(...) VA_NARGS_CALL_OVERLOAD(_VA_BMALLOC_TEMPLATE_FROM_DM_, __VA_ARGS__) - - -enum { - BM_MESH_CREATE_USE_TOOLFLAGS = (1 << 0) -}; - #endif /* __BMESH_MESH_H__ */ diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h index cf93fe0935e..30cd1df9c4e 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api.h +++ b/source/blender/bmesh/intern/bmesh_operator_api.h @@ -75,15 +75,74 @@ extern "C" { struct GHashIterator; -#define BMO_elem_flag_test( bm, ele, oflag) _bmo_elem_flag_test (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_test_bool(bm, ele, oflag) _bmo_elem_flag_test_bool(bm, (ele)->oflags, oflag) -#define BMO_elem_flag_enable( bm, ele, oflag) _bmo_elem_flag_enable (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_disable( bm, ele, oflag) _bmo_elem_flag_disable (bm, (ele)->oflags, oflag) -#define BMO_elem_flag_set( bm, ele, oflag, val) _bmo_elem_flag_set (bm, (ele)->oflags, oflag, val) -#define BMO_elem_flag_toggle( bm, ele, oflag) _bmo_elem_flag_toggle (bm, (ele)->oflags, oflag) - -BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, BMFlagLayer *oflags, const short oflag); -BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag); +BLI_INLINE BMFlagLayer *BMO_elem_flag_from_header(BMHeader *ele_head) +{ + switch (ele_head->htype) { + case BM_VERT: return ((BMVert_OFlag *)ele_head)->oflags; + case BM_EDGE: return ((BMEdge_OFlag *)ele_head)->oflags; + default: return ((BMFace_OFlag *)ele_head)->oflags; + } +} + +#define BMO_elem_flag_test(bm, ele, oflag) \ + _bmo_elem_flag_test(bm, BMO_elem_flag_from_header(&(ele)->head), oflag) +#define BMO_elem_flag_test_bool(bm, ele, oflag) \ + _bmo_elem_flag_test_bool(bm, BMO_elem_flag_from_header(&(ele)->head), oflag) +#define BMO_elem_flag_enable(bm, ele, oflag) \ + _bmo_elem_flag_enable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) +#define BMO_elem_flag_disable(bm, ele, oflag) \ + _bmo_elem_flag_disable(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) +#define BMO_elem_flag_set(bm, ele, oflag, val) \ + _bmo_elem_flag_set(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag, val) +#define BMO_elem_flag_toggle(bm, ele, oflag) \ + _bmo_elem_flag_toggle(bm, (BM_CHECK_TYPE_ELEM_NONCONST(ele), BMO_elem_flag_from_header(&(ele)->head)), oflag) + +/* take care not to instansiate args multiple times */ +#ifdef __GNUC___ +#define _BMO_CAST_V_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_VERT(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_VERT), (const BMVert_OFlag *)_e); }) +#define _BMO_CAST_E_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_EDGE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_EDGE), (const BMEdge_OFlag *)_e); }) +#define _BMO_CAST_F_CONST(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_FACE(_e), BLI_assert(((const BMHeader *)_e)->htype == BM_FACE), (const BMFace_OFlag *)_e); }) +#define _BMO_CAST_V(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_VERT_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_VERT), (BMVert_OFlag *)_e); }) +#define _BMO_CAST_E(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_EDGE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_EDGE), (BMEdge_OFlag *)_e); }) +#define _BMO_CAST_F(e) ({ typeof(e) _e = e; \ + (BM_CHECK_TYPE_FACE_NONCONST(_e), BLI_assert(((BMHeader *)_e)->htype == BM_FACE), (BMFace_OFlag *)_e); }) +#else +#define _BMO_CAST_V_CONST(e) (BM_CHECK_TYPE_VERT(e), (const BMVert_OFlag *)e) +#define _BMO_CAST_E_CONST(e) (BM_CHECK_TYPE_EDGE(e), (const BMEdge_OFlag *)e) +#define _BMO_CAST_F_CONST(e) (BM_CHECK_TYPE_FACE(e), (const BMFace_OFlag *)e) +#define _BMO_CAST_V(e) (BM_CHECK_TYPE_VERT_NONCONST(e), (BMVert_OFlag *)e) +#define _BMO_CAST_E(e) (BM_CHECK_TYPE_EDGE_NONCONST(e), (BMEdge_OFlag *)e) +#define _BMO_CAST_F(e) (BM_CHECK_TYPE_FACE_NONCONST(e), (BMFace_OFlag *)e) +#endif + +#define BMO_vert_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_V_CONST(e)->oflags, oflag) +#define BMO_vert_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_V_CONST(e)->oflags, oflag) +#define BMO_vert_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_V(e)->oflags, oflag) +#define BMO_vert_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_V(e)->oflags, oflag) +#define BMO_vert_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_V(e)->oflags, oflag, val) +#define BMO_vert_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_V(e)->oflags, oflag) + +#define BMO_edge_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_E_CONST(e)->oflags, oflag) +#define BMO_edge_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_E_CONST(e)->oflags, oflag) +#define BMO_edge_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_E(e)->oflags, oflag) +#define BMO_edge_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_E(e)->oflags, oflag) +#define BMO_edge_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_E(e)->oflags, oflag, val) +#define BMO_edge_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_E(e)->oflags, oflag) + +#define BMO_face_flag_test( bm, e, oflag) _bmo_elem_flag_test (bm, _BMO_CAST_F_CONST(e)->oflags, oflag) +#define BMO_face_flag_test_bool(bm, e, oflag) _bmo_elem_flag_test_bool(bm, _BMO_CAST_F_CONST(e)->oflags, oflag) +#define BMO_face_flag_enable( bm, e, oflag) _bmo_elem_flag_enable (bm, _BMO_CAST_F(e)->oflags, oflag) +#define BMO_face_flag_disable( bm, e, oflag) _bmo_elem_flag_disable (bm, _BMO_CAST_F(e)->oflags, oflag) +#define BMO_face_flag_set( bm, e, oflag, val) _bmo_elem_flag_set (bm, _BMO_CAST_F(e)->oflags, oflag, val) +#define BMO_face_flag_toggle( bm, e, oflag) _bmo_elem_flag_toggle (bm, _BMO_CAST_F(e)->oflags, oflag) + +BLI_INLINE short _bmo_elem_flag_test( BMesh *bm, const BMFlagLayer *oflags, const short oflag); +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_enable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_disable( BMesh *bm, BMFlagLayer *oflags, const short oflag); BLI_INLINE void _bmo_elem_flag_set( BMesh *bm, BMFlagLayer *oflags, const short oflag, int val); diff --git a/source/blender/bmesh/intern/bmesh_operator_api_inline.h b/source/blender/bmesh/intern/bmesh_operator_api_inline.h index 00fcd9e7a9b..eb1c161f19d 100644 --- a/source/blender/bmesh/intern/bmesh_operator_api_inline.h +++ b/source/blender/bmesh/intern/bmesh_operator_api_inline.h @@ -39,32 +39,37 @@ /* flags 15 and 16 (1 << 14 and 1 << 15) are reserved for bmesh api use */ ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2) -BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, BMFlagLayer *oflags, const short oflag) +BLI_INLINE short _bmo_elem_flag_test(BMesh *bm, const BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); return oflags[bm->toolflag_index].f & oflag; } ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2) -BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, BMFlagLayer *oflags, const short oflag) +BLI_INLINE bool _bmo_elem_flag_test_bool(BMesh *bm, const BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); return (oflags[bm->toolflag_index].f & oflag) != 0; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_enable(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f |= oflag; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_disable(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f &= (short)~oflag; } ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short oflag, int val) { + BLI_assert(bm->use_toolflags); if (val) oflags[bm->toolflag_index].f |= oflag; else oflags[bm->toolflag_index].f &= (short)~oflag; } @@ -72,6 +77,7 @@ BLI_INLINE void _bmo_elem_flag_set(BMesh *bm, BMFlagLayer *oflags, const short o ATTR_NONNULL(1, 2) BLI_INLINE void _bmo_elem_flag_toggle(BMesh *bm, BMFlagLayer *oflags, const short oflag) { + BLI_assert(bm->use_toolflags); oflags[bm->toolflag_index].f ^= oflag; } diff --git a/source/blender/bmesh/intern/bmesh_operators.c b/source/blender/bmesh/intern/bmesh_operators.c index 960ff568e93..706a7f74ed2 100644 --- a/source/blender/bmesh/intern/bmesh_operators.c +++ b/source/blender/bmesh/intern/bmesh_operators.c @@ -548,27 +548,44 @@ static int bmo_mesh_flag_count( BMesh *bm, const char htype, const short oflag, const bool test_for_enabled) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; + int count_vert = 0, count_edge = 0, count_face = 0; - const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE}; - - BMIter iter; - int count = 0; - BMElemF *ele_f; - int i; - - for (i = 0; i < 3; i++) { - if (htype & flag_types[i]) { - BM_ITER_MESH (ele_f, &iter, bm, iter_types[i]) { - if (BMO_elem_flag_test_bool(bm, ele_f, oflag) == test_for_enabled) - count++; +#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \ + (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0)) + { +#pragma omp section + if (htype & BM_VERT) { + BMIter iter; + BMVert *ele; + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + if (BMO_vert_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_vert++; + } + } + } +#pragma omp section + if (htype & BM_EDGE) { + BMIter iter; + BMEdge *ele; + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_edge++; + } + } + } +#pragma omp section + if (htype & BM_FACE) { + BMIter iter; + BMFace *ele; + BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { + if (BMO_face_flag_test_bool(bm, ele, oflag) == test_for_enabled) { + count_face++; + } } } } - return count; + return (count_vert + count_edge + count_face); } @@ -584,21 +601,32 @@ int BMO_mesh_disabled_flag_count(BMesh *bm, const char htype, const short oflag) void BMO_mesh_flag_disable_all(BMesh *bm, BMOperator *UNUSED(op), const char htype, const short oflag) { - const char iter_types[3] = {BM_VERTS_OF_MESH, - BM_EDGES_OF_MESH, - BM_FACES_OF_MESH}; - - const char flag_types[3] = {BM_VERT, BM_EDGE, BM_FACE}; - BMElemF *ele; - int i; - -#pragma omp parallel for schedule(static) if (bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) - for (i = 0; i < 3; i++) { - if (htype & flag_types[i]) { +#pragma omp parallel sections if ((bm->totvert + bm->totedge + bm->totface >= BM_OMP_LIMIT) && \ + (ELEM(htype, BM_VERT, BM_EDGE, BM_FACE) == 0)) + { +#pragma omp section + if (htype & BM_VERT) { BMIter iter; - BM_ITER_MESH (ele, &iter, bm, iter_types[i]) { - BMO_elem_flag_disable(bm, ele, oflag); + BMVert *ele; + BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { + BMO_vert_flag_disable(bm, ele, oflag); + } + } +#pragma omp section + if (htype & BM_EDGE) { + BMIter iter; + BMEdge *ele; + BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { + BMO_edge_flag_disable(bm, ele, oflag); + } + } +#pragma omp section + if (htype & BM_FACE) { + BMIter iter; + BMFace *ele; + BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { + BMO_face_flag_disable(bm, ele, oflag); } } } @@ -1007,7 +1035,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_VERT) { BM_ITER_MESH (ele, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_vert_flag_test_bool(bm, (BMVert *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1016,7 +1044,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_EDGE) { BM_ITER_MESH (ele, &iter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_edge_flag_test_bool(bm, (BMEdge *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1025,7 +1053,7 @@ static void bmo_slot_buffer_from_flag( if (htype & BM_FACE) { BM_ITER_MESH (ele, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test_bool(bm, (BMElemF *)ele, oflag) == test_for_enabled) { + if (BMO_face_flag_test_bool(bm, (BMFace *)ele, oflag) == test_for_enabled) { ele_array[i] = ele; i++; } @@ -1213,7 +1241,7 @@ static void bmo_flag_layer_alloc(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BLI_mempool *newpool = bm->vtoolflagpool; @@ -1223,14 +1251,14 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BLI_mempool *newpool = bm->etoolflagpool; @@ -1239,14 +1267,14 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BLI_mempool *newpool = bm->ftoolflagpool; @@ -1255,7 +1283,7 @@ static void bmo_flag_layer_alloc(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_calloc(newpool); memcpy(ele->oflags, oldflags, old_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } @@ -1292,7 +1320,7 @@ static void bmo_flag_layer_free(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BLI_mempool *newpool = bm->vtoolflagpool; @@ -1302,14 +1330,14 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BLI_mempool *newpool = bm->etoolflagpool; @@ -1318,14 +1346,14 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BLI_mempool *newpool = bm->ftoolflagpool; @@ -1334,7 +1362,7 @@ static void bmo_flag_layer_free(BMesh *bm) void *oldflags = ele->oflags; ele->oflags = BLI_mempool_alloc(newpool); memcpy(ele->oflags, oldflags, new_totflags_size); - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ BM_ELEM_API_FLAG_CLEAR((BMElemF *)ele); } } @@ -1361,31 +1389,31 @@ static void bmo_flag_layer_clear(BMesh *bm) #pragma omp section { BMIter iter; - BMElemF *ele; + BMVert_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_VERTS_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMEdge_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_EDGES_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } #pragma omp section { BMIter iter; - BMElemF *ele; + BMFace_OFlag *ele; int i; BM_ITER_MESH_INDEX (ele, &iter, bm, BM_FACES_OF_MESH, i) { ele->oflags[totflags_offset] = zero_flag; - BM_elem_index_set(ele, i); /* set_inline */ + BM_elem_index_set(&ele->base, i); /* set_inline */ } } } diff --git a/source/blender/bmesh/intern/bmesh_polygon.c b/source/blender/bmesh/intern/bmesh_polygon.c index 79051a2490f..08e97046f68 100644 --- a/source/blender/bmesh/intern/bmesh_polygon.c +++ b/source/blender/bmesh/intern/bmesh_polygon.c @@ -57,10 +57,9 @@ static bool testedgesidef(const float v1[2], const float v2[2], const float v3[2]) { /* is v3 to the right of v1 - v2 ? With exception: v3 == v1 || v3 == v2 */ - double inp; - - //inp = (v2[cox] - v1[cox]) * (v1[coy] - v3[coy]) + (v1[coy] - v2[coy]) * (v1[cox] - v3[cox]); - inp = (v2[0] - v1[0]) * (v1[1] - v3[1]) + (v1[1] - v2[1]) * (v1[0] - v3[0]); + const float inp = + ((v2[0] - v1[0]) * (v1[1] - v3[1])) + + ((v1[1] - v2[1]) * (v1[0] - v3[0])); if (inp < 0.0) { return false; @@ -371,7 +370,7 @@ void BM_vert_tri_calc_tangent_edge_pair(BMVert *verts[3], float r_tangent[3]) } /** - * Compute the tanget of the face, using the longest edge. + * Compute the tangent of the face, using the longest edge. */ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) { @@ -384,7 +383,7 @@ void BM_face_calc_tangent_edge(const BMFace *f, float r_tangent[3]) } /** - * Compute the tanget of the face, using the two longest disconected edges. + * Compute the tangent of the face, using the two longest disconnected edges. * * \param r_tangent: Calculated unit length tangent (return value). */ @@ -449,7 +448,7 @@ void BM_face_calc_tangent_edge_pair(const BMFace *f, float r_tangent[3]) } /** - * Compute the tanget of the face, using the edge farthest away from any vertex in the face. + * Compute the tangent of the face, using the edge farthest away from any vertex in the face. * * \param r_tangent: Calculated unit length tangent (return value). */ @@ -485,7 +484,7 @@ void BM_face_calc_tangent_edge_diagonal(const BMFace *f, float r_tangent[3]) } /** - * Compute the tanget of the face, using longest distance between vertices on the face. + * Compute the tangent of the face, using longest distance between vertices on the face. * * \note The logic is almost identical to #BM_face_calc_tangent_edge_diagonal */ @@ -1036,6 +1035,7 @@ void BM_face_triangulate( const int quad_method, const int ngon_method, const bool use_tag, + /* use for ngons only! */ MemArena *pf_arena, /* use for MOD_TRIANGULATE_NGON_BEAUTY only! */ diff --git a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c index c224a1ad587..5ee0e904a33 100644 --- a/source/blender/bmesh/intern/bmesh_polygon_edgenet.c +++ b/source/blender/bmesh/intern/bmesh_polygon_edgenet.c @@ -97,15 +97,27 @@ static BMLoop *bm_edge_flagged_radial_first(BMEdge *e) return NULL; } +static void normalize_v2_m3_v3v3(float out[2], float axis_mat[3][3], const float v1[3], const float v2[3]) +{ + float dir[3]; + sub_v3_v3v3(dir, v1, v2); + mul_v2_m3v3(out, axis_mat, dir); + normalize_v2(out); +} + + +/** + * \note Be sure to update #bm_face_split_edgenet_find_loop_pair_exists + * when making changed to edge picking logic. + */ static bool bm_face_split_edgenet_find_loop_pair( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, + const float face_normal[3], float face_normal_matrix[3][3], BMEdge *e_pair[2]) { /* Always find one boundary edge (to determine winding) * and one wire (if available), otherwise another boundary. */ - BMIter iter; - BMEdge *e; /* detect winding */ BMLoop *l_walk; @@ -116,18 +128,22 @@ static bool bm_face_split_edgenet_find_loop_pair( int edges_boundary_len = 0; int edges_wire_len = 0; - BM_ITER_ELEM (e, &iter, v_init, BM_EDGES_OF_VERT) { - if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { - const unsigned int count = bm_edge_flagged_radial_count(e); - if (count == 1) { - BLI_SMALLSTACK_PUSH(edges_boundary, e); - edges_boundary_len++; - } - else if (count == 0) { - BLI_SMALLSTACK_PUSH(edges_wire, e); - edges_wire_len++; + { + BMEdge *e, *e_first; + e = e_first = v_init->e; + do { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + BLI_SMALLSTACK_PUSH(edges_boundary, e); + edges_boundary_len++; + } + else if (count == 0) { + BLI_SMALLSTACK_PUSH(edges_wire, e); + edges_wire_len++; + } } - } + } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first); } /* first edge should always be boundary */ @@ -136,10 +152,17 @@ static bool bm_face_split_edgenet_find_loop_pair( } e_pair[0] = BLI_SMALLSTACK_POP(edges_boundary); + /* use to hold boundary OR wire edges */ + BLI_SMALLSTACK_DECLARE(edges_search, BMEdge *); + /* attempt one boundary and one wire, or 2 boundary */ if (edges_wire_len == 0) { - if (edges_boundary_len >= 2) { + if (edges_boundary_len > 1) { e_pair[1] = BLI_SMALLSTACK_POP(edges_boundary); + + if (edges_boundary_len > 2) { + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); + } } else { /* one boundary and no wire */ @@ -148,27 +171,37 @@ static bool bm_face_split_edgenet_find_loop_pair( } else { e_pair[1] = BLI_SMALLSTACK_POP(edges_wire); - if (edges_wire_len > 1) { - BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); - BMVert *v_next; - float angle_best; - - v_next = BM_edge_other_vert(e_pair[1], v_init); - angle_best = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - - while ((e = BLI_SMALLSTACK_POP(edges_wire))) { - float angle_test; - v_next = BM_edge_other_vert(e, v_init); - angle_test = angle_on_axis_v3v3v3_v3(v_prev->co, v_init->co, v_next->co, face_normal); - if (angle_test < angle_best) { - angle_best = angle_test; - e_pair[1] = e; - } - } + BLI_SMALLSTACK_SWAP(edges_search, edges_wire); } } + /* if we swapped above, search this list for the best edge */ + if (!BLI_SMALLSTACK_IS_EMPTY(edges_search)) { + /* find the best edge in 'edge_list' to use for 'e_pair[1]' */ + const BMVert *v_prev = BM_edge_other_vert(e_pair[0], v_init); + const BMVert *v_next = BM_edge_other_vert(e_pair[1], v_init); + + float dir_prev[2], dir_next[2]; + + normalize_v2_m3_v3v3(dir_prev, face_normal_matrix, v_prev->co, v_init->co); + normalize_v2_m3_v3v3(dir_next, face_normal_matrix, v_next->co, v_init->co); + float angle_best_cos = dot_v2v2(dir_next, dir_prev); + + BMEdge *e; + while ((e = BLI_SMALLSTACK_POP(edges_search))) { + v_next = BM_edge_other_vert(e, v_init); + float dir_test[2]; + + normalize_v2_m3_v3v3(dir_test, face_normal_matrix, v_next->co, v_init->co); + const float angle_test_cos = dot_v2v2(dir_prev, dir_test); + + if (angle_test_cos > angle_best_cos) { + angle_best_cos = angle_test_cos; + e_pair[1] = e; + } + } + } /* flip based on winding */ l_walk = bm_edge_flagged_radial_first(e_pair[0]); @@ -186,6 +219,58 @@ static bool bm_face_split_edgenet_find_loop_pair( return true; } +/** + * A reduced version of #bm_face_split_edgenet_find_loop_pair + * that only checks if it would return true. + * + * \note There is no use in caching resulting edges here, + * since between this check and running #bm_face_split_edgenet_find_loop, + * the selected edges may have had faces attached. + */ +static bool bm_face_split_edgenet_find_loop_pair_exists( + BMVert *v_init) +{ + int edges_boundary_len = 0; + int edges_wire_len = 0; + + { + BMEdge *e, *e_first; + e = e_first = v_init->e; + do { + if (BM_ELEM_API_FLAG_TEST(e, EDGE_NET)) { + const unsigned int count = bm_edge_flagged_radial_count(e); + if (count == 1) { + edges_boundary_len++; + } + else if (count == 0) { + edges_wire_len++; + } + } + } while ((e = BM_DISK_EDGE_NEXT(e, v_init)) != e_first); + } + + /* first edge should always be boundary */ + if (edges_boundary_len == 0) { + return false; + } + + /* attempt one boundary and one wire, or 2 boundary */ + if (edges_wire_len == 0) { + if (edges_boundary_len >= 2) { + /* pass */ + } + else { + /* one boundary and no wire */ + return false; + } + } + else { + /* pass */ + } + + return true; +} + static bool bm_face_split_edgenet_find_loop_walk( BMVert *v_init, const float face_normal[3], /* cache to avoid realloc every time */ @@ -232,9 +317,6 @@ static bool bm_face_split_edgenet_find_loop_walk( * alternatives are stored in the 'vert_stack'. */ while ((v = BLI_SMALLSTACK_POP_EX(vert_stack, vert_stack_next))) { - BMIter eiter; - BMEdge *e_next; - #ifdef USE_FASTPATH_NOFORK walk_nofork: #else @@ -250,35 +332,42 @@ walk_nofork: goto finally; } - BM_ITER_ELEM (e_next, &eiter, v, BM_EDGES_OF_VERT) { - if ((v->e != e_next) && - (BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && - (bm_edge_flagged_radial_count(e_next) < 2)) - { - BMVert *v_next; + BMEdge *e_next, *e_first; + e_first = v->e; + e_next = BM_DISK_EDGE_NEXT(e_first, v); /* always skip this verts edge */ + + /* in rare cases there may be edges with a single connecting vertex */ + if (e_next != e_first) { + do { + if ((BM_ELEM_API_FLAG_TEST(e_next, EDGE_NET)) && + (bm_edge_flagged_radial_count(e_next) < 2)) + { + BMVert *v_next; - v_next = BM_edge_other_vert(e_next, v); + v_next = BM_edge_other_vert(e_next, v); + BLI_assert(v->e != e_next); #ifdef DEBUG_PRINT - /* indent and print */ - { - BMVert *_v = v; - do { - printf(" "); - } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); - printf("vert %d -> %d (add=%d)\n", - BM_elem_index_get(v), BM_elem_index_get(v_next), - BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); - } + /* indent and print */ + { + BMVert *_v = v; + do { + printf(" "); + } while ((_v = BM_edge_other_vert(_v->e, _v)) != v_init); + printf("vert %d -> %d (add=%d)\n", + BM_elem_index_get(v), BM_elem_index_get(v_next), + BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT) == 0); + } #endif - if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { - eo = STACK_PUSH_RET_PTR(edge_order); - eo->v = v_next; + if (!BM_ELEM_API_FLAG_TEST(v_next, VERT_VISIT)) { + eo = STACK_PUSH_RET_PTR(edge_order); + eo->v = v_next; - v_next->e = e_next; + v_next->e = e_next; + } } - } + } while ((e_next = BM_DISK_EDGE_NEXT(e_next, v)) != e_first); } #ifdef USE_FASTPATH_NOFORK @@ -329,7 +418,7 @@ finally: } static bool bm_face_split_edgenet_find_loop( - BMVert *v_init, const float face_normal[3], + BMVert *v_init, const float face_normal[3], float face_normal_matrix[3][3], /* cache to avoid realloc every time */ struct VertOrder *edge_order, const unsigned int edge_order_len, BMVert **r_face_verts, int *r_face_verts_len) @@ -337,7 +426,7 @@ static bool bm_face_split_edgenet_find_loop( BMEdge *e_pair[2]; BMVert *v; - if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, e_pair)) { + if (!bm_face_split_edgenet_find_loop_pair(v_init, face_normal, face_normal_matrix, e_pair)) { return false; } @@ -432,12 +521,18 @@ bool BM_face_split_edgenet( BM_ELEM_API_FLAG_ENABLE(l_iter->e, EDGE_NET); } while ((l_iter = l_iter->next) != l_first); + float face_normal_matrix[3][3]; + axis_dominant_v3_to_m3(face_normal_matrix, f->no); + /* any vert can be used to begin with */ STACK_PUSH(vert_queue, l_first->v); while ((v = STACK_POP(vert_queue))) { - if (bm_face_split_edgenet_find_loop(v, f->no, edge_order, edge_order_len, face_verts, &face_verts_len)) { + if (bm_face_split_edgenet_find_loop( + v, f->no, face_normal_matrix, + edge_order, edge_order_len, face_verts, &face_verts_len)) + { BMFace *f_new; f_new = BM_face_create_verts(bm, face_verts, face_verts_len, f, BM_CREATE_NOP, false); @@ -447,7 +542,6 @@ bool BM_face_split_edgenet( } if (f_new) { - bool l_prev_is_boundary; BLI_array_append(face_arr, f_new); copy_v3_v3(f_new->no, f->no); @@ -463,13 +557,10 @@ bool BM_face_split_edgenet( /* add new verts to keep finding loops for * (verts between boundary and manifold edges) */ l_iter = l_first = BM_FACE_FIRST_LOOP(f_new); - l_prev_is_boundary = (bm_edge_flagged_radial_count(l_iter->prev->e) == 1); do { - bool l_iter_is_boundary = (bm_edge_flagged_radial_count(l_iter->e) == 1); - if (l_prev_is_boundary != l_iter_is_boundary) { + if (bm_face_split_edgenet_find_loop_pair_exists(l_iter->v)) { STACK_PUSH(vert_queue, l_iter->v); } - l_prev_is_boundary = l_iter_is_boundary; } while ((l_iter = l_iter->next) != l_first); } } diff --git a/source/blender/bmesh/intern/bmesh_private.h b/source/blender/bmesh/intern/bmesh_private.h index 9b3a147301d..d8d297c9298 100644 --- a/source/blender/bmesh/intern/bmesh_private.h +++ b/source/blender/bmesh/intern/bmesh_private.h @@ -67,12 +67,13 @@ enum { _FLAG_MV = (1 << 1), /* make face, vertex */ _FLAG_OVERLAP = (1 << 2), /* general overlap flag */ _FLAG_WALK = (1 << 3), /* general walk flag (keep clean) */ + _FLAG_WALK_ALT = (1 << 4), /* same as _FLAG_WALK, for when a second tag is needed */ _FLAG_ELEM_CHECK = (1 << 7), /* reserved for bmesh_elem_check */ }; #define BM_ELEM_API_FLAG_ENABLE(element, f) { ((element)->head.api_flag |= (f)); } (void)0 -#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= ~(f)); } (void)0 +#define BM_ELEM_API_FLAG_DISABLE(element, f) { ((element)->head.api_flag &= (unsigned char)~(f)); } (void)0 #define BM_ELEM_API_FLAG_TEST(element, f) ((element)->head.api_flag & (f)) #define BM_ELEM_API_FLAG_CLEAR(element) { ((element)->head.api_flag = 0); } (void)0 diff --git a/source/blender/bmesh/intern/bmesh_walkers_impl.c b/source/blender/bmesh/intern/bmesh_walkers_impl.c index 018700c0efa..279440984bb 100644 --- a/source/blender/bmesh/intern/bmesh_walkers_impl.c +++ b/source/blender/bmesh/intern/bmesh_walkers_impl.c @@ -49,7 +49,7 @@ static bool bmw_mask_check_vert(BMWalker *walker, BMVert *v) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_vert && !BMO_elem_flag_test(walker->bm, v, walker->mask_vert)) { + else if (walker->mask_vert && !BMO_vert_flag_test(walker->bm, v, walker->mask_vert)) { return false; } else { @@ -62,7 +62,7 @@ static bool bmw_mask_check_edge(BMWalker *walker, BMEdge *e) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_edge && !BMO_elem_flag_test(walker->bm, e, walker->mask_edge)) { + else if (walker->mask_edge && !BMO_edge_flag_test(walker->bm, e, walker->mask_edge)) { return false; } else { @@ -75,7 +75,7 @@ static bool bmw_mask_check_face(BMWalker *walker, BMFace *f) if ((walker->flag & BMW_FLAG_TEST_HIDDEN) && BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { return false; } - else if (walker->mask_face && !BMO_elem_flag_test(walker->bm, f, walker->mask_face)) { + else if (walker->mask_face && !BMO_face_flag_test(walker->bm, f, walker->mask_face)) { return false; } else { @@ -223,7 +223,7 @@ static void *bmw_VertShellWalker_step(BMWalker *walker) do { if (!BLI_gset_haskey(walker->visit_set, curedge)) { if (!walker->restrictflag || - (walker->restrictflag && BMO_elem_flag_test(walker->bm, curedge, walker->restrictflag))) + (walker->restrictflag && BMO_edge_flag_test(walker->bm, curedge, walker->restrictflag))) { BMwShellWalker *newstate; @@ -748,7 +748,7 @@ static void *bmw_IslandboundWalker_step(BMWalker *walker) iwalk = BMW_state_add(walker); iwalk->base = owalk.base; - //if (!BMO_elem_flag_test(walker->bm, l->f, walker->restrictflag)) + //if (!BMO_face_flag_test(walker->bm, l->f, walker->restrictflag)) // iwalk->curloop = l->radial_next; iwalk->curloop = l; //else iwalk->curloop = l; iwalk->lastv = v; diff --git a/source/blender/bmesh/operators/bmo_beautify.c b/source/blender/bmesh/operators/bmo_beautify.c index 4a292c33472..c68d92ea5e0 100644 --- a/source/blender/bmesh/operators/bmo_beautify.c +++ b/source/blender/bmesh/operators/bmo_beautify.c @@ -52,7 +52,7 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) int edge_array_len = 0; BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -68,8 +68,8 @@ void bmo_beautify_fill_exec(BMesh *bm, BMOperator *op) /* edge is manifold and can be rotated */ if (BM_edge_rotate_check(e) && /* faces are tagged */ - BMO_elem_flag_test(bm, e->l->f, FACE_MARK) && - BMO_elem_flag_test(bm, e->l->radial_next->f, FACE_MARK)) + BMO_face_flag_test(bm, e->l->f, FACE_MARK) && + BMO_face_flag_test(bm, e->l->radial_next->f, FACE_MARK)) { edge_array[edge_array_len] = e; edge_array_len++; diff --git a/source/blender/bmesh/operators/bmo_bridge.c b/source/blender/bmesh/operators/bmo_bridge.c index a0149a41921..6ef0fd6b084 100644 --- a/source/blender/bmesh/operators/bmo_bridge.c +++ b/source/blender/bmesh/operators/bmo_bridge.c @@ -131,13 +131,13 @@ static void bm_face_edges_tag_out(BMesh *bm, BMFace *f) BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT); } while ((l_iter = l_iter->next) != l_first); } static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_elem_flag_test((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test((BMesh *)bm_v, e, EDGE_MARK); } static void bridge_loop_pair( @@ -425,7 +425,7 @@ static void bridge_loop_pair( if (f_example && (f_example != f)) { BM_elem_attrs_copy(bm, bm, f_example, f); } - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); BM_elem_flag_enable(f, BM_ELEM_TAG); /* tag all edges of the face, untag the loop edges after */ @@ -486,7 +486,7 @@ static void bridge_loop_pair( BMOIter siter; BMFace *f; BMO_ITER (f, &siter, op_sub.slots_in, "faces", BM_FACE) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); bm_face_edges_tag_out(bm, f); } } @@ -498,7 +498,7 @@ static void bridge_loop_pair( BMOIter siter; BMFace *f; BMO_ITER (f, &siter, op_sub.slots_out, "geom.out", BM_FACE) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); bm_face_edges_tag_out(bm, f); } } @@ -520,7 +520,7 @@ static void bridge_loop_pair( if (el_next) { if (el->data != el_next->data) { BMEdge *e = BM_edge_exists(el->data, el_next->data); - BMO_elem_flag_disable(bm, e, EDGE_OUT); + BMO_edge_flag_disable(bm, e, EDGE_OUT); } } } diff --git a/source/blender/bmesh/operators/bmo_connect.c b/source/blender/bmesh/operators/bmo_connect.c index 0213329118c..5c9cd8dc3fa 100644 --- a/source/blender/bmesh/operators/bmo_connect.c +++ b/source/blender/bmesh/operators/bmo_connect.c @@ -62,10 +62,10 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (BMO_elem_flag_test(bm, l_iter->v, VERT_INPUT) && + if (BMO_vert_flag_test(bm, l_iter->v, VERT_INPUT) && /* ensure this vertex isnt part of a contiguous group */ - ((BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || - (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) + ((BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT) == 0) || + (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT) == 0))) { if (!l_tag_prev) { l_tag_prev = l_tag_first = l_iter; @@ -75,7 +75,7 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera if (!BM_loop_is_adjacent(l_tag_prev, l_iter)) { BMEdge *e; e = BM_edge_exists(l_tag_prev->v, l_iter->v); - if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_OUT)) { + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_OUT)) { BMLoop **l_pair = STACK_PUSH_RET(loops_split); l_pair[0] = l_tag_prev; l_pair[1] = l_iter; @@ -138,8 +138,8 @@ static int bm_face_connect_verts(BMesh *bm, BMFace *f, const bool check_degenera if (!l_new || !f_new) { return -1; } - // BMO_elem_flag_enable(bm, f_new, FACE_NEW); - BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT); + // BMO_face_flag_enable(bm, f_new, FACE_NEW); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); } return 1; @@ -164,12 +164,12 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) BMIter iter; BMLoop *l_iter; - BMO_elem_flag_enable(bm, v, VERT_INPUT); + BMO_vert_flag_enable(bm, v, VERT_INPUT); BM_ITER_ELEM (l_iter, &iter, v, BM_LOOPS_OF_VERT) { f = l_iter->f; - if (!BMO_elem_flag_test(bm, f, FACE_EXCLUDE)) { - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { - BMO_elem_flag_enable(bm, f, FACE_TAG); + if (!BMO_face_flag_test(bm, f, FACE_EXCLUDE)) { + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { + BMO_face_flag_enable(bm, f, FACE_TAG); if (f->len > 3) { BLI_LINKSTACK_PUSH(faces, f); } @@ -179,11 +179,11 @@ void bmo_connect_verts_exec(BMesh *bm, BMOperator *op) /* flag edges even if these are not newly created * this way cut-pairs that include co-linear edges will get * predictable output. */ - if (BMO_elem_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { - BMO_elem_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); + if (BMO_vert_flag_test(bm, l_iter->prev->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->prev->e, EDGE_OUT_ADJ); } - if (BMO_elem_flag_test(bm, l_iter->next->v, VERT_INPUT)) { - BMO_elem_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); + if (BMO_vert_flag_test(bm, l_iter->next->v, VERT_INPUT)) { + BMO_edge_flag_enable(bm, l_iter->e, EDGE_OUT_ADJ); } } } diff --git a/source/blender/bmesh/operators/bmo_connect_concave.c b/source/blender/bmesh/operators/bmo_connect_concave.c index 8b9c60ada52..9bb67ed9341 100644 --- a/source/blender/bmesh/operators/bmo_connect_concave.c +++ b/source/blender/bmesh/operators/bmo_connect_concave.c @@ -107,10 +107,10 @@ static bool bm_face_split_by_concave( int i; for (i = 0; i < faces_array_tot; i++) { BMFace *f = faces_array[i]; - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); } } - BMO_elem_flag_enable(bm, f_base, FACE_OUT); + BMO_face_flag_enable(bm, f_base, FACE_OUT); if (edges_array_tot) { int i; @@ -120,7 +120,7 @@ static bool bm_face_split_by_concave( for (i = 0; i < edges_array_tot; i++) { BMLoop *l_pair[2]; BMEdge *e = edges_array[i]; - BMO_elem_flag_enable(bm, e, EDGE_OUT); + BMO_edge_flag_enable(bm, e, EDGE_OUT); if (BM_edge_is_contiguous(e) && BM_edge_loop_pair(e, &l_pair[0], &l_pair[1])) @@ -153,7 +153,7 @@ static bool bm_face_split_by_concave( BMFace *f_new, *f_pair[2] = {l_pair[0]->f, l_pair[1]->f}; f_new = BM_faces_join(bm, f_pair, 2, true); if (f_new) { - BMO_elem_flag_enable(bm, f_new, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); } } } diff --git a/source/blender/bmesh/operators/bmo_connect_nonplanar.c b/source/blender/bmesh/operators/bmo_connect_nonplanar.c index c80fb95c44a..9b3e1d38feb 100644 --- a/source/blender/bmesh/operators/bmo_connect_nonplanar.c +++ b/source/blender/bmesh/operators/bmo_connect_nonplanar.c @@ -136,9 +136,9 @@ static bool bm_face_split_by_angle(BMesh *bm, BMFace *f, BMFace *r_f_pair[2], co r_f_pair[0] = f; r_f_pair[1] = f_new; - BMO_elem_flag_enable(bm, f, FACE_OUT); - BMO_elem_flag_enable(bm, f_new, FACE_OUT); - BMO_elem_flag_enable(bm, l_new->e, EDGE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); + BMO_edge_flag_enable(bm, l_new->e, EDGE_OUT); return true; } } diff --git a/source/blender/bmesh/operators/bmo_connect_pair.c b/source/blender/bmesh/operators/bmo_connect_pair.c index 3b860778e1c..05322a570a7 100644 --- a/source/blender/bmesh/operators/bmo_connect_pair.c +++ b/source/blender/bmesh/operators/bmo_connect_pair.c @@ -67,18 +67,29 @@ #define ELE_TOUCHED 4 #define FACE_WALK_TEST(f) (CHECK_TYPE_INLINE(f, BMFace *), \ - BMO_elem_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) + BMO_face_flag_test(pc->bm_bmoflag, f, FACE_EXCLUDE) == 0) #define VERT_WALK_TEST(v) (CHECK_TYPE_INLINE(v, BMVert *), \ - BMO_elem_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) + BMO_vert_flag_test(pc->bm_bmoflag, v, VERT_EXCLUDE) == 0) +#if 0 #define ELE_TOUCH_TEST(e) \ (CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *), \ BMO_elem_flag_test(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED)) +#endif #define ELE_TOUCH_MARK(e) \ { CHECK_TYPE_ANY(e, BMVert *, BMEdge *, BMElem *, BMElemF *); \ BMO_elem_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED); } ((void)0) +#define ELE_TOUCH_TEST_VERT(v) BMO_vert_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_VERT(v) BMO_vert_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + +// #define ELE_TOUCH_TEST_EDGE(v) BMO_edge_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_EDGE(v) BMO_edge_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + +// #define ELE_TOUCH_TEST_FACE(v) BMO_face_flag_test(pc->bm_bmoflag, v, ELE_TOUCHED) +// #define ELE_TOUCH_MARK_FACE(v) BMO_face_flag_enable(pc->bm_bmoflag, (BMElemF *)e, ELE_TOUCHED) + // #define DEBUG_PRINT typedef struct PathContext { @@ -113,8 +124,8 @@ typedef struct PathLinkState { } PathLinkState; /** - \name Min Dist Dir Util - + * \name Min Dist Dir Util + * * Simply getting the closest intersecting vert/edge is _not_ good enough. see T43792 * we need to get the closest in both directions since the absolute closest may be a dead-end. * @@ -352,7 +363,7 @@ static PathLinkState *state_step__face_edges( BMElem *ele_next_from = (BMElem *)l_iter->f; if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST(ele_next) == false)) + (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) { min_dist_dir_update(mddir, dist_dir); mddir->dist_min[index] = dist_test; @@ -397,7 +408,7 @@ static PathLinkState *state_step__face_verts( BMElem *ele_next_from = (BMElem *)l_iter->f; if (FACE_WALK_TEST((BMFace *)ele_next_from) && - (ELE_TOUCH_TEST(ele_next) == false)) + (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false)) { min_dist_dir_update(mddir, dist_dir); mddir->dist_min[index] = dist_test; @@ -480,7 +491,7 @@ static bool state_step(PathContext *pc, PathLinkState *state) if (state_isect_co_exact(pc, v_other->co)) { BMElem *ele_next = (BMElem *)v_other; BMElem *ele_next_from = (BMElem *)e; - if (ELE_TOUCH_TEST(ele_next) == false) { + if (ELE_TOUCH_TEST_VERT((BMVert *)ele_next) == false) { state = state_link_add_test(pc, state, &state_orig, ele_next, ele_next_from); } } @@ -703,11 +714,11 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) BMVert *v_new; float e_fac = state_calc_co_pair_fac(&pc, e->v1->co, e->v2->co); v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); - BMO_elem_flag_enable(bm, v_new, VERT_OUT); + BMO_vert_flag_enable(bm, v_new, VERT_OUT); } else if (link->ele->head.htype == BM_VERT) { BMVert *v = (BMVert *)link->ele; - BMO_elem_flag_enable(bm, v, VERT_OUT); + BMO_vert_flag_enable(bm, v, VERT_OUT); } else { BLI_assert(0); @@ -715,8 +726,8 @@ void bmo_connect_vert_pair_exec(BMesh *bm, BMOperator *op) } while ((link = link->next)); } - BMO_elem_flag_enable(bm, pc.v_a, VERT_OUT); - BMO_elem_flag_enable(bm, pc.v_b, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_a, VERT_OUT); + BMO_vert_flag_enable(bm, pc.v_b, VERT_OUT); BLI_mempool_destroy(pc.link_pool); diff --git a/source/blender/bmesh/operators/bmo_create.c b/source/blender/bmesh/operators/bmo_create.c index a1e20dab63e..7b8cb36ab59 100644 --- a/source/blender/bmesh/operators/bmo_create.c +++ b/source/blender/bmesh/operators/bmo_create.c @@ -52,12 +52,19 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* count number of each element type we were passe */ BMO_ITER (h, &oiter, op->slots_in, "geom", BM_VERT | BM_EDGE | BM_FACE) { switch (h->htype) { - case BM_VERT: totv++; break; - case BM_EDGE: tote++; break; - case BM_FACE: totf++; break; + case BM_VERT: + BMO_vert_flag_enable(bm, (BMVert *)h, ELE_NEW); + totv++; + break; + case BM_EDGE: + BMO_edge_flag_enable(bm, (BMEdge *)h, ELE_NEW); + tote++; + break; + case BM_FACE: + BMO_face_flag_enable(bm, (BMFace *)h, ELE_NEW); + totf++; + break; } - - BMO_elem_flag_enable(bm, (BMElemF *)h, ELE_NEW); } /* --- Support Edge Creation --- @@ -71,7 +78,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) /* create edge */ e = BM_edge_create(bm, verts[0], verts[1], NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_OUT); + BMO_edge_flag_enable(bm, e, ELE_OUT); tote += 1; BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "edges.out", BM_EDGE, ELE_OUT); return; @@ -131,10 +138,10 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMEdge *e; e = BM_edge_create(bm, v_free, v_a, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); e = BM_edge_create(bm, v_free, v_b, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); tote += 2; } } @@ -236,7 +243,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) for (ese = bm->selected.first; ese; ese = ese->next) { if (ese->htype == BM_VERT) { - if (BMO_elem_flag_test(bm, (BMElemF *)ese->ele, ELE_NEW)) { + if (BMO_vert_flag_test(bm, (BMVert *)ese->ele, ELE_NEW)) { tot_ese_v++; } else { @@ -256,7 +263,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) BMVert *v = (BMVert *)ese->ele; if (v_prev) { BMEdge *e = BM_edge_create(bm, v, v_prev, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_OUT); + BMO_edge_flag_enable(bm, e, ELE_OUT); } v_prev = v; } @@ -286,7 +293,7 @@ void bmo_contextual_create_exec(BMesh *bm, BMOperator *op) f = BM_face_create_ngon_vcloud(bm, vert_arr, totv, NULL, BM_CREATE_NO_DOUBLE); if (f) { - BMO_elem_flag_enable(bm, f, ELE_OUT); + BMO_face_flag_enable(bm, f, ELE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); diff --git a/source/blender/bmesh/operators/bmo_dissolve.c b/source/blender/bmesh/operators/bmo_dissolve.c index 86062ff0b66..05efb14a699 100644 --- a/source/blender/bmesh/operators/bmo_dissolve.c +++ b/source/blender/bmesh/operators/bmo_dissolve.c @@ -74,10 +74,10 @@ static bool UNUSED_FUNCTION(check_hole_in_region) (BMesh *bm, BMFace *f) for (f2 = BMW_begin(®walker, f); f2; f2 = BMW_step(®walker)) { BM_ITER_ELEM (l2, &liter2, f2, BM_LOOPS_OF_FACE) { l3 = l2->radial_next; - if (BMO_elem_flag_test(bm, l3->f, FACE_MARK) != - BMO_elem_flag_test(bm, l2->f, FACE_MARK)) + if (BMO_face_flag_test(bm, l3->f, FACE_MARK) != + BMO_face_flag_test(bm, l2->f, FACE_MARK)) { - if (!BMO_elem_flag_test(bm, l2->e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, l2->e, EDGE_MARK)) { return false; } } @@ -99,14 +99,14 @@ static void bm_face_split(BMesh *bm, const short oflag, bool use_edge_delete) } BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, oflag)) { + if (BMO_vert_flag_test(bm, v, oflag)) { if (BM_vert_is_edge_pair(v) == false) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, v, BM_LOOPS_OF_VERT) { if (l->f->len > 3) { - if (BMO_elem_flag_test(bm, l->next->v, oflag) == 0 && - BMO_elem_flag_test(bm, l->prev->v, oflag) == 0) + if (BMO_vert_flag_test(bm, l->next->v, oflag) == 0 && + BMO_vert_flag_test(bm, l->prev->v, oflag) == 0) { BM_face_split(bm, l->f, l->next, l->prev, NULL, NULL, true); } @@ -153,7 +153,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) BMVert *v; BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); } } @@ -162,7 +162,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) /* collect region */ BMO_ITER (f, &oiter, op->slots_in, "faces", BM_FACE) { BMFace *f_iter; - if (!BMO_elem_flag_test(bm, f, FACE_TAG)) { + if (!BMO_face_flag_test(bm, f, FACE_TAG)) { continue; } @@ -181,8 +181,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) for (i = 0; i < BLI_array_count(faces); i++) { f_iter = faces[i]; - BMO_elem_flag_disable(bm, f_iter, FACE_TAG); - BMO_elem_flag_enable(bm, f_iter, FACE_ORIG); + BMO_face_flag_disable(bm, f_iter, FACE_TAG); + BMO_face_flag_enable(bm, f_iter, FACE_ORIG); } if (BMO_error_occurred(bm)) { @@ -229,8 +229,8 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) /* if making the new face failed (e.g. overlapping test) * unmark the original faces for deletion */ - BMO_elem_flag_disable(bm, f_new, FACE_ORIG); - BMO_elem_flag_enable(bm, f_new, FACE_NEW); + BMO_face_flag_disable(bm, f_new, FACE_ORIG); + BMO_face_flag_enable(bm, f_new, FACE_NEW); } /* Typically no faces need to be deleted */ @@ -243,7 +243,7 @@ void bmo_dissolve_faces_exec(BMesh *bm, BMOperator *op) BMVert *v, *v_next; BM_ITER_MESH_MUTABLE (v, v_next, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { if (BM_vert_is_edge_pair(v)) { BM_vert_collapse_edge(bm, v->e, v, true, true); } @@ -285,14 +285,14 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) BMIter itersub; int untag_count = 0; BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EDGE_TAG)) { + if (!BMO_edge_flag_test(bm, e, EDGE_TAG)) { untag_count++; } } /* check that we have 2 edges remaining after dissolve */ if (untag_count <= 2) { - BMO_elem_flag_enable(bm, v, VERT_TAG); + BMO_vert_flag_enable(bm, v, VERT_TAG); } } @@ -301,7 +301,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) if (use_verts) { BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { - BMO_elem_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); + BMO_vert_flag_set(bm, v, VERT_MARK, !BM_vert_is_edge_pair(v)); } } @@ -314,8 +314,8 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) BMLoop *l_first, *l_iter; l_iter = l_first = BM_FACE_FIRST_LOOP(f_pair[j]); do { - BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC); + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); } while ((l_iter = l_iter->next) != l_first); } } @@ -341,12 +341,12 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) * so do this in a separate pass instead. */ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { BM_edge_kill(bm, e); } } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { BM_vert_kill(bm, v); } } @@ -355,7 +355,7 @@ void bmo_dissolve_edges_exec(BMesh *bm, BMOperator *op) if (use_verts) { BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { if (BM_vert_is_edge_pair(v)) { BM_vert_collapse_edge(bm, v->e, v, true, true); } @@ -376,7 +376,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) const bool use_boundary_tear = BMO_slot_bool_get(op->slots_in, "use_boundary_tear"); BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { - BMO_elem_flag_enable(bm, v, VERT_MARK | VERT_ISGC); + BMO_vert_flag_enable(bm, v, VERT_MARK | VERT_ISGC); } if (use_face_split) { @@ -388,7 +388,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) if (!BM_vert_is_edge_pair(v)) { BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_enable(bm, v, VERT_MARK_TEAR); + BMO_vert_flag_enable(bm, v, VERT_MARK_TEAR); break; } } @@ -406,8 +406,8 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMLoop *l_iter; l_iter = l_first; do { - BMO_elem_flag_enable(bm, l_iter->v, VERT_ISGC); - BMO_elem_flag_enable(bm, l_iter->e, EDGE_ISGC); + BMO_vert_flag_enable(bm, l_iter->v, VERT_ISGC); + BMO_edge_flag_enable(bm, l_iter->e, EDGE_ISGC); } while ((l_iter = l_iter->next) != l_first); e_first = l_first->e; @@ -428,14 +428,14 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { /* tag here so we avoid feedback loop (checking topology as we edit) */ if (BM_vert_is_edge_pair(v)) { - BMO_elem_flag_enable(bm, v, VERT_MARK_PAIR); + BMO_vert_flag_enable(bm, v, VERT_MARK_PAIR); } } BMO_ITER (v, &oiter, op->slots_in, "verts", BM_VERT) { BMIter itersub; - if (!BMO_elem_flag_test(bm, v, VERT_MARK_PAIR)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK_PAIR)) { BM_ITER_ELEM (e, &itersub, v, BM_EDGES_OF_VERT) { BMFace *fa, *fb; if (BM_edge_face_pair(e, &fa, &fb)) { @@ -456,7 +456,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) /* Cleanup geometry (#BM_faces_join_pair, but it removes geometry we're looping on) * so do this in a separate pass instead. */ BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { - if ((e->l == NULL) && BMO_elem_flag_test(bm, e, EDGE_ISGC)) { + if ((e->l == NULL) && BMO_edge_flag_test(bm, e, EDGE_ISGC)) { BM_edge_kill(bm, e); } } @@ -469,7 +469,7 @@ void bmo_dissolve_verts_exec(BMesh *bm, BMOperator *op) } BM_ITER_MESH_MUTABLE (v, v_next, &iter, bm, BM_VERTS_OF_MESH) { - if ((v->e == NULL) && BMO_elem_flag_test(bm, v, VERT_ISGC)) { + if ((v->e == NULL) && BMO_vert_flag_test(bm, v, VERT_ISGC)) { BM_vert_kill(bm, v); } } @@ -518,9 +518,9 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* collapse zero length edges, this accounts for zero area faces too */ found = false; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (BM_edge_calc_length_squared(e) < dist_sq) { - BMO_elem_flag_enable(bm, e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, e, EDGE_COLLAPSE); found = true; } } @@ -543,7 +543,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* clip degenerate ears from the face */ found = false; BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (e->l && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e->l && BMO_edge_flag_test(bm, e, EDGE_MARK)) { BMLoop *l_iter, *l_first; l_iter = l_first = e->l; do { @@ -553,11 +553,11 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) ((void)BM_elem_flag_enable(l_iter, BM_ELEM_TAG), /* check we're marked to tested (radial edge already tested) */ - BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_MARK) && + BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_MARK) && /* check edges are not already going to be collapsed */ - !BMO_elem_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && - !BMO_elem_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) + !BMO_edge_flag_test(bm, l_iter->e, EDGE_COLLAPSE) && + !BMO_edge_flag_test(bm, l_iter->prev->e, EDGE_COLLAPSE))) { /* test if the faces loop (ear) is degenerate */ float dir_prev[3], len_prev; @@ -577,14 +577,14 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) /* both edges the same length */ if (l_iter->f->len == 3) { /* ideally this would have been discovered with short edge test above */ - BMO_elem_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_iter->next->e, EDGE_COLLAPSE); found = true; } else { /* add a joining edge and tag for removal */ BMLoop *l_split; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; reset = true; } @@ -599,7 +599,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) BLI_assert(v_new == l_iter->next->v); (void)v_new; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; } reset = true; @@ -613,7 +613,7 @@ void bmo_dissolve_degenerate_exec(BMesh *bm, BMOperator *op) BLI_assert(v_new == l_iter->prev->v); (void)v_new; if (BM_face_split(bm, l_iter->f, l_iter->prev, l_iter->next, &l_split, NULL, true)) { - BMO_elem_flag_enable(bm, l_split->e, EDGE_COLLAPSE); + BMO_edge_flag_enable(bm, l_split->e, EDGE_COLLAPSE); found = true; } reset = true; diff --git a/source/blender/bmesh/operators/bmo_dupe.c b/source/blender/bmesh/operators/bmo_dupe.c index fd430de80f9..56639a097b6 100644 --- a/source/blender/bmesh/operators/bmo_dupe.c +++ b/source/blender/bmesh/operators/bmo_dupe.c @@ -63,7 +63,7 @@ static BMVert *bmo_vert_copy( BM_elem_attrs_copy(bm_src, bm_dst, v_src, v_dst); /* Mark the vert for output */ - BMO_elem_flag_enable(bm_dst, v_dst, DUPE_NEW); + BMO_vert_flag_enable(bm_dst, v_dst, DUPE_NEW); return v_dst; } @@ -94,7 +94,7 @@ static BMEdge *bmo_edge_copy( BMLoop *l_iter_src, *l_first_src; l_iter_src = l_first_src = e_src->l; do { - if (BMO_elem_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, l_iter_src->f, DUPE_INPUT)) { rlen++; } } while ((l_iter_src = l_iter_src->radial_next) != l_first_src); @@ -123,7 +123,7 @@ static BMEdge *bmo_edge_copy( BM_elem_attrs_copy(bm_src, bm_dst, e_src, e_dst); /* Mark the edge for output */ - BMO_elem_flag_enable(bm_dst, e_dst, DUPE_NEW); + BMO_edge_flag_enable(bm_dst, e_dst, DUPE_NEW); return e_dst; } @@ -175,7 +175,7 @@ static BMFace *bmo_face_copy( (l_iter_src = l_iter_src->next) != l_first_src); /* Mark the face for output */ - BMO_elem_flag_enable(bm_dst, f_dst, DUPE_NEW); + BMO_face_flag_enable(bm_dst, f_dst, DUPE_NEW); return f_dst; } @@ -209,8 +209,8 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) /* duplicate flagged vertices */ BM_ITER_MESH (v, &viter, bm_src, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm_src, v, DUPE_INPUT) && - !BMO_elem_flag_test(bm_src, v, DUPE_DONE)) + if (BMO_vert_flag_test(bm_src, v, DUPE_INPUT) && + BMO_vert_flag_test(bm_src, v, DUPE_DONE) == false) { BMIter iter; bool isolated = true; @@ -218,7 +218,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) v2 = bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { isolated = false; break; } @@ -226,7 +226,7 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) if (isolated) { BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT)) { + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT)) { isolated = false; break; } @@ -237,53 +237,53 @@ static void bmo_mesh_copy(BMOperator *op, BMesh *bm_dst, BMesh *bm_src) BMO_slot_map_elem_insert(op, slot_isovert_map_out, v, v2); } - BMO_elem_flag_enable(bm_src, v, DUPE_DONE); + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); } } /* now we dupe all the edges */ BM_ITER_MESH (e, &eiter, bm_src, BM_EDGES_OF_MESH) { - if (BMO_elem_flag_test(bm_src, e, DUPE_INPUT) && - !BMO_elem_flag_test(bm_src, e, DUPE_DONE)) + if (BMO_edge_flag_test(bm_src, e, DUPE_INPUT) && + BMO_edge_flag_test(bm_src, e, DUPE_DONE) == false) { /* make sure that verts are copied */ - if (!BMO_elem_flag_test(bm_src, e->v1, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, e->v1, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v1, vhash); - BMO_elem_flag_enable(bm_src, e->v1, DUPE_DONE); + BMO_vert_flag_enable(bm_src, e->v1, DUPE_DONE); } - if (!BMO_elem_flag_test(bm_src, e->v2, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, e->v2, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, e->v2, vhash); - BMO_elem_flag_enable(bm_src, e->v2, DUPE_DONE); + BMO_vert_flag_enable(bm_src, e->v2, DUPE_DONE); } /* now copy the actual edge */ bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, bm_dst, bm_src, e, vhash, ehash); - BMO_elem_flag_enable(bm_src, e, DUPE_DONE); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); } } /* first we dupe all flagged faces and their elements from source */ BM_ITER_MESH (f, &fiter, bm_src, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm_src, f, DUPE_INPUT)) { + if (BMO_face_flag_test(bm_src, f, DUPE_INPUT)) { /* vertex pass */ BM_ITER_ELEM (v, &viter, f, BM_VERTS_OF_FACE) { - if (!BMO_elem_flag_test(bm_src, v, DUPE_DONE)) { + if (!BMO_vert_flag_test(bm_src, v, DUPE_DONE)) { bmo_vert_copy(op, slot_vert_map_out, bm_dst, bm_src, v, vhash); - BMO_elem_flag_enable(bm_src, v, DUPE_DONE); + BMO_vert_flag_enable(bm_src, v, DUPE_DONE); } } /* edge pass */ BM_ITER_ELEM (e, &eiter, f, BM_EDGES_OF_FACE) { - if (!BMO_elem_flag_test(bm_src, e, DUPE_DONE)) { + if (!BMO_edge_flag_test(bm_src, e, DUPE_DONE)) { bmo_edge_copy(op, slot_edge_map_out, slot_boundary_map_out, bm_dst, bm_src, e, vhash, ehash); - BMO_elem_flag_enable(bm_src, e, DUPE_DONE); + BMO_edge_flag_enable(bm_src, e, DUPE_DONE); } } bmo_face_copy(op, slot_face_map_out, bm_dst, bm_src, f, vhash, ehash); - BMO_elem_flag_enable(bm_src, f, DUPE_DONE); + BMO_face_flag_enable(bm_src, f, DUPE_DONE); } } @@ -408,26 +408,26 @@ void bmo_split_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { bool found = false; BM_ITER_ELEM (f, &iter2, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, SPLIT_INPUT)) { + if (!BMO_face_flag_test(bm, f, SPLIT_INPUT)) { found = true; break; } } if (found == false) { - BMO_elem_flag_enable(bm, e, SPLIT_INPUT); + BMO_edge_flag_enable(bm, e, SPLIT_INPUT); } } BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { bool found = false; BM_ITER_ELEM (e, &iter2, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SPLIT_INPUT)) { + if (!BMO_edge_flag_test(bm, e, SPLIT_INPUT)) { found = true; break; } } if (found == false) { - BMO_elem_flag_enable(bm, v, SPLIT_INPUT); + BMO_vert_flag_enable(bm, v, SPLIT_INPUT); } } } diff --git a/source/blender/bmesh/operators/bmo_edgenet.c b/source/blender/bmesh/operators/bmo_edgenet.c index f348014cead..64b092da5c8 100644 --- a/source/blender/bmesh/operators/bmo_edgenet.c +++ b/source/blender/bmesh/operators/bmo_edgenet.c @@ -94,8 +94,8 @@ static BMEdge *edge_next(BMesh *bm, BMEdge *e) for (i = 0; i < 2; i++) { BM_ITER_ELEM (e2, &iter, i ? e->v2 : e->v1, BM_EDGES_OF_VERT) { - if ((BMO_elem_flag_test(bm, e2, EDGE_MARK)) && - (!BMO_elem_flag_test(bm, e2, EDGE_VIS)) && + if ((BMO_edge_flag_test(bm, e2, EDGE_MARK)) && + (BMO_edge_flag_test(bm, e2, EDGE_VIS) == false) && (e2 != e)) { return e2; @@ -144,7 +144,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) count = 0; while (1) { BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - if (!BMO_elem_flag_test(bm, e, EDGE_VIS)) { + if (!BMO_edge_flag_test(bm, e, EDGE_VIS)) { if (BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v1, EDGE_MARK, true) == 1 || BMO_iter_elem_count_flag(bm, BM_EDGES_OF_VERT, e->v2, EDGE_MARK, true) == 1) { @@ -169,7 +169,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) i = 0; while (e) { - BMO_elem_flag_enable(bm, e, EDGE_VIS); + BMO_edge_flag_enable(bm, e, EDGE_VIS); BLI_array_grow_one(edges); edges[i] = e; @@ -258,9 +258,9 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) } e = BM_edge_create(bm, v1, v3, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); e = BM_edge_create(bm, v2, v4, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); } else if (edges1) { BMVert *v1, *v2; @@ -270,7 +270,7 @@ void bmo_edgenet_prepare_exec(BMesh *bm, BMOperator *op) i = BLI_array_count(edges1) - 1; v2 = BM_vert_in_edge(edges1[i - 1], edges1[i]->v1) ? edges1[i]->v2 : edges1[i]->v1; e = BM_edge_create(bm, v1, v2, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, e, ELE_NEW); + BMO_edge_flag_enable(bm, e, ELE_NEW); } } diff --git a/source/blender/bmesh/operators/bmo_extrude.c b/source/blender/bmesh/operators/bmo_extrude.c index 5a3bef6ba81..87369472df7 100644 --- a/source/blender/bmesh/operators/bmo_extrude.c +++ b/source/blender/bmesh/operators/bmo_extrude.c @@ -70,10 +70,10 @@ void bmo_extrude_discrete_faces_exec(BMesh *bm, BMOperator *op) BMLoop *l_org, *l_org_first; BMLoop *l_new; - BMO_elem_flag_enable(bm, f_org, EXT_DEL); + BMO_face_flag_enable(bm, f_org, EXT_DEL); f_new = BM_face_copy(bm, bm, f_org, true, true); - BMO_elem_flag_enable(bm, f_new, EXT_KEEP); + BMO_face_flag_enable(bm, f_new, EXT_KEEP); if (select_history_map) { BMEditSelection *ese; @@ -188,9 +188,9 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) BMEdge *e, *e_new; BMO_ITER (e, &siter, op->slots_in, "edges", BM_EDGE) { - BMO_elem_flag_enable(bm, e, EXT_INPUT); - BMO_elem_flag_enable(bm, e->v1, EXT_INPUT); - BMO_elem_flag_enable(bm, e->v2, EXT_INPUT); + BMO_edge_flag_enable(bm, e, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v1, EXT_INPUT); + BMO_vert_flag_enable(bm, e->v2, EXT_INPUT); } BMO_op_initf( @@ -228,13 +228,14 @@ void bmo_extrude_edge_only_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, f_verts, 4, NULL, BM_CREATE_NOP, true); bm_extrude_copy_face_loop_attributes(bm, f); - if (BMO_elem_flag_test(bm, e, EXT_INPUT)) + if (BMO_edge_flag_test(bm, e, EXT_INPUT)) { e = e_new; + } - BMO_elem_flag_enable(bm, f, EXT_KEEP); - BMO_elem_flag_enable(bm, e, EXT_KEEP); - BMO_elem_flag_enable(bm, e->v1, EXT_KEEP); - BMO_elem_flag_enable(bm, e->v2, EXT_KEEP); + BMO_face_flag_enable(bm, f, EXT_KEEP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v1, EXT_KEEP); + BMO_vert_flag_enable(bm, e->v2, EXT_KEEP); } @@ -258,7 +259,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) for (v = BMO_iter_new(&siter, op->slots_in, "verts", BM_VERT); v; v = BMO_iter_step(&siter)) { dupev = BM_vert_create(bm, v->co, v, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, dupev, EXT_KEEP); + BMO_vert_flag_enable(bm, dupev, EXT_KEEP); if (has_vskin) bm_extrude_disable_skin_root(bm, v); @@ -279,7 +280,7 @@ void bmo_extrude_vert_indiv_exec(BMesh *bm, BMOperator *op) } e = BM_edge_create(bm, v, dupev, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, e, EXT_KEEP); + BMO_edge_flag_enable(bm, e, EXT_KEEP); } if (select_history_map) { @@ -350,7 +351,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) int edge_face_tot; - if (!BMO_elem_flag_test(bm, e, EXT_INPUT)) { + if (!BMO_edge_flag_test(bm, e, EXT_INPUT)) { continue; } @@ -358,7 +359,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) edge_face_tot = 0; /* edge/face count */ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { found = true; delorig = true; break; @@ -369,7 +370,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) if ((edge_face_tot > 1) && (found == false)) { /* edge has a face user, that face isn't extrude input */ - BMO_elem_flag_enable(bm, e, EXT_DEL); + BMO_edge_flag_enable(bm, e, EXT_DEL); } } } @@ -380,7 +381,9 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) found = false; BM_ITER_ELEM (e, &viter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EXT_INPUT) || !BMO_elem_flag_test(bm, e, EXT_DEL)) { + if (!BMO_edge_flag_test(bm, e, EXT_INPUT) || + !BMO_edge_flag_test(bm, e, EXT_DEL)) + { found = true; break; } @@ -389,7 +392,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* avoid an extra loop */ if (found == true) { BM_ITER_ELEM (f, &viter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (!BMO_face_flag_test(bm, f, EXT_INPUT)) { found = true; break; } @@ -397,14 +400,14 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) } if (found == false) { - BMO_elem_flag_enable(bm, v, EXT_DEL); + BMO_vert_flag_enable(bm, v, EXT_DEL); } } } BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, EXT_INPUT)) { - BMO_elem_flag_enable(bm, f, EXT_DEL); + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { + BMO_face_flag_enable(bm, f, EXT_DEL); } } @@ -426,7 +429,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) } slot_facemap_out = BMO_slot_get(dupeop.slots_out, "face_map.out"); - if (bm->act_face && BMO_elem_flag_test(bm, bm->act_face, EXT_INPUT)) { + if (bm->act_face && BMO_face_flag_test(bm, bm->act_face, EXT_INPUT)) { bm->act_face = BMO_slot_map_elem_get(slot_facemap_out, bm->act_face); } @@ -437,7 +440,7 @@ void bmo_extrude_face_region_exec(BMesh *bm, BMOperator *op) /* if not delorig, reverse loops of original face */ if (!delorig) { BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, EXT_INPUT)) { + if (BMO_face_flag_test(bm, f, EXT_INPUT)) { BM_face_normal_flip(bm, f); } } @@ -583,7 +586,7 @@ static void calc_solidify_normals(BMesh *bm) BM_mesh_elem_index_ensure(bm, BM_EDGE); BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (!BMO_face_flag_test(bm, f, FACE_MARK)) { continue; } @@ -591,15 +594,15 @@ static void calc_solidify_normals(BMesh *bm) /* And mark all edges and vertices on the * marked faces */ - BMO_elem_flag_enable(bm, e, EDGE_MARK); - BMO_elem_flag_enable(bm, e->v1, VERT_MARK); - BMO_elem_flag_enable(bm, e->v2, VERT_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); + BMO_vert_flag_enable(bm, e->v1, VERT_MARK); + BMO_vert_flag_enable(bm, e->v2, VERT_MARK); edge_face_count[BM_elem_index_get(e)]++; } } BM_ITER_MESH (e, &eiter, bm, BM_EDGES_OF_MESH) { - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { continue; } @@ -608,9 +611,9 @@ static void calc_solidify_normals(BMesh *bm) if (i == 0 || i > 2) { /* Edge & vertices are non-manifold even when considering * only marked faces */ - BMO_elem_flag_enable(bm, e, EDGE_NONMAN); - BMO_elem_flag_enable(bm, e->v1, VERT_NONMAN); - BMO_elem_flag_enable(bm, e->v2, VERT_NONMAN); + BMO_edge_flag_enable(bm, e, EDGE_NONMAN); + BMO_vert_flag_enable(bm, e->v1, VERT_NONMAN); + BMO_vert_flag_enable(bm, e->v2, VERT_NONMAN); } } MEM_freeN(edge_face_count); @@ -618,11 +621,11 @@ static void calc_solidify_normals(BMesh *bm) BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { if (!BM_vert_is_manifold(v)) { - BMO_elem_flag_enable(bm, v, VERT_NONMAN); + BMO_vert_flag_enable(bm, v, VERT_NONMAN); continue; } - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { zero_v3(v->no); } } @@ -631,20 +634,20 @@ static void calc_solidify_normals(BMesh *bm) /* If the edge is not part of a the solidify region * its normal should not be considered */ - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) { continue; } /* If the edge joins more than two marked faces high * quality normal computation won't work */ - if (BMO_elem_flag_test(bm, e, EDGE_NONMAN)) { + if (BMO_edge_flag_test(bm, e, EDGE_NONMAN)) { continue; } f1 = f2 = NULL; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { if (f1 == NULL) { f1 = f; } @@ -664,8 +667,7 @@ static void calc_solidify_normals(BMesh *bm) /* two faces using this edge, calculate the edge normal * using the angle between the faces as a weighting */ add_v3_v3v3(edge_normal, f1->no, f2->no); - normalize_v3(edge_normal); - mul_v3_fl(edge_normal, angle); + normalize_v3_length(edge_normal, angle); } else { /* can't do anything useful here! @@ -689,11 +691,11 @@ static void calc_solidify_normals(BMesh *bm) /* normalize accumulated vertex normal */ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK)) { continue; } - if (BMO_elem_flag_test(bm, v, VERT_NONMAN)) { + if (BMO_vert_flag_test(bm, v, VERT_NONMAN)) { /* use standard normals for vertices connected to non-manifold edges */ BM_vert_normal_update(v); } @@ -701,7 +703,7 @@ static void calc_solidify_normals(BMesh *bm) /* exceptional case, totally flat. use the normal * of any marked face around the vertex */ BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { break; } } @@ -726,7 +728,7 @@ static void solidify_add_thickness(BMesh *bm, const float dist) BM_mesh_elem_index_ensure(bm, BM_VERT); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (BMO_elem_flag_test(bm, f, FACE_MARK)) { + if (BMO_face_flag_test(bm, f, FACE_MARK)) { /* array for passing verts to angle_poly_v3 */ float *face_angles = BLI_buffer_reinit_data(&face_angles_buf, float, f->len); diff --git a/source/blender/bmesh/operators/bmo_fill_edgeloop.c b/source/blender/bmesh/operators/bmo_fill_edgeloop.c index 0fbaf5ff11a..c68130bc11d 100644 --- a/source/blender/bmesh/operators/bmo_fill_edgeloop.c +++ b/source/blender/bmesh/operators/bmo_fill_edgeloop.c @@ -59,14 +59,14 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) i = 0; BMO_ITER (e, &oiter, op->slots_in, "edges", BM_EDGE) { BMIter viter; - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); BM_ITER_ELEM (v, &viter, e, BM_VERTS_OF_EDGE) { - if (BMO_elem_flag_test(bm, v, VERT_USED) == false) { + if (BMO_vert_flag_test(bm, v, VERT_USED) == false) { if (i == tote) { goto cleanup; } - BMO_elem_flag_enable(bm, v, VERT_USED); + BMO_vert_flag_enable(bm, v, VERT_USED); verts[i++] = v; } } @@ -103,21 +103,21 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) while (totv_used < totv) { for (i = 0; i < totv; i++) { v = verts[i]; - if (BMO_elem_flag_test(bm, v, VERT_USED)) { + if (BMO_vert_flag_test(bm, v, VERT_USED)) { break; } } /* this should never fail, as long as (totv_used < totv) * we should have marked verts available */ - BLI_assert(BMO_elem_flag_test(bm, v, VERT_USED)); + BLI_assert(BMO_vert_flag_test(bm, v, VERT_USED)); /* watch it, 'i' is used for final face length */ i = 0; do { /* we know that there are 2 edges per vertex so no need to check */ BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (e != e_prev) { e_next = e; break; @@ -127,7 +127,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) /* fill in the array */ f_verts[i] = v; - BMO_elem_flag_disable(bm, v, VERT_USED); + BMO_vert_flag_disable(bm, v, VERT_USED); totv_used++; /* step over the edges */ @@ -141,7 +141,7 @@ void bmo_edgeloop_fill_exec(BMesh *bm, BMOperator *op) /* don't use calc_edges option because we already have the edges */ f = BM_face_create_ngon_verts(bm, f_verts, i, NULL, BM_CREATE_NOP, true, false); - BMO_elem_flag_enable(bm, f, ELE_OUT); + BMO_face_flag_enable(bm, f, ELE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); diff --git a/source/blender/bmesh/operators/bmo_fill_grid.c b/source/blender/bmesh/operators/bmo_fill_grid.c index 77556591728..04ae915b707 100644 --- a/source/blender/bmesh/operators/bmo_fill_grid.c +++ b/source/blender/bmesh/operators/bmo_fill_grid.c @@ -466,7 +466,7 @@ static void bm_grid_fill_array( /* end interp */ - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); f->mat_nr = mat_nr; if (use_smooth) { BM_elem_flag_enable(f, BM_ELEM_SMOOTH); @@ -585,7 +585,7 @@ static void bm_edgeloop_flag_set(struct BMEdgeLoopStore *estore, char hflag, boo static bool bm_edge_test_cb(BMEdge *e, void *bm_v) { - return BMO_elem_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); + return BMO_edge_flag_test_bool((BMesh *)bm_v, e, EDGE_MARK); } static bool bm_edge_test_rail_cb(BMEdge *e, void *UNUSED(bm_v)) diff --git a/source/blender/bmesh/operators/bmo_hull.c b/source/blender/bmesh/operators/bmo_hull.c index 2dfad5a1f47..9c41e4f2115 100644 --- a/source/blender/bmesh/operators/bmo_hull.c +++ b/source/blender/bmesh/operators/bmo_hull.c @@ -81,7 +81,7 @@ static void hull_add_triangle( /* Mark triangles vertices as not interior */ for (i = 0; i < 3; i++) - BMO_elem_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); + BMO_vert_flag_disable(bm, t->v[i], HULL_FLAG_INTERIOR_ELE); BLI_gset_insert(hull_triangles, t); normal_tri_v3(t->no, v1->co, v2->co, v3->co); @@ -93,8 +93,8 @@ static BMFace *hull_find_example_face(BMesh *bm, BMEdge *e) BMFace *f; BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT) || - !BMO_elem_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM)) + if (BMO_face_flag_test(bm, f, HULL_FLAG_INPUT) || + BMO_face_flag_test(bm, f, HULL_FLAG_OUTPUT_GEOM) == false) { return f; } @@ -124,9 +124,9 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) * disabled, but an output face in the hull is the * same as a face in the existing mesh, it should not * be marked as unused or interior. */ - BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); - BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE); - BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); } else { /* Look for an adjacent face that existed before the hull */ @@ -140,12 +140,12 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) BM_face_copy_shared(bm, f, NULL, NULL); } /* Mark face for 'geom.out' slot and select */ - BMO_elem_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); + BMO_face_flag_enable(bm, f, HULL_FLAG_OUTPUT_GEOM); BM_face_select_set(bm, f, true); /* Mark edges for 'geom.out' slot */ for (i = 0; i < 3; i++) { - BMO_elem_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); + BMO_edge_flag_enable(bm, edges[i], HULL_FLAG_OUTPUT_GEOM); } } else { @@ -154,17 +154,17 @@ static void hull_output_triangles(BMesh *bm, GSet *hull_triangles) const int next = (i == 2 ? 0 : i + 1); BMEdge *e = BM_edge_exists(t->v[i], t->v[next]); if (e && - BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT) && - !BMO_elem_flag_test(bm, e, HULL_FLAG_HOLE)) + BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT) && + !BMO_edge_flag_test(bm, e, HULL_FLAG_HOLE)) { - BMO_elem_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); + BMO_edge_flag_enable(bm, e, HULL_FLAG_OUTPUT_GEOM); } } } /* Mark verts for 'geom.out' slot */ for (i = 0; i < 3; i++) { - BMO_elem_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); + BMO_vert_flag_enable(bm, t->v[i], HULL_FLAG_OUTPUT_GEOM); } } } @@ -292,8 +292,8 @@ static void hull_remove_overlapping( BM_vert_in_face(t->v[2], f) && f_on_hull) { t->skip = true; - BMO_elem_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); - BMO_elem_flag_enable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_HOLE); } } } @@ -310,13 +310,13 @@ static void hull_mark_interior_elements( /* Check for interior edges too */ BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { if (!hull_final_edges_lookup(final_edges, e->v1, e->v2)) - BMO_elem_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); + BMO_edge_flag_enable(bm, e, HULL_FLAG_INTERIOR_ELE); } /* Mark all input faces as interior, some may be unmarked in * hull_remove_overlapping() */ BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - BMO_elem_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); + BMO_face_flag_enable(bm, f, HULL_FLAG_INTERIOR_ELE); } } @@ -333,47 +333,50 @@ static void hull_tag_unused(BMesh *bm, BMOperator *op) * the hull), but that aren't also used by elements outside the * input set */ BMO_ITER (v, &oiter, op->slots_in, "input", BM_VERT) { - if (BMO_elem_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { + if (BMO_vert_flag_test(bm, v, HULL_FLAG_INTERIOR_ELE)) { bool del = true; BM_ITER_ELEM (e, &iter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, HULL_FLAG_INPUT)) { + if (!BMO_edge_flag_test(bm, e, HULL_FLAG_INPUT)) { del = false; break; } } BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { del = false; break; } } - if (del) - BMO_elem_flag_enable(bm, v, HULL_FLAG_DEL); + if (del) { + BMO_vert_flag_enable(bm, v, HULL_FLAG_DEL); + } } } BMO_ITER (e, &oiter, op->slots_in, "input", BM_EDGE) { - if (BMO_elem_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { + if (BMO_edge_flag_test(bm, e, HULL_FLAG_INTERIOR_ELE)) { bool del = true; BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_INPUT)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_INPUT)) { del = false; break; } } - if (del) - BMO_elem_flag_enable(bm, e, HULL_FLAG_DEL); + if (del) { + BMO_edge_flag_enable(bm, e, HULL_FLAG_DEL); + } } } BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) - BMO_elem_flag_enable(bm, f, HULL_FLAG_DEL); + if (BMO_face_flag_test(bm, f, HULL_FLAG_INTERIOR_ELE)) { + BMO_face_flag_enable(bm, f, HULL_FLAG_DEL); + } } } @@ -387,10 +390,10 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op) /* Unmark any hole faces if they are isolated or part of a * border */ BMO_ITER (f, &oiter, op->slots_in, "input", BM_FACE) { - if (BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) { + if (BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { BM_ITER_ELEM (e, &iter, f, BM_EDGES_OF_FACE) { if (BM_edge_is_boundary(e)) { - BMO_elem_flag_disable(bm, f, HULL_FLAG_HOLE); + BMO_face_flag_disable(bm, f, HULL_FLAG_HOLE); break; } } @@ -405,14 +408,14 @@ static void hull_tag_holes(BMesh *bm, BMOperator *op) BM_ITER_ELEM (f, &iter, e, BM_FACES_OF_EDGE) { any_faces = true; - if (!BMO_elem_flag_test(bm, f, HULL_FLAG_HOLE)) { + if (!BMO_face_flag_test(bm, f, HULL_FLAG_HOLE)) { hole = false; break; } } if (hole && any_faces) - BMO_elem_flag_enable(bm, e, HULL_FLAG_HOLE); + BMO_edge_flag_enable(bm, e, HULL_FLAG_HOLE); } } @@ -578,11 +581,17 @@ void bmo_convex_hull_exec(BMesh *bm, BMOperator *op) /* Tag input elements */ BMO_ITER (ele, &oiter, op->slots_in, "input", BM_ALL) { - BMO_elem_flag_enable(bm, ele, HULL_FLAG_INPUT); - + /* Mark all vertices as interior to begin with */ - if (ele->head.htype == BM_VERT) - BMO_elem_flag_enable(bm, ele, HULL_FLAG_INTERIOR_ELE); + if (ele->head.htype == BM_VERT) { + BMO_vert_flag_enable(bm, (BMVert *)ele, HULL_FLAG_INPUT | HULL_FLAG_INTERIOR_ELE); + } + else if (ele->head.htype == BM_EDGE) { + BMO_edge_flag_enable(bm, (BMEdge *)ele, HULL_FLAG_INPUT); + } + else { + BMO_face_flag_enable(bm, (BMFace *)ele, HULL_FLAG_INPUT); + } } hull_pool = BLI_mempool_create(sizeof(HullTriangle), 0, 128, BLI_MEMPOOL_NOP); diff --git a/source/blender/bmesh/operators/bmo_inset.c b/source/blender/bmesh/operators/bmo_inset.c index ef5d90e6acb..c52c608e671 100644 --- a/source/blender/bmesh/operators/bmo_inset.c +++ b/source/blender/bmesh/operators/bmo_inset.c @@ -313,7 +313,7 @@ static void bmo_face_inset_individual( l_iter->next->v, l_iter->v, f, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f_new_outer, ELE_NEW); + BMO_face_flag_enable(bm, f_new_outer, ELE_NEW); /* copy loop data */ l_other = l_iter->radial_next; @@ -1037,7 +1037,7 @@ void bmo_inset_region_exec(BMesh *bm, BMOperator *op) /* no need to check doubles, we KNOW there won't be any */ /* yes - reverse face is correct in this case */ f = BM_face_create_verts(bm, varr, j, es->l->f, BM_CREATE_NOP, true); - BMO_elem_flag_enable(bm, f, ELE_NEW); + BMO_face_flag_enable(bm, f, ELE_NEW); /* copy for loop data, otherwise UV's and vcols are no good. * tiny speedup here we could be more clever and copy from known adjacent data diff --git a/source/blender/bmesh/operators/bmo_join_triangles.c b/source/blender/bmesh/operators/bmo_join_triangles.c index 3718f14276c..bc620e4a020 100644 --- a/source/blender/bmesh/operators/bmo_join_triangles.c +++ b/source/blender/bmesh/operators/bmo_join_triangles.c @@ -315,7 +315,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) /* flag all edges of all input face */ BMO_ITER (f, &siter, op->slots_in, "faces", BM_FACE) { if (f->len == 3) { - BMO_elem_flag_enable(bm, f, FACE_INPUT); + BMO_face_flag_enable(bm, f, FACE_INPUT); } } @@ -323,11 +323,11 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BMFace *f_a, *f_b; if (BM_edge_face_pair(e, &f_a, &f_b) && - (BMO_elem_flag_test(bm, f_a, FACE_INPUT) && - BMO_elem_flag_test(bm, f_b, FACE_INPUT))) + (BMO_face_flag_test(bm, f_a, FACE_INPUT) && + BMO_face_flag_test(bm, f_b, FACE_INPUT))) { if (!bm_edge_is_delimit(e, &delimit_data)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); totedge_tag++; } } @@ -345,7 +345,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) const BMVert *verts[4]; float error; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) continue; bm_edge_to_quad_verts(e, verts); @@ -372,7 +372,7 @@ void bmo_join_triangles_exec(BMesh *bm, BMOperator *op) BMFace *f_new; f_new = BM_faces_join_pair(bm, f_a, f_b, e, true); if (f_new) { - BMO_elem_flag_enable(bm, f_new, FACE_OUT); + BMO_face_flag_enable(bm, f_new, FACE_OUT); } } } diff --git a/source/blender/bmesh/operators/bmo_normals.c b/source/blender/bmesh/operators/bmo_normals.c index 6044960265b..73dbee25be3 100644 --- a/source/blender/bmesh/operators/bmo_normals.c +++ b/source/blender/bmesh/operators/bmo_normals.c @@ -86,7 +86,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f int f_start_index; int i; - /* Search for the best loop. Members are comapred in-order defined here. */ + /* Search for the best loop. Members are compared in-order defined here. */ struct { /* Squared distance from the center to the loops vertex 'l->v'. * The normalized direction between the center and this vertex is also used for the dot-products below. */ @@ -111,7 +111,7 @@ static int recalc_face_normals_find_index(BMesh *bm, BMFace **faces, const int f madd_v3_v3fl(cent, f_cent, cent_fac * f_area); cent_area_accum += f_area; - BLI_assert(BMO_elem_flag_test(bm, faces[i], FACE_TEMP) == 0); + BLI_assert(BMO_face_flag_test(bm, faces[i], FACE_TEMP) == 0); BLI_assert(BM_face_is_normal_valid(faces[i])); } @@ -209,7 +209,7 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f f_start_index = recalc_face_normals_find_index(bm, faces, faces_len, &is_flip); if (is_flip) { - BMO_elem_flag_enable(bm, faces[f_start_index], FACE_FLIP); + BMO_face_flag_enable(bm, faces[f_start_index], FACE_FLIP); } /* now that we've found our starting face, make all connected faces @@ -219,10 +219,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f BLI_LINKSTACK_INIT(fstack); BLI_LINKSTACK_PUSH(fstack, faces[f_start_index]); - BMO_elem_flag_enable(bm, faces[f_start_index], FACE_TEMP); + BMO_face_flag_enable(bm, faces[f_start_index], FACE_TEMP); while ((f = BLI_LINKSTACK_POP(fstack))) { - const bool flip_state = BMO_elem_flag_test_bool(bm, f, FACE_FLIP); + const bool flip_state = BMO_face_flag_test_bool(bm, f, FACE_FLIP); BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); @@ -230,9 +230,9 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f BMLoop *l_other = l_iter->radial_next; if ((l_other != l_iter) && bmo_recalc_normal_loop_filter_cb(l_iter, NULL)) { - if (!BMO_elem_flag_test(bm, l_other->f, FACE_TEMP)) { - BMO_elem_flag_enable(bm, l_other->f, FACE_TEMP); - BMO_elem_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); + if (!BMO_face_flag_test(bm, l_other->f, FACE_TEMP)) { + BMO_face_flag_enable(bm, l_other->f, FACE_TEMP); + BMO_face_flag_set(bm, l_other->f, FACE_FLIP, (l_other->v == l_iter->v) != flip_state); BLI_LINKSTACK_PUSH(fstack, l_other->f); } } @@ -243,10 +243,10 @@ static void bmo_recalc_face_normals_array(BMesh *bm, BMFace **faces, const int f /* apply flipping to oflag'd faces */ for (i = 0; i < faces_len; i++) { - if (BMO_elem_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { + if (BMO_face_flag_test(bm, faces[i], oflag_flip) == oflag_flip) { BM_face_normal_flip(bm, faces[i]); } - BMO_elem_flag_disable(bm, faces[i], FACE_TEMP); + BMO_face_flag_disable(bm, faces[i], FACE_TEMP); } } @@ -284,7 +284,7 @@ void bmo_recalc_face_normals_exec(BMesh *bm, BMOperator *op) faces_grp[j] = BM_face_at_index(bm, groups_array[fg_sta + j]); if (is_calc == false) { - is_calc = BMO_elem_flag_test_bool(bm, faces_grp[j], FACE_FLAG); + is_calc = BMO_face_flag_test_bool(bm, faces_grp[j], FACE_FLAG); } } diff --git a/source/blender/bmesh/operators/bmo_offset_edgeloops.c b/source/blender/bmesh/operators/bmo_offset_edgeloops.c index 8f4bc5ef3ad..7a6f779b34f 100644 --- a/source/blender/bmesh/operators/bmo_offset_edgeloops.c +++ b/source/blender/bmesh/operators/bmo_offset_edgeloops.c @@ -178,7 +178,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) #ifdef USE_CAP_OPTION if (v_edges_num_untag == 1) { - BMO_elem_flag_enable(bm, v, ELE_VERT_ENDPOINT); + BMO_vert_flag_enable(bm, v, ELE_VERT_ENDPOINT); } CLAMP_MIN(v_edges_max, v_edges_num); @@ -201,7 +201,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) (BM_elem_index_get(l->prev->v) == -1)) { #ifdef USE_CAP_OPTION - if (use_cap_endpoint || (BMO_elem_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) + if (use_cap_endpoint || (BMO_vert_flag_test(bm, v, ELE_VERT_ENDPOINT) == 0)) #endif { BMLoop *l_new; @@ -209,7 +209,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BLI_assert(f_cmp == l->f); BLI_assert(f_cmp != l_new->f); UNUSED_VARS_NDEBUG(f_cmp); - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); } } else if (l->f->len > 4) { @@ -222,7 +222,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BM_face_split(bm, l->f, l->prev->prev, l->next, &l_new, NULL, true); BLI_assert(f_cmp == l->f); BLI_assert(f_cmp != l_new->f); - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); BM_elem_flag_disable(l->f, BM_ELEM_TAG); } else { @@ -230,7 +230,7 @@ void bmo_offset_edgeloops_exec(BMesh *bm, BMOperator *op) BMLoop *l_new; bm_face_split_walk_back(bm, l, &l_new); do { - BMO_elem_flag_enable(bm, l_new->e, ELE_NEW); + BMO_edge_flag_enable(bm, l_new->e, ELE_NEW); l_new = l_new->next; } while (BM_vert_is_edge_pair(l_new->v)); BM_elem_flag_disable(l->f, BM_ELEM_TAG); diff --git a/source/blender/bmesh/operators/bmo_planar_faces.c b/source/blender/bmesh/operators/bmo_planar_faces.c index 2856d3d18a6..a0951455fb4 100644 --- a/source/blender/bmesh/operators/bmo_planar_faces.c +++ b/source/blender/bmesh/operators/bmo_planar_faces.c @@ -71,13 +71,13 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (!BMO_elem_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { - BMO_elem_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); + if (!BMO_vert_flag_test(bm, l_iter->v, ELE_VERT_ADJUST)) { + BMO_vert_flag_enable(bm, l_iter->v, ELE_VERT_ADJUST); shared_vert_num += 1; } } while ((l_iter = l_iter->next) != l_first); - BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); } vert_accum_pool = BLI_mempool_create(sizeof(struct VertAccum), 0, 512, BLI_MEMPOOL_NOP); @@ -91,10 +91,10 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) BMLoop *l_iter, *l_first; float plane[4]; - if (!BMO_elem_flag_test(bm, f, ELE_FACE_ADJUST)) { + if (!BMO_face_flag_test(bm, f, ELE_FACE_ADJUST)) { continue; } - BMO_elem_flag_disable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_disable(bm, f, ELE_FACE_ADJUST); BLI_assert(f->len != 3); @@ -130,7 +130,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) BMIter iter; if (len_squared_v3v3(v->co, va->co) > eps_sq) { - BMO_elem_flag_enable(bm, v, ELE_VERT_ADJUST); + BMO_vert_flag_enable(bm, v, ELE_VERT_ADJUST); interp_v3_v3v3(v->co, v->co, va->co, fac); changed = true; } @@ -138,7 +138,7 @@ void bmo_planar_faces_exec(BMesh *bm, BMOperator *op) /* tag for re-calculation */ BM_ITER_ELEM (f, &iter, v, BM_FACES_OF_VERT) { if (f->len != 3) { - BMO_elem_flag_enable(bm, f, ELE_FACE_ADJUST); + BMO_face_flag_enable(bm, f, ELE_FACE_ADJUST); } } } diff --git a/source/blender/bmesh/operators/bmo_poke.c b/source/blender/bmesh/operators/bmo_poke.c index 4d86d6e8e5b..32ad25b7b82 100644 --- a/source/blender/bmesh/operators/bmo_poke.c +++ b/source/blender/bmesh/operators/bmo_poke.c @@ -87,7 +87,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) bm_face_calc_center_fn(f, f_center); v_center = BM_vert_create(bm, f_center, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v_center, ELE_NEW); + BMO_vert_flag_enable(bm, v_center, ELE_NEW); if (cd_loop_mdisp_offset != -1) { if (center_mode == BMOP_POKE_MEAN) { @@ -128,7 +128,7 @@ void bmo_poke_exec(BMesh *bm, BMOperator *op) BM_elem_attrs_copy(bm, bm, l_iter, l_new); BM_elem_attrs_copy(bm, bm, l_iter->next, l_new->next); - BMO_elem_flag_enable(bm, f_new, ELE_NEW); + BMO_face_flag_enable(bm, f_new, ELE_NEW); if (cd_loop_mdisp_offset != -1) { float f_new_center[3]; diff --git a/source/blender/bmesh/operators/bmo_primitive.c b/source/blender/bmesh/operators/bmo_primitive.c index b120b48447f..d2b9fa9efa3 100644 --- a/source/blender/bmesh/operators/bmo_primitive.c +++ b/source/blender/bmesh/operators/bmo_primitive.c @@ -259,7 +259,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) vec[0] = ((x * xtot_inv2) - 1.0f) * dia; mul_v3_m4v3(tvec, mat, vec); varr[i] = BM_vert_create(bm, tvec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, varr[i], VERT_MARK); + BMO_vert_flag_enable(bm, varr[i], VERT_MARK); i++; } } @@ -277,7 +277,7 @@ void bmo_create_grid_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, vquad, 4, NULL, BM_CREATE_NOP, true); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } } @@ -315,7 +315,7 @@ void BM_mesh_calc_uvs_grid(BMesh *bm, const unsigned int x_segments, const unsig BLI_assert(cd_loop_uv_offset != -1); BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; BM_ITER_ELEM_INDEX (l, &liter, f, BM_LOOPS_OF_FACE, loop_index) { @@ -380,11 +380,11 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) vec[1] = dia * sinf(phi); vec[2] = dia * cosf(phi); eve = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, eve, VERT_MARK); + BMO_vert_flag_enable(bm, eve, VERT_MARK); if (a != 0) { e = BM_edge_create(bm, preveve, eve, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, e, EDGE_ORIG); + BMO_edge_flag_enable(bm, e, EDGE_ORIG); } phi += phid; @@ -442,14 +442,14 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) bool valid = true; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { valid = false; break; } } if (valid) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -458,7 +458,7 @@ void bmo_create_uvsphere_exec(BMesh *bm, BMOperator *op) /* and now do imat */ BM_ITER_MESH (eve, &iter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, eve, VERT_MARK)) { + if (BMO_vert_flag_test(bm, eve, VERT_MARK)) { mul_m4_v3(mat, eve->co); } } @@ -493,7 +493,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) vec[2] = dia_div * icovert[a][2]; eva[a] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, eva[a], VERT_MARK); + BMO_vert_flag_enable(bm, eva[a], VERT_MARK); } for (a = 0; a < 20; a++) { @@ -507,10 +507,10 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) eftemp = BM_face_create_quad_tri(bm, v1, v2, v3, NULL, NULL, BM_CREATE_NOP); BM_ITER_ELEM (l, &liter, eftemp, BM_LOOPS_OF_FACE) { - BMO_elem_flag_enable(bm, l->e, EDGE_MARK); + BMO_edge_flag_enable(bm, l->e, EDGE_MARK); } - BMO_elem_flag_enable(bm, eftemp, FACE_MARK); + BMO_face_flag_enable(bm, eftemp, FACE_MARK); } if (subdiv > 1) { @@ -540,14 +540,14 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) bool valid = true; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->v, VERT_MARK)) { + if (!BMO_vert_flag_test(bm, l->v, VERT_MARK)) { valid = false; break; } } if (valid) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -556,7 +556,7 @@ void bmo_create_icosphere_exec(BMesh *bm, BMOperator *op) /* must transform after because of sphere subdivision */ BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { mul_m4_v3(mat, v->co); } } @@ -626,7 +626,7 @@ void BM_mesh_calc_uvs_sphere(BMesh *bm, const short oflag) BLI_assert(cd_loop_uv_offset != -1); /* caller is responsible for giving us UVs */ BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; bm_mesh_calc_uvs_sphere_face(f, mat_rot, cd_loop_uv_offset); @@ -650,7 +650,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) v[1] = monkeyv[i][2] / -128.0; tv[i] = BM_vert_create(bm, v, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, tv[i], VERT_MARK); + BMO_vert_flag_enable(bm, tv[i], VERT_MARK); if (fabsf(v[0] = -v[0]) < 0.001f) { tv[monkeynv + i] = tv[i]; @@ -661,7 +661,7 @@ void bmo_create_monkey_exec(BMesh *bm, BMOperator *op) tv[monkeynv + i] = eve; } - BMO_elem_flag_enable(bm, tv[monkeynv + i], VERT_MARK); + BMO_vert_flag_enable(bm, tv[monkeynv + i], VERT_MARK); mul_m4_v3(mat, tv[i]->co); } @@ -713,7 +713,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); cent1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, cent1, VERT_MARK); + BMO_vert_flag_enable(bm, cent1, VERT_MARK); } for (a = 0; a < segs; a++, phi += phid) { @@ -724,7 +724,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); v1 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v1, VERT_MARK); if (lastv1) BM_edge_create(bm, v1, lastv1, NULL, BM_CREATE_NOP); @@ -733,7 +733,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) BMFace *f; f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } if (!firstv1) @@ -751,7 +751,7 @@ void bmo_create_circle_exec(BMesh *bm, BMOperator *op) BMFace *f; f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); if (calc_uvs) { BM_mesh_calc_uvs_circle(bm, mat, dia, FACE_NEW); @@ -791,7 +791,7 @@ void BM_mesh_calc_uvs_circle(BMesh *bm, float mat[4][4], const float radius, con invert_m4_m4(inv_mat, mat); BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { @@ -845,8 +845,8 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) cent2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, cent1, VERT_MARK); - BMO_elem_flag_enable(bm, cent2, VERT_MARK); + BMO_vert_flag_enable(bm, cent1, VERT_MARK); + BMO_vert_flag_enable(bm, cent2, VERT_MARK); } for (a = 0; a < segs; a++, phi += phid) { @@ -862,27 +862,27 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) mul_m4_v3(mat, vec); v2 = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, v1, VERT_MARK); - BMO_elem_flag_enable(bm, v2, VERT_MARK); + BMO_vert_flag_enable(bm, v1, VERT_MARK); + BMO_vert_flag_enable(bm, v2, VERT_MARK); if (a) { if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, lastv1, v1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); f = BM_face_create_quad_tri(bm, cent2, v2, lastv2, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } f = BM_face_create_quad_tri(bm, lastv1, lastv2, v2, v1, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } else { @@ -900,20 +900,20 @@ void bmo_create_cone_exec(BMesh *bm, BMOperator *op) if (cap_ends) { f = BM_face_create_quad_tri(bm, cent1, v1, firstv1, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); f = BM_face_create_quad_tri(bm, cent2, firstv2, v2, NULL, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } - BMO_elem_flag_enable(bm, f, FACE_NEW); + BMO_face_flag_enable(bm, f, FACE_NEW); } f = BM_face_create_quad_tri(bm, v1, v2, firstv2, firstv1, NULL, BM_CREATE_NOP); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } if (calc_uvs) { @@ -981,7 +981,7 @@ void BM_mesh_calc_uvs_cone( y = 1.0f - uv_height; BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) + if (!BMO_face_flag_test(bm, f, oflag)) continue; if (f->len == 4 && radius_top && radius_bottom) { @@ -1063,7 +1063,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) float vec[3] = {(float)x * off, (float)y * off, (float)z * off}; mul_m4_v3(mat, vec); verts[i] = BM_vert_create(bm, vec, NULL, BM_CREATE_NOP); - BMO_elem_flag_enable(bm, verts[i], VERT_MARK); + BMO_vert_flag_enable(bm, verts[i], VERT_MARK); i++; } } @@ -1080,7 +1080,7 @@ void bmo_create_cube_exec(BMesh *bm, BMOperator *op) f = BM_face_create_verts(bm, quad, 4, NULL, BM_CREATE_NOP, true); if (calc_uvs) { - BMO_elem_flag_enable(bm, f, FACE_MARK); + BMO_face_flag_enable(bm, f, FACE_MARK); } } @@ -1117,7 +1117,7 @@ void BM_mesh_calc_uvs_cube(BMesh *bm, const short oflag) BLI_assert(cd_loop_uv_offset != -1); /* the caller can ensure that we have UVs */ BM_ITER_MESH (f, &fiter, bm, BM_FACES_OF_MESH) { - if (!BMO_elem_flag_test(bm, f, oflag)) { + if (!BMO_face_flag_test(bm, f, oflag)) { continue; } diff --git a/source/blender/bmesh/operators/bmo_removedoubles.c b/source/blender/bmesh/operators/bmo_removedoubles.c index c58b4814726..6da591b23a0 100644 --- a/source/blender/bmesh/operators/bmo_removedoubles.c +++ b/source/blender/bmesh/operators/bmo_removedoubles.c @@ -98,7 +98,7 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target { #define LOOP_MAP_VERT_INIT(l_init, v_map, is_del) \ v_map = l_init->v; \ - is_del = BMO_elem_flag_test_bool(bm, v_map, ELE_DEL); \ + is_del = BMO_vert_flag_test_bool(bm, v_map, ELE_DEL); \ if (is_del) { \ v_map = BMO_slot_map_elem_get(slot_targetmap, v_map); \ } ((void)0) @@ -131,12 +131,12 @@ static BMFace *remdoubles_createface(BMesh *bm, BMFace *f, BMOpSlot *slot_target } if (e_new) { - if (UNLIKELY(BMO_elem_flag_test(bm, v_curr, VERT_IN_FACE))) { + if (UNLIKELY(BMO_vert_flag_test(bm, v_curr, VERT_IN_FACE))) { /* we can't make the face, bail out */ STACK_CLEAR(edges); goto finally; } - BMO_elem_flag_enable(bm, v_curr, VERT_IN_FACE); + BMO_vert_flag_enable(bm, v_curr, VERT_IN_FACE); STACK_PUSH(edges, e_new); STACK_PUSH(loops, l_curr); @@ -155,7 +155,7 @@ finally: { unsigned int i; for (i = 0; i < STACK_SIZE(verts); i++) { - BMO_elem_flag_disable(bm, verts[i], VERT_IN_FACE); + BMO_vert_flag_disable(bm, verts[i], VERT_IN_FACE); } } @@ -198,7 +198,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) /* mark merge verts for deletion */ BM_ITER_MESH (v1, &iter, bm, BM_VERTS_OF_MESH) { if ((v2 = BMO_slot_map_elem_get(slot_targetmap, v1))) { - BMO_elem_flag_enable(bm, v1, ELE_DEL); + BMO_vert_flag_enable(bm, v1, ELE_DEL); /* merge the vertex flags, else we get randomly selected/unselected verts */ BM_elem_flag_merge(v1, v2); @@ -212,8 +212,8 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) } BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { - const bool is_del_v1 = BMO_elem_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); - const bool is_del_v2 = BMO_elem_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); + const bool is_del_v1 = BMO_vert_flag_test_bool(bm, (v1 = e->v1), ELE_DEL); + const bool is_del_v2 = BMO_vert_flag_test_bool(bm, (v2 = e->v2), ELE_DEL); if (is_del_v1 || is_del_v2) { if (is_del_v1) @@ -222,7 +222,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) v2 = BMO_slot_map_elem_get(slot_targetmap, v2); if (v1 == v2) { - BMO_elem_flag_enable(bm, e, EDGE_COL); + BMO_edge_flag_enable(bm, e, EDGE_COL); } else { /* always merge flags, even for edges we already created */ @@ -233,7 +233,7 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) BM_elem_flag_merge(e_new, e); } - BMO_elem_flag_enable(bm, e, ELE_DEL); + BMO_edge_flag_enable(bm, e, ELE_DEL); } } @@ -244,16 +244,16 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) int edge_collapse = 0; BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->v, ELE_DEL)) { + if (BMO_vert_flag_test(bm, l->v, ELE_DEL)) { vert_delete = true; } - if (BMO_elem_flag_test(bm, l->e, EDGE_COL)) { + if (BMO_edge_flag_test(bm, l->e, EDGE_COL)) { edge_collapse++; } } if (vert_delete) { - BMO_elem_flag_enable(bm, f, ELE_DEL); + BMO_face_flag_enable(bm, f, ELE_DEL); if (f->len - edge_collapse >= 3) { BMFace *f_new = remdoubles_createface(bm, f, slot_targetmap); @@ -261,8 +261,12 @@ void bmo_weld_verts_exec(BMesh *bm, BMOperator *op) /* do this so we don't need to return a list of created faces */ if (f_new) { bmesh_face_swap_data(f_new, f); - SWAP(BMFlagLayer *, f->oflags, f_new->oflags); - BMO_elem_flag_disable(bm, f, ELE_DEL); + + if (bm->use_toolflags) { + SWAP(BMFlagLayer *, ((BMFace_OFlag *)f)->oflags, ((BMFace_OFlag *)f_new)->oflags); + } + + BMO_face_flag_disable(bm, f, ELE_DEL); BM_face_kill(bm, f_new); } @@ -439,7 +443,7 @@ void bmo_collapse_exec(BMesh *bm, BMOperator *op) float min[3], max[3], center[3]; BMVert *v_tar; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK)) + if (!BMO_edge_flag_test(bm, e, EDGE_MARK)) continue; BLI_assert(BLI_stack_is_empty(edge_stack)); @@ -510,7 +514,7 @@ static void bmo_collapsecon_do_layer(BMesh *bm, const int layer, const short ofl BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->e, oflag)) { + if (BMO_edge_flag_test(bm, l->e, oflag)) { /* walk */ BLI_assert(BLI_stack_is_empty(block_stack)); @@ -606,7 +610,7 @@ static void bmesh_find_doubles_common( for (i = 0; i < verts_len; i++) { BMVert *v_check = verts[i]; - if (BMO_elem_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { + if (BMO_vert_flag_test(bm, v_check, VERT_DOUBLE | VERT_TARGET)) { continue; } @@ -614,7 +618,7 @@ static void bmesh_find_doubles_common( BMVert *v_other = verts[j]; /* a match has already been found, (we could check which is best, for now don't) */ - if (BMO_elem_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { + if (BMO_vert_flag_test(bm, v_other, VERT_DOUBLE | VERT_TARGET)) { continue; } @@ -628,19 +632,19 @@ static void bmesh_find_doubles_common( } if (keepvert) { - if (BMO_elem_flag_test(bm, v_other, VERT_KEEP) == BMO_elem_flag_test(bm, v_check, VERT_KEEP)) + if (BMO_vert_flag_test(bm, v_other, VERT_KEEP) == BMO_vert_flag_test(bm, v_check, VERT_KEEP)) continue; } if (compare_len_squared_v3v3(v_check->co, v_other->co, dist_sq)) { /* If one vert is marked as keep, make sure it will be the target */ - if (BMO_elem_flag_test(bm, v_other, VERT_KEEP)) { + if (BMO_vert_flag_test(bm, v_other, VERT_KEEP)) { SWAP(BMVert *, v_check, v_other); } - BMO_elem_flag_enable(bm, v_other, VERT_DOUBLE); - BMO_elem_flag_enable(bm, v_check, VERT_TARGET); + BMO_vert_flag_enable(bm, v_other, VERT_DOUBLE); + BMO_vert_flag_enable(bm, v_check, VERT_TARGET); BMO_slot_map_elem_insert(optarget, optarget_slot, v_other, v_check); } @@ -683,8 +687,8 @@ void bmo_automerge_exec(BMesh *bm, BMOperator *op) * as VERT_KEEP. */ BMO_slot_buffer_flag_enable(bm, op->slots_in, "verts", BM_VERT, VERT_IN); BM_ITER_MESH (v, &viter, bm, BM_VERTS_OF_MESH) { - if (!BMO_elem_flag_test(bm, v, VERT_IN)) { - BMO_elem_flag_enable(bm, v, VERT_KEEP); + if (!BMO_vert_flag_test(bm, v, VERT_IN)) { + BMO_vert_flag_enable(bm, v, VERT_KEEP); } } diff --git a/source/blender/bmesh/operators/bmo_similar.c b/source/blender/bmesh/operators/bmo_similar.c index 708d57a7a08..454d6d8c6c8 100644 --- a/source/blender/bmesh/operators/bmo_similar.c +++ b/source/blender/bmesh/operators/bmo_similar.c @@ -121,8 +121,8 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) * and n is the total number of faces */ BMO_ITER (fs, &fs_iter, op->slots_in, "faces", BM_FACE) { - if (!BMO_elem_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */ - BMO_elem_flag_enable(bm, fs, FACE_MARK); + if (!BMO_face_flag_test(bm, fs, FACE_MARK)) { /* is this really needed ? */ + BMO_face_flag_enable(bm, fs, FACE_MARK); num_sels++; } } @@ -134,7 +134,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) /* loop through all the faces and fill the faces/indices structure */ BM_ITER_MESH (fm, &fm_iter, bm, BM_FACES_OF_MESH) { f_ext[i].f = fm; - if (BMO_elem_flag_test(bm, fm, FACE_MARK)) { + if (BMO_face_flag_test(bm, fm, FACE_MARK)) { indices[idx] = i; idx++; } @@ -179,21 +179,21 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) /* now select the rest (if any) */ for (i = 0; i < num_total; i++) { fm = f_ext[i].f; - if (!BMO_elem_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) { + if (!BMO_face_flag_test(bm, fm, FACE_MARK) && !BM_elem_flag_test(fm, BM_ELEM_HIDDEN)) { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { fs = f_ext[indices[idx]].f; switch (type) { case SIMFACE_MATERIAL: if (fm->mat_nr == fs->mat_nr) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; case SIMFACE_IMAGE: if (f_ext[i].t == f_ext[indices[idx]].t) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -201,7 +201,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_NORMAL: angle = angle_normalized_v3v3(fs->no, fm->no); /* if the angle between the normals -> 0 */ if (angle <= thresh_radians) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -218,7 +218,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) if (angle <= thresh_radians) { /* and dot product difference -> 0 */ delta_fl = f_ext[i].d - (f_ext[indices[idx]].d * sign); if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } } @@ -227,7 +227,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_AREA: delta_fl = f_ext[i].area - f_ext[indices[idx]].area; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -235,7 +235,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_SIDES: delta_i = fm->len - fs->len; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -243,14 +243,14 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) case SIMFACE_PERIMETER: delta_fl = f_ext[i].perim - f_ext[indices[idx]].perim; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; case SIMFACE_SMOOTH: if (BM_elem_flag_test(fm, BM_ELEM_SMOOTH) == BM_elem_flag_test(fs, BM_ELEM_SMOOTH)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } break; @@ -263,7 +263,7 @@ void bmo_similar_faces_exec(BMesh *bm, BMOperator *op) ffa2 = CustomData_bmesh_get(&bm->pdata, fm->head.data, CD_FREESTYLE_FACE); if (ffa1 && ffa2 && (ffa1->flag & FREESTYLE_FACE_MARK) == (ffa2->flag & FREESTYLE_FACE_MARK)) { - BMO_elem_flag_enable(bm, fm, FACE_MARK); + BMO_face_flag_enable(bm, fm, FACE_MARK); cont = false; } } @@ -350,7 +350,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* iterate through all selected edges and mark them */ BMO_ITER (es, &es_iter, op->slots_in, "edges", BM_EDGE) { - BMO_elem_flag_enable(bm, es, EDGE_MARK); + BMO_edge_flag_enable(bm, es, EDGE_MARK); num_sels++; } @@ -361,7 +361,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* loop through all the edges and fill the edges/indices structure */ BM_ITER_MESH (e, &e_iter, bm, BM_EDGES_OF_MESH) { e_ext[i].e = e; - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { indices[idx] = i; idx++; } @@ -397,7 +397,9 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) /* select the edges if any */ for (i = 0; i < num_total; i++) { e = e_ext[i].e; - if (!BMO_elem_flag_test(bm, e, EDGE_MARK) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (!BMO_edge_flag_test(bm, e, EDGE_MARK) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { es = e_ext[indices[idx]].e; @@ -405,7 +407,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_LENGTH: delta_fl = e_ext[i].length - e_ext[indices[idx]].length; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -418,7 +420,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) angle = fabsf(angle - (float)M_PI); if (angle / (float)M_PI_2 <= thresh) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -426,7 +428,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_FACE: delta_i = e_ext[i].faces - e_ext[indices[idx]].faces; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -435,7 +437,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) if (e_ext[i].faces == 2) { if (e_ext[indices[idx]].faces == 2) { if (fabsf(e_ext[i].angle - e_ext[indices[idx]].angle) <= thresh) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -454,7 +456,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) delta_fl = *c1 - *c2; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -469,7 +471,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) delta_fl = *c1 - *c2; if (bm_sel_similar_cmp_fl(delta_fl, thresh, compare)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -477,14 +479,14 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) case SIMEDGE_SEAM: if (BM_elem_flag_test(e, BM_ELEM_SEAM) == BM_elem_flag_test(es, BM_ELEM_SEAM)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; case SIMEDGE_SHARP: if (BM_elem_flag_test(e, BM_ELEM_SMOOTH) == BM_elem_flag_test(es, BM_ELEM_SMOOTH)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } break; @@ -497,7 +499,7 @@ void bmo_similar_edges_exec(BMesh *bm, BMOperator *op) fed2 = CustomData_bmesh_get(&bm->edata, es->head.data, CD_FREESTYLE_EDGE); if (fed1 && fed2 && (fed1->flag & FREESTYLE_EDGE_MARK) == (fed2->flag & FREESTYLE_EDGE_MARK)) { - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); cont = false; } } @@ -562,7 +564,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* iterate through all selected edges and mark them */ BMO_ITER (vs, &vs_iter, op->slots_in, "verts", BM_VERT) { - BMO_elem_flag_enable(bm, vs, VERT_MARK); + BMO_vert_flag_enable(bm, vs, VERT_MARK); num_sels++; } @@ -573,7 +575,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* loop through all the vertices and fill the vertices/indices structure */ BM_ITER_MESH (v, &v_iter, bm, BM_VERTS_OF_MESH) { v_ext[i].v = v; - if (BMO_elem_flag_test(bm, v, VERT_MARK)) { + if (BMO_vert_flag_test(bm, v, VERT_MARK)) { indices[idx] = i; idx++; } @@ -599,7 +601,9 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* select the vertices if any */ for (i = 0; i < num_total; i++) { v = v_ext[i].v; - if (!BMO_elem_flag_test(bm, v, VERT_MARK) && !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) { + if (!BMO_vert_flag_test(bm, v, VERT_MARK) && + !BM_elem_flag_test(v, BM_ELEM_HIDDEN)) + { bool cont = true; for (idx = 0; idx < num_sels && cont == true; idx++) { vs = v_ext[indices[idx]].v; @@ -607,7 +611,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) case SIMVERT_NORMAL: /* compare the angle between the normals */ if (angle_normalized_v3v3(v->no, vs->no) <= thresh_radians) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; @@ -615,7 +619,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* number of adjacent faces */ delta_i = v_ext[i].num_faces - v_ext[indices[idx]].num_faces; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; @@ -623,7 +627,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) case SIMVERT_VGROUP: if (v_ext[i].dvert != NULL && v_ext[indices[idx]].dvert != NULL) { if (defvert_find_shared(v_ext[i].dvert, v_ext[indices[idx]].dvert) != -1) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } } @@ -632,7 +636,7 @@ void bmo_similar_verts_exec(BMesh *bm, BMOperator *op) /* number of adjacent edges */ delta_i = v_ext[i].num_edges - v_ext[indices[idx]].num_edges; if (bm_sel_similar_cmp_i(delta_i, compare)) { - BMO_elem_flag_enable(bm, v, VERT_MARK); + BMO_vert_flag_enable(bm, v, VERT_MARK); cont = false; } break; diff --git a/source/blender/bmesh/operators/bmo_subdivide.c b/source/blender/bmesh/operators/bmo_subdivide.c index 38fa2cfdcc8..894129b4a33 100644 --- a/source/blender/bmesh/operators/bmo_subdivide.c +++ b/source/blender/bmesh/operators/bmo_subdivide.c @@ -254,8 +254,7 @@ static void alter_co( copy_v3_v3(co, v->co); if (UNLIKELY(params->use_sphere)) { /* subdivide sphere */ - normalize_v3(co); - mul_v3_fl(co, params->smooth); + normalize_v3_length(co, params->smooth); } else if (params->use_smooth) { /* calculating twice and blending gives smoother results, @@ -384,7 +383,7 @@ static BMVert *bm_subdivide_edge_addvert( v_new = BM_edge_split(bm, edge, edge->v1, r_edge, factor_edge_split); - BMO_elem_flag_enable(bm, v_new, ELE_INNER); + BMO_vert_flag_enable(bm, v_new, ELE_INNER); /* offset for smooth or sphere or fractal */ alter_co(v_new, e_orig, params, factor_subd, v_a, v_b); @@ -419,7 +418,7 @@ static BMVert *subdivide_edge_num( BMVert *v_new; float factor_edge_split, factor_subd; - if (BMO_elem_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { + if (BMO_edge_flag_test(bm, edge, EDGE_PERCENT) && totpoint == 1) { factor_edge_split = BMO_slot_map_float_get(params->slot_edge_percents, edge); factor_subd = 0.0f; } @@ -449,9 +448,9 @@ static void bm_subdivide_multicut( for (i = 0; i < numcuts; i++) { v = subdivide_edge_num(bm, eed, &e_tmp, i, params->numcuts, params, v_a, v_b, &e_new); - BMO_elem_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); - BMO_elem_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); - BMO_elem_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); + BMO_vert_flag_enable(bm, v, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, eed, SUBD_SPLIT | ELE_SPLIT); + BMO_edge_flag_enable(bm, e_new, SUBD_SPLIT | ELE_SPLIT); BM_CHECK_ELEMENT(v); if (v->e) BM_CHECK_ELEMENT(v->e); @@ -698,8 +697,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts if (!e) continue; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); v1 = lines[(i + 1) * s] = verts[a]; @@ -711,7 +710,7 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts BMESH_ASSERT(v != NULL); - BMO_elem_flag_enable(bm, e_new, ELE_INNER); + BMO_edge_flag_enable(bm, e_new, ELE_INNER); lines[(i + 1) * s + a + 1] = v; } } @@ -724,8 +723,8 @@ static void quad_4edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts if (!e) continue; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); } } @@ -802,8 +801,8 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, e = connect_smallest_face(bm, verts[a], verts[b], &f_new); if (!e) goto cleanup; - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); lines[i + 1][0] = verts[a]; lines[i + 1][i + 1] = verts[b]; @@ -817,7 +816,7 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, v = subdivide_edge_num(bm, e, &e_tmp, j, i, params, verts[a], verts[b], &e_new); lines[i + 1][j + 1] = v; - BMO_elem_flag_enable(bm, e_new, ELE_INNER); + BMO_edge_flag_enable(bm, e_new, ELE_INNER); } } @@ -837,13 +836,13 @@ static void tri_3edge_subdivide(BMesh *bm, BMFace *UNUSED(face), BMVert **verts, for (j = 0; j < i; j++) { e = connect_smallest_face(bm, lines[i][j], lines[i + 1][j + 1], &f_new); - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); e = connect_smallest_face(bm, lines[i][j + 1], lines[i + 1][j + 1], &f_new); - BMO_elem_flag_enable(bm, e, ELE_INNER); - BMO_elem_flag_enable(bm, f_new, ELE_INNER); + BMO_edge_flag_enable(bm, e, ELE_INNER); + BMO_face_flag_enable(bm, f_new, ELE_INNER); } } @@ -1023,7 +1022,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) edges[i] = l_new->e; verts[i] = l_new->v; - if (BMO_elem_flag_test(bm, edges[i], SUBD_SPLIT)) { + if (BMO_edge_flag_test(bm, edges[i], SUBD_SPLIT)) { if (!e1) e1 = edges[i]; else e2 = edges[i]; @@ -1043,13 +1042,13 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) } } - if (BMO_elem_flag_test(bm, face, FACE_CUSTOMFILL)) { + if (BMO_face_flag_test(bm, face, FACE_CUSTOMFILL)) { pat = *BMO_slot_map_data_get(params.slot_custom_patterns, face); for (i = 0; i < pat->len; i++) { matched = 1; for (j = 0; j < pat->len; j++) { a = (j + i) % pat->len; - if ((!!BMO_elem_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { + if ((!!BMO_edge_flag_test(bm, edges[a], SUBD_SPLIT)) != (!!pat->seledges[j])) { matched = 0; break; } @@ -1062,7 +1061,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) fd->start = verts[i]; fd->face = face; fd->totedgesel = totesel; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); break; } } @@ -1082,7 +1081,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) matched = 1; for (b = 0; b < pat->len; b++) { j = (b + a) % pat->len; - if ((!!BMO_elem_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { + if ((!!BMO_edge_flag_test(bm, edges[j], SUBD_SPLIT)) != (!!pat->seledges[b])) { matched = 0; break; } @@ -1094,7 +1093,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) if (matched) { SubDFaceData *fd; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); fd = BLI_stack_push_r(facedata); fd->pat = pat; @@ -1110,7 +1109,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) if (!matched && totesel) { SubDFaceData *fd; - BMO_elem_flag_enable(bm, face, SUBD_SPLIT); + BMO_face_flag_enable(bm, face, SUBD_SPLIT); /* must initialize all members here */ fd = BLI_stack_push_r(facedata); @@ -1162,22 +1161,22 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) /* find the boundary of one of the split edges */ for (a = 1; a < vlen; a++) { - if (!BMO_elem_flag_test(bm, loops[a - 1]->v, ELE_INNER) && - BMO_elem_flag_test(bm, loops[a]->v, ELE_INNER)) + if (!BMO_vert_flag_test(bm, loops[a - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[a]->v, ELE_INNER)) { break; } } - if (BMO_elem_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { + if (BMO_vert_flag_test(bm, loops[(a + numcuts + 1) % vlen]->v, ELE_INNER)) { b = (a + numcuts + 1) % vlen; } else { /* find the boundary of the other edge. */ for (j = 0; j < vlen; j++) { b = (j + a + numcuts + 1) % vlen; - if (!BMO_elem_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && - BMO_elem_flag_test(bm, loops[b]->v, ELE_INNER)) + if (!BMO_vert_flag_test(bm, loops[b == 0 ? vlen - 1 : b - 1]->v, ELE_INNER) && + BMO_vert_flag_test(bm, loops[b]->v, ELE_INNER)) { break; } @@ -1245,7 +1244,7 @@ void bmo_subdivide_edges_exec(BMesh *bm, BMOperator *op) BLI_assert(BM_edge_exists(loops_split[j][0]->v, loops_split[j][1]->v) == NULL); f_new = BM_face_split(bm, face, loops_split[j][0], loops_split[j][1], &l_new, NULL, false); if (f_new) { - BMO_elem_flag_enable(bm, l_new->e, ELE_INNER); + BMO_edge_flag_enable(bm, l_new->e, ELE_INNER); } } } diff --git a/source/blender/bmesh/operators/bmo_subdivide_edgering.c b/source/blender/bmesh/operators/bmo_subdivide_edgering.c index b5a95ad6283..b4a77bf1a38 100644 --- a/source/blender/bmesh/operators/bmo_subdivide_edgering.c +++ b/source/blender/bmesh/operators/bmo_subdivide_edgering.c @@ -128,7 +128,7 @@ static void bmo_edgeloop_vert_tag(BMesh *bm, struct BMEdgeLoopStore *el_store, c { LinkData *node = BM_edgeloop_verts_get(el_store)->first; do { - BMO_elem_flag_set(bm, (BMVert *)node->data, oflag, tag); + BMO_vert_flag_set(bm, (BMVert *)node->data, oflag, tag); } while ((node = node->next)); } @@ -137,7 +137,7 @@ static bool bmo_face_is_vert_tag_all(BMesh *bm, BMFace *f, short oflag) BMLoop *l_iter, *l_first; l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (!BMO_elem_flag_test(bm, l_iter->v, oflag)) { + if (!BMO_vert_flag_test(bm, l_iter->v, oflag)) { return false; } } while ((l_iter = l_iter->next) != l_first); @@ -150,7 +150,7 @@ static bool bm_vert_is_tag_edge_connect(BMesh *bm, BMVert *v) BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { BMVert *v_other = BM_edge_other_vert(e, v); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { return true; @@ -243,7 +243,7 @@ static GSet *bm_edgering_pair_calc(BMesh *bm, ListBase *eloops_rim) BMVert *v = ((LinkData *)BM_edgeloop_verts_get(el_store)->first)->data; BM_ITER_ELEM (e, &eiter, (BMVert *)v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { struct BMEdgeLoopStore *el_store_other; BMVert *v_other = BM_edge_other_vert(e, v); GHashPair pair_test; @@ -339,7 +339,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) if (UNLIKELY(BM_edge_is_wire(e))) { /* pass - this may confuse things */ } - else if (BMO_elem_flag_test(bm, e, EDGE_RIM)) { + else if (BMO_edge_flag_test(bm, e, EDGE_RIM)) { BMIter liter; BMLoop *l; BM_ITER_ELEM (l, &liter, e, BM_LOOPS_OF_EDGE) { @@ -347,7 +347,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) float no[3]; // BM_face_normal_update(l->f); BM_edge_calc_face_tangent(e, l, no); - if (BMO_elem_flag_test(bm, l->f, FACE_SHARED)) { + if (BMO_face_flag_test(bm, l->f, FACE_SHARED)) { add_v3_v3(no_inner, no); found_inner = true; } @@ -356,7 +356,7 @@ static void bm_vert_calc_surface_tangent(BMesh *bm, BMVert *v, float r_no[3]) found_outer = true; /* other side is used too, blend midway */ - if (BMO_elem_flag_test(bm, l->f, FACE_OUT)) { + if (BMO_face_flag_test(bm, l->f, FACE_OUT)) { found_outer_tag = true; } } @@ -400,9 +400,9 @@ static void bm_faces_share_tag_flush(BMesh *bm, BMEdge **e_arr, const unsigned i l_iter = l_first = e->l; do { - if (!BMO_elem_flag_test(bm, l_iter->f, FACE_SHARED)) { + if (!BMO_face_flag_test(bm, l_iter->f, FACE_SHARED)) { if (bmo_face_is_vert_tag_all(bm, l_iter->f, VERT_SHARED)) { - BMO_elem_flag_enable(bm, l_iter->f, FACE_SHARED); + BMO_face_flag_enable(bm, l_iter->f, FACE_SHARED); } } } while ((l_iter = l_iter->radial_next) != l_first); @@ -422,7 +422,7 @@ static void bm_faces_share_tag_clear(BMesh *bm, BMEdge **e_arr_iter, const unsig l_iter = l_first = e->l; do { - BMO_elem_flag_disable(bm, l_iter->f, FACE_SHARED); + BMO_face_flag_disable(bm, l_iter->f, FACE_SHARED); } while ((l_iter = l_iter->radial_next) != l_first); } } @@ -834,8 +834,8 @@ static void bm_face_slice(BMesh *bm, BMLoop *l, const int cuts) if (l_new->f->len < l_new->radial_next->f->len) { l_new = l_new->radial_next; } - BMO_elem_flag_enable(bm, l_new->f, FACE_OUT); - BMO_elem_flag_enable(bm, l_new->radial_next->f, FACE_OUT); + BMO_face_flag_enable(bm, l_new->f, FACE_OUT); + BMO_face_flag_enable(bm, l_new->radial_next->f, FACE_OUT); } } @@ -903,7 +903,7 @@ static void bm_edgering_pair_order( node = lb_a->first; BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (BMO_edge_flag_test(bm, e, EDGE_RING)) { v_other = BM_edge_other_vert(e, (BMVert *)node->data); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { break; @@ -938,7 +938,7 @@ static void bm_edgering_pair_order( /* if we dont share and edge - flip */ BMEdge *e = BM_edge_exists(((LinkData *)lb_a->first)->data, ((LinkData *)lb_b->first)->data); - if (e == NULL || !BMO_elem_flag_test(bm, e, EDGE_RING)) { + if (e == NULL || !BMO_edge_flag_test(bm, e, EDGE_RING)) { BM_edgeloop_flip(bm, el_store_b); } } @@ -983,19 +983,19 @@ static void bm_edgering_pair_subdiv( BMIter eiter; BM_ITER_ELEM (e, &eiter, (BMVert *)node->data, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, EDGE_IN_STACK)) { + if (!BMO_edge_flag_test(bm, e, EDGE_IN_STACK)) { BMVert *v_other = BM_edge_other_vert(e, (BMVert *)node->data); if (BM_elem_flag_test(v_other, BM_ELEM_TAG)) { BMIter fiter; - BMO_elem_flag_enable(bm, e, EDGE_IN_STACK); + BMO_edge_flag_enable(bm, e, EDGE_IN_STACK); STACK_PUSH(edges_ring_arr, e); /* add faces to the stack */ BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (BMO_elem_flag_test(bm, f, FACE_OUT)) { - if (!BMO_elem_flag_test(bm, f, FACE_IN_STACK)) { - BMO_elem_flag_enable(bm, f, FACE_IN_STACK); + if (BMO_face_flag_test(bm, f, FACE_OUT)) { + if (!BMO_face_flag_test(bm, f, FACE_IN_STACK)) { + BMO_face_flag_enable(bm, f, FACE_IN_STACK); STACK_PUSH(faces_ring_arr, f); } } @@ -1009,10 +1009,10 @@ static void bm_edgering_pair_subdiv( /* found opposite edge */ BMVert *v_other; - BMO_elem_flag_disable(bm, e, EDGE_IN_STACK); + BMO_edge_flag_disable(bm, e, EDGE_IN_STACK); /* unrelated to subdiv, but if we _don't_ clear flag, multiple rings fail */ - BMO_elem_flag_disable(bm, e, EDGE_RING); + BMO_edge_flag_disable(bm, e, EDGE_RING); v_other = BM_elem_flag_test(e->v1, BM_ELEM_TAG) ? e->v1 : e->v2; bm_edge_subdiv_as_loop(bm, eloops_ring, e, v_other, cuts); @@ -1021,12 +1021,12 @@ static void bm_edgering_pair_subdiv( while ((f = STACK_POP(faces_ring_arr))) { BMLoop *l_iter, *l_first; - BMO_elem_flag_disable(bm, f, FACE_IN_STACK); + BMO_face_flag_disable(bm, f, FACE_IN_STACK); /* Check each edge of the face */ l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - if (BMO_elem_flag_test(bm, l_iter->e, EDGE_RIM)) { + if (BMO_edge_flag_test(bm, l_iter->e, EDGE_RIM)) { bm_face_slice(bm, l_iter, cuts); break; } @@ -1064,7 +1064,7 @@ static void bm_edgering_pair_ringsubd( static bool bm_edge_rim_test_cb(BMEdge *e, void *bm_v) { BMesh *bm = bm_v; - return BMO_elem_flag_test_bool(bm, e, EDGE_RIM); + return BMO_edge_flag_test_bool(bm, e, EDGE_RIM); } @@ -1099,25 +1099,25 @@ void bmo_subdivide_edgering_exec(BMesh *bm, BMOperator *op) BMFace *f; BM_ITER_ELEM (f, &fiter, e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f, FACE_OUT)) { + if (!BMO_face_flag_test(bm, f, FACE_OUT)) { BMIter liter; BMLoop *l; bool ok = false; /* check at least 2 edges in the face are rings */ BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (BMO_elem_flag_test(bm, l->e, EDGE_RING) && e != l->e) { + if (BMO_edge_flag_test(bm, l->e, EDGE_RING) && e != l->e) { ok = true; break; } } if (ok) { - BMO_elem_flag_enable(bm, f, FACE_OUT); + BMO_face_flag_enable(bm, f, FACE_OUT); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->e, EDGE_RING)) { - BMO_elem_flag_enable(bm, l->e, EDGE_RIM); + if (!BMO_edge_flag_test(bm, l->e, EDGE_RING)) { + BMO_edge_flag_enable(bm, l->e, EDGE_RIM); } } } diff --git a/source/blender/bmesh/operators/bmo_triangulate.c b/source/blender/bmesh/operators/bmo_triangulate.c index 6fb09c76ea4..8938d086c1a 100644 --- a/source/blender/bmesh/operators/bmo_triangulate.c +++ b/source/blender/bmesh/operators/bmo_triangulate.c @@ -91,7 +91,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMVert **e_verts = &e->v1; unsigned int i; - BMO_elem_flag_enable(bm, e, EDGE_MARK); + BMO_edge_flag_enable(bm, e, EDGE_MARK); calc_winding = (calc_winding || BM_edge_is_boundary(e)); @@ -132,7 +132,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) add_v3_v3(normal, v->no); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (BMO_edge_flag_test(bm, e, EDGE_MARK)) { if (e_index == 2) { e_index = 0; break; @@ -203,7 +203,7 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) for (i = 0, i_prev = 2; i < 3; i_prev = i++) { e = BM_edge_exists(v_tri[i], v_tri[i_prev]); - if (e && BM_edge_is_boundary(e) && BMO_elem_flag_test(bm, e, EDGE_MARK)) { + if (e && BM_edge_is_boundary(e) && BMO_edge_flag_test(bm, e, EDGE_MARK)) { winding_votes += (e->l->v == v_tri[i]) ? 1 : -1; } } @@ -226,10 +226,10 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) sf_tri->v1->tmp.p, sf_tri->v2->tmp.p, sf_tri->v3->tmp.p, NULL, NULL, BM_CREATE_NO_DOUBLE); - BMO_elem_flag_enable(bm, f, ELE_NEW); + BMO_face_flag_enable(bm, f, ELE_NEW); BM_ITER_ELEM (l, &liter, f, BM_LOOPS_OF_FACE) { - if (!BMO_elem_flag_test(bm, l->e, EDGE_MARK)) { - BMO_elem_flag_enable(bm, l->e, ELE_NEW); + if (!BMO_edge_flag_test(bm, l->e, EDGE_MARK)) { + BMO_edge_flag_enable(bm, l->e, ELE_NEW); } } } @@ -244,29 +244,33 @@ void bmo_triangle_fill_exec(BMesh *bm, BMOperator *op) BMO_slot_buffer_flag_enable(bm, bmop.slots_out, "geom.out", BM_FACE | BM_EDGE, ELE_NEW); BMO_op_finish(bm, &bmop); } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); if (use_dissolve) { - BMO_ITER (e, &siter, op->slots_out, "geom.out", BM_EDGE) { - if (LIKELY(e->l)) { /* in rare cases the edges face will have already been removed from the edge */ - BMFace *f_new; - f_new = BM_faces_join_pair(bm, e->l->f, - e->l->radial_next->f, e, - false); /* join faces */ - if (f_new) { - BMO_elem_flag_enable(bm, f_new, ELE_NEW); - BM_edge_kill(bm, e); + BMEdge *e_next; + BMIter iter; + + BM_ITER_MESH_MUTABLE (e, e_next, &iter, bm, BM_EDGES_OF_MESH) { + if (BMO_edge_flag_test(bm, e, ELE_NEW)) { + /* in rare cases the edges face will have already been removed from the edge */ + if (LIKELY(e->l)) { + BMFace *f_new = BM_faces_join_pair( + bm, e->l->f, + e->l->radial_next->f, e, + false); /* join faces */ + if (f_new) { + BMO_face_flag_enable(bm, f_new, ELE_NEW); + BM_edge_kill(bm, e); + } + else { + BMO_error_clear(bm); + } } else { - BMO_error_clear(bm); + BM_edge_kill(bm, e); } } - else { - BM_edge_kill(bm, e); - } } - - BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } + + BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "geom.out", BM_EDGE | BM_FACE, ELE_NEW); } diff --git a/source/blender/bmesh/operators/bmo_utils.c b/source/blender/bmesh/operators/bmo_utils.c index e596032663e..aa1e4bc7523 100644 --- a/source/blender/bmesh/operators/bmo_utils.c +++ b/source/blender/bmesh/operators/bmo_utils.c @@ -48,7 +48,7 @@ void bmo_create_vert_exec(BMesh *bm, BMOperator *op) BMO_slot_vec_get(op->slots_in, "co", vec); - BMO_elem_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); + BMO_vert_flag_enable(bm, BM_vert_create(bm, vec, NULL, BM_CREATE_NOP), ELE_NEW); BMO_slot_buffer_from_enabled_flag(bm, op, op->slots_out, "vert.out", BM_VERT, ELE_NEW); } @@ -74,7 +74,7 @@ void bmo_transform_exec(BMesh *UNUSED(bm), BMOperator *op) void bmo_translate_exec(BMesh *bm, BMOperator *op) { float mat[4][4], vec[3]; - + BMO_slot_vec_get(op->slots_in, "vec", vec); unit_m4(mat); @@ -86,7 +86,7 @@ void bmo_translate_exec(BMesh *bm, BMOperator *op) void bmo_scale_exec(BMesh *bm, BMOperator *op) { float mat[3][3], vec[3]; - + BMO_slot_vec_get(op->slots_in, "vec", vec); unit_m3(mat); @@ -143,18 +143,18 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op) if (BM_edge_face_pair(e, &fa, &fb)) { /* check we're untouched */ - if (BMO_elem_flag_test(bm, fa, FACE_TAINT) == false && - BMO_elem_flag_test(bm, fb, FACE_TAINT) == false) + if (BMO_face_flag_test(bm, fa, FACE_TAINT) == false && + BMO_face_flag_test(bm, fb, FACE_TAINT) == false) { /* don't touch again (faces will be freed so run before rotating the edge) */ - BMO_elem_flag_enable(bm, fa, FACE_TAINT); - BMO_elem_flag_enable(bm, fb, FACE_TAINT); + BMO_face_flag_enable(bm, fa, FACE_TAINT); + BMO_face_flag_enable(bm, fb, FACE_TAINT); if (!(e2 = BM_edge_rotate(bm, e, use_ccw, check_flag))) { - BMO_elem_flag_disable(bm, fa, FACE_TAINT); - BMO_elem_flag_disable(bm, fb, FACE_TAINT); + BMO_face_flag_disable(bm, fa, FACE_TAINT); + BMO_face_flag_disable(bm, fb, FACE_TAINT); #if 0 BMO_error_raise(bm, op, BMERR_INVALID_SELECTION, "Could not rotate edge"); return; @@ -163,7 +163,7 @@ void bmo_rotate_edges_exec(BMesh *bm, BMOperator *op) continue; } - BMO_elem_flag_enable(bm, e2, EDGE_OUT); + BMO_edge_flag_enable(bm, e2, EDGE_OUT); } } } @@ -184,11 +184,11 @@ static void bmo_face_flag_set_flush(BMesh *bm, BMFace *f, const short oflag, con BMLoop *l_iter; BMLoop *l_first; - BMO_elem_flag_set(bm, f, oflag, value); + BMO_face_flag_set(bm, f, oflag, value); l_iter = l_first = BM_FACE_FIRST_LOOP(f); do { - BMO_elem_flag_set(bm, l_iter->e, oflag, value); - BMO_elem_flag_set(bm, l_iter->v, oflag, value); + BMO_edge_flag_set(bm, l_iter->e, oflag, value); + BMO_vert_flag_set(bm, l_iter->v, oflag, value); } while ((l_iter = l_iter->next) != l_first); } @@ -210,7 +210,9 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { found = true; break; } @@ -223,9 +225,11 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); - BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } } } @@ -234,7 +238,9 @@ static void bmo_region_extend_expand( BMFace *f; BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, SEL_FLAG) && !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) { + if (!BMO_face_flag_test(bm, f, SEL_FLAG) && + !BM_elem_flag_test(f, BM_ELEM_HIDDEN)) + { bmo_face_flag_set_flush(bm, f, SEL_FLAG, true); } } @@ -245,9 +251,11 @@ static void bmo_region_extend_expand( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(e)) { - if (!BMO_elem_flag_test(bm, e, SEL_FLAG) && !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); - BMO_elem_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); + if (!BMO_edge_flag_test(bm, e, SEL_FLAG) && + !BM_elem_flag_test(e, BM_ELEM_HIDDEN)) + { + BMO_edge_flag_enable(bm, e, SEL_FLAG); + BMO_vert_flag_enable(bm, BM_edge_other_vert(e, v), SEL_FLAG); } } } @@ -269,10 +277,10 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, f_other, SEL_FLAG); + BMO_face_flag_enable(bm, f_other, SEL_FLAG); } } } @@ -281,10 +289,10 @@ static void bmo_region_extend_expand( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG | SEL_FLAG) && !BM_elem_flag_test(f_other, BM_ELEM_HIDDEN)) { - BMO_elem_flag_enable(bm, f_other, SEL_FLAG); + BMO_face_flag_enable(bm, f_other, SEL_FLAG); } } } @@ -310,7 +318,7 @@ static void bmo_region_extend_contract( BMEdge *e; BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { found = true; break; } @@ -321,7 +329,7 @@ static void bmo_region_extend_contract( BMFace *f; BM_ITER_ELEM (f, &fiter, v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f, SEL_ORIG)) { + if (!BMO_face_flag_test(bm, f, SEL_ORIG)) { found = true; break; } @@ -334,7 +342,7 @@ static void bmo_region_extend_contract( BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { if (BM_edge_is_wire(e)) { - if (!BMO_elem_flag_test(bm, e, SEL_ORIG)) { + if (!BMO_edge_flag_test(bm, e, SEL_ORIG)) { found = true; break; } @@ -347,10 +355,10 @@ static void bmo_region_extend_contract( BMIter eiter; BMEdge *e; - BMO_elem_flag_enable(bm, v, SEL_FLAG); + BMO_vert_flag_enable(bm, v, SEL_FLAG); BM_ITER_ELEM (e, &eiter, v, BM_EDGES_OF_VERT) { - BMO_elem_flag_enable(bm, e, SEL_FLAG); + BMO_edge_flag_enable(bm, e, SEL_FLAG); } } } @@ -369,8 +377,8 @@ static void bmo_region_extend_contract( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->e, BM_FACES_OF_EDGE) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) { - BMO_elem_flag_enable(bm, f, SEL_FLAG); + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); break; } } @@ -380,8 +388,8 @@ static void bmo_region_extend_contract( BMFace *f_other; BM_ITER_ELEM (f_other, &fiter, l->v, BM_FACES_OF_VERT) { - if (!BMO_elem_flag_test(bm, f_other, SEL_ORIG)) { - BMO_elem_flag_enable(bm, f, SEL_FLAG); + if (!BMO_face_flag_test(bm, f_other, SEL_ORIG)) { + BMO_face_flag_enable(bm, f, SEL_FLAG); break; } } @@ -420,7 +428,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) const float fac = BMO_slot_float_get(op->slots_in, "factor"); int i, j, clipx, clipy, clipz; int xaxis, yaxis, zaxis; - + clipx = BMO_slot_bool_get(op->slots_in, "mirror_clip_x"); clipy = BMO_slot_bool_get(op->slots_in, "mirror_clip_y"); clipz = BMO_slot_bool_get(op->slots_in, "mirror_clip_z"); @@ -441,7 +449,7 @@ void bmo_smooth_vert_exec(BMesh *UNUSED(bm), BMOperator *op) add_v3_v3v3(co, co, co2); j += 1; } - + if (!j) { copy_v3_v3(co, v->co); i++; diff --git a/source/blender/bmesh/tools/bmesh_beautify.c b/source/blender/bmesh/tools/bmesh_beautify.c index 19fe492c670..3e3a6547b75 100644 --- a/source/blender/bmesh/tools/bmesh_beautify.c +++ b/source/blender/bmesh/tools/bmesh_beautify.c @@ -424,11 +424,13 @@ void BM_mesh_beautify_fill( flag, method); /* update flags */ - if (oflag_edge) - BMO_elem_flag_enable(bm, e, oflag_edge); + if (oflag_edge) { + BMO_edge_flag_enable(bm, e, oflag_edge); + } + if (oflag_face) { - BMO_elem_flag_enable(bm, e->l->f, oflag_face); - BMO_elem_flag_enable(bm, e->l->radial_next->f, oflag_face); + BMO_face_flag_enable(bm, e->l->f, oflag_face); + BMO_face_flag_enable(bm, e->l->radial_next->f, oflag_face); } } } diff --git a/source/blender/bmesh/tools/bmesh_bevel.c b/source/blender/bmesh/tools/bmesh_bevel.c index 0ed1dffcafb..b647f5a667d 100644 --- a/source/blender/bmesh/tools/bmesh_bevel.c +++ b/source/blender/bmesh/tools/bmesh_bevel.c @@ -1648,9 +1648,11 @@ static void build_boundary_vertex_only(BevelParams *bp, BevVert *bv, bool constr } } -/* Special case of build_boundary when a single edge is beveled. - * The 'width adjust' part of build_boundary has been done already, and - * efirst is the first beveled edge at vertex bv. */ +/** + * Special case of build_boundary when a single edge is beveled. + * The 'width adjust' part of build_boundary has been done already, + * and \a efirst is the first beveled edge at vertex \a bv. +*/ static void build_boundary_terminal_edge(BevelParams *bp, BevVert *bv, EdgeHalf *efirst, bool construct) { MemArena *mem_arena = bp->mem_arena; @@ -1849,11 +1851,11 @@ static void build_boundary(BevelParams *bp, BevVert *bv, bool construct) do { BLI_assert(e->is_bev); /* Make the BoundVert for the right side of e; other side will be made - * when the beveled edge to the left of e is handled. - * Analyze edges until next beveled edge. - * They are either "in plane" (preceding and subsequent faces are coplanar) - * or not. The "non-in-plane" edges effect silhouette and we prefer to slide - * along one of those if possible. */ + * when the beveled edge to the left of e is handled. + * Analyze edges until next beveled edge. + * They are either "in plane" (preceding and subsequent faces are coplanar) + * or not. The "non-in-plane" edges effect silhouette and we prefer to slide + * along one of those if possible. */ nip = nnip = 0; /* counts of in-plane / not-in-plane */ enip = eip = NULL; /* representatives of each */ for (e2 = e->next; !e2->is_bev; e2 = e2->next) { diff --git a/source/blender/bmesh/tools/bmesh_bisect_plane.c b/source/blender/bmesh/tools/bmesh_bisect_plane.c index 9fb6d39a008..51b92a3c45e 100644 --- a/source/blender/bmesh/tools/bmesh_bisect_plane.c +++ b/source/blender/bmesh/tools/bmesh_bisect_plane.c @@ -155,9 +155,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con BM_face_split(bm, f, l_a, l_b, &l_new, NULL, true); if (l_new) { if (oflag_center) { - BMO_elem_flag_enable(bm, l_new->e, oflag_center); - BMO_elem_flag_enable(bm, l_new->f, oflag_center); - BMO_elem_flag_enable(bm, f, oflag_center); + BMO_edge_flag_enable(bm, l_new->e, oflag_center); + BMO_face_flag_enable(bm, l_new->f, oflag_center); + BMO_face_flag_enable(bm, f, oflag_center); } } } @@ -270,9 +270,9 @@ static void bm_face_bisect_verts(BMesh *bm, BMFace *f, const float plane[4], con if (l_new) { if (oflag_center) { - BMO_elem_flag_enable(bm, l_new->e, oflag_center); - BMO_elem_flag_enable(bm, l_new->f, oflag_center); - BMO_elem_flag_enable(bm, face_split_arr[j], oflag_center); + BMO_edge_flag_enable(bm, l_new->e, oflag_center); + BMO_face_flag_enable(bm, l_new->f, oflag_center); + BMO_face_flag_enable(bm, face_split_arr[j], oflag_center); } } @@ -372,7 +372,7 @@ void BM_mesh_bisect_plane( if (BM_VERT_DIR(v) == 0) { if (oflag_center) { - BMO_elem_flag_enable(bm, v, oflag_center); + BMO_vert_flag_enable(bm, v, oflag_center); } if (use_snap_center) { closest_to_plane_v3(v->co, plane, v->co); @@ -407,7 +407,7 @@ void BM_mesh_bisect_plane( v_new = BM_edge_split(bm, e, e->v1, NULL, e_fac); vert_is_center_enable(v_new); if (oflag_center) { - BMO_elem_flag_enable(bm, v_new, oflag_center); + BMO_vert_flag_enable(bm, v_new, oflag_center); } BM_VERT_DIR(v_new) = 0; @@ -439,7 +439,7 @@ void BM_mesh_bisect_plane( /* if both verts are on the center - tag it */ if (oflag_center) { if (side[0] == 0 && side[1] == 0) { - BMO_elem_flag_enable(bm, e, oflag_center); + BMO_edge_flag_enable(bm, e, oflag_center); } } } diff --git a/source/blender/bmesh/tools/bmesh_decimate_collapse.c b/source/blender/bmesh/tools/bmesh_decimate_collapse.c index fe8b132a2a5..52a0df5b9d1 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_collapse.c +++ b/source/blender/bmesh/tools/bmesh_decimate_collapse.c @@ -68,7 +68,9 @@ #endif #define BOUNDARY_PRESERVE_WEIGHT 100.0f -#define OPTIMIZE_EPS 0.01f /* FLT_EPSILON is too small, see [#33106] */ +/* Uses double precision, impacts behavior on near-flat surfaces, + * cane give issues with very small faces. 1e-2 is too big, see: T48154. */ +#define OPTIMIZE_EPS 1e-8 #define COST_INVALID FLT_MAX typedef enum CD_UseFlag { @@ -140,8 +142,8 @@ static void bm_decim_build_quadrics(BMesh *bm, Quadric *vquadrics) } -static void bm_decim_calc_target_co( - BMEdge *e, float optimize_co[3], +static void bm_decim_calc_target_co_db( + BMEdge *e, double optimize_co[3], const Quadric *vquadrics) { /* compute an edge contraction target for edge 'e' @@ -158,10 +160,22 @@ static void bm_decim_calc_target_co( return; /* all is good */ } else { - mid_v3_v3v3(optimize_co, e->v1->co, e->v2->co); + optimize_co[0] = 0.5 * ((double)e->v1->co[0] + (double)e->v2->co[0]); + optimize_co[1] = 0.5 * ((double)e->v1->co[1] + (double)e->v2->co[1]); + optimize_co[2] = 0.5 * ((double)e->v1->co[2] + (double)e->v2->co[2]); } } +static void bm_decim_calc_target_co_fl( + BMEdge *e, float optimize_co[3], + const Quadric *vquadrics) +{ + double optimize_co_db[3]; + bm_decim_calc_target_co_db(e, optimize_co_db, vquadrics); + copy_v3fl_v3db(optimize_co, optimize_co_db); +} + + static bool bm_edge_collapse_is_degenerate_flip(BMEdge *e, const float optimize_co[3]) { BMIter liter; @@ -240,8 +254,6 @@ static void bm_decim_build_edge_cost_single( const float *vweights, const float vweight_factor, Heap *eheap, HeapNode **eheap_table) { - const Quadric *q1, *q2; - float optimize_co[3]; float cost; if (eheap_table[BM_elem_index_get(e)]) { @@ -279,15 +291,17 @@ static void bm_decim_build_edge_cost_single( } /* end sanity check */ + { + double optimize_co[3]; + bm_decim_calc_target_co_db(e, optimize_co, vquadrics); - bm_decim_calc_target_co(e, optimize_co, vquadrics); - - q1 = &vquadrics[BM_elem_index_get(e->v1)]; - q2 = &vquadrics[BM_elem_index_get(e->v2)]; - - cost = (BLI_quadric_evaluate(q1, optimize_co) + - BLI_quadric_evaluate(q2, optimize_co)); + const Quadric *q1, *q2; + q1 = &vquadrics[BM_elem_index_get(e->v1)]; + q2 = &vquadrics[BM_elem_index_get(e->v2)]; + cost = (BLI_quadric_evaluate(q1, optimize_co) + + BLI_quadric_evaluate(q2, optimize_co)); + } /* note, 'cost' shouldn't be negative but happens sometimes with small values. * this can cause faces that make up a flat surface to over-collapse, see [#37121] */ @@ -528,8 +542,8 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) { BMIter iter; BMFace *f; - bool has_quad; - bool has_ngon; + bool has_quad = false; + bool has_ngon = false; bool has_cut = false; BLI_assert((bm->elem_index_dirty & BM_VERT) == 0); @@ -589,9 +603,8 @@ static bool bm_decim_triangulate_begin(BMesh *bm, int *r_edges_tri_tot) faces_double = next; } - BLI_memarena_free(pf_arena); - if (has_ngon) { + BLI_memarena_free(pf_arena); BLI_heap_free(pf_heap, NULL); BLI_edgehash_free(pf_ehash, NULL); } @@ -618,6 +631,8 @@ static void bm_decim_triangulate_end(BMesh *bm, const int edges_tri_tot) BMEdge **edges_tri = MEM_mallocN(MIN2(edges_tri_tot, bm->totedge) * sizeof(*edges_tri), __func__); STACK_DECLARE(edges_tri); + STACK_INIT(edges_tri, MIN2(edges_tri_tot, bm->totedge)); + /* boundary edges */ BM_ITER_MESH (e, &iter, bm, BM_EDGES_OF_MESH) { BMLoop *l_a, *l_b; @@ -1155,7 +1170,7 @@ static bool bm_decim_edge_collapse( return false; } - bm_decim_calc_target_co(e, optimize_co, vquadrics); + bm_decim_calc_target_co_fl(e, optimize_co, vquadrics); /* check if this would result in an overlapping face */ if (UNLIKELY(bm_edge_collapse_is_degenerate_flip(e, optimize_co))) { @@ -1277,7 +1292,8 @@ static bool bm_decim_edge_collapse( * \param factor face count multiplier [0 - 1] * \param vweights Optional array of vertex aligned weights [0 - 1], * a vertex group is the usual source for this. - * \param axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_axis: Axis of symmetry, -1 to disable mirror decimate. + * \param symmetry_eps: Threshold when matching mirror verts. */ void BM_mesh_decimate_collapse( BMesh *bm, @@ -1426,7 +1442,7 @@ void BM_mesh_decimate_collapse( goto invalidate; } - bm_decim_calc_target_co(e, optimize_co, vquadrics); + bm_decim_calc_target_co_fl(e, optimize_co, vquadrics); if (e_index_mirr == e_index) { optimize_co[symmetry_axis] = 0.0f; diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c index ad35d57f35b..978cceee37c 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c +++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c @@ -335,7 +335,7 @@ void BM_mesh_decimate_dissolve_ex( /* update normal */ BM_face_normal_update(f_new); if (oflag_out) { - BMO_elem_flag_enable(bm, f_new, oflag_out); + BMO_face_flag_enable(bm, f_new, oflag_out); } /* re-calculate costs */ diff --git a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c index db60b3e15e1..0fc571bc0a8 100644 --- a/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c +++ b/source/blender/bmesh/tools/bmesh_decimate_unsubdivide.c @@ -213,7 +213,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (BM_elem_flag_test(v, BM_ELEM_TAG) && bm_vert_dissolve_fan_test(v)) { #ifdef USE_WALKER - BMO_elem_flag_enable(bm, v, ELE_VERT_TAG); + BMO_vert_flag_enable(bm, v, ELE_VERT_TAG); #endif BM_elem_index_set(v, VERT_INDEX_INIT); /* set_dirty! */ } @@ -238,7 +238,7 @@ void BM_mesh_decimate_unsubdivide_ex(BMesh *bm, const int iterations, const bool BM_ITER_MESH (v, &iter, bm, BM_VERTS_OF_MESH) { if (v->e && (BM_elem_index_get(v) == VERT_INDEX_INIT)) { #ifdef USE_WALKER - if (BMO_elem_flag_test(bm, v, ELE_VERT_TAG)) + if (BMO_vert_flag_test(bm, v, ELE_VERT_TAG)) #endif { /* check again incase the topology changed */ diff --git a/source/blender/bmesh/tools/bmesh_intersect.c b/source/blender/bmesh/tools/bmesh_intersect.c index 9d1f7fa45d2..58234ddf3bd 100644 --- a/source/blender/bmesh/tools/bmesh_intersect.c +++ b/source/blender/bmesh/tools/bmesh_intersect.c @@ -53,6 +53,8 @@ #include "BLI_buffer.h" #include "bmesh.h" +#include "intern/bmesh_private.h" + #include "bmesh_intersect.h" /* own include */ #include "tools/bmesh_edgesplit.h" @@ -535,8 +537,6 @@ static void bm_isect_tri_tri( const float *f_b_cos[3] = {UNPACK3_EX(, fv_b, ->co)}; float f_a_nor[3]; float f_b_nor[3]; - int a_mask = 0; - int b_mask = 0; unsigned int i; @@ -556,6 +556,22 @@ static void bm_isect_tri_tri( STACK_INIT(iv_ls_a, ARRAY_SIZE(iv_ls_a)); STACK_INIT(iv_ls_b, ARRAY_SIZE(iv_ls_b)); +#define VERT_VISIT_A _FLAG_WALK +#define VERT_VISIT_B _FLAG_WALK_ALT + +#define STACK_PUSH_TEST_A(ele) \ + if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_A) == 0) { \ + BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_A); \ + STACK_PUSH(iv_ls_a, ele); \ + } ((void)0) + +#define STACK_PUSH_TEST_B(ele) \ + if (BM_ELEM_API_FLAG_TEST(ele, VERT_VISIT_B) == 0) { \ + BM_ELEM_API_FLAG_ENABLE(ele, VERT_VISIT_B); \ + STACK_PUSH(iv_ls_b, ele); \ + } ((void)0) + + /* vert-vert * --------- */ { @@ -567,22 +583,18 @@ static void bm_isect_tri_tri( unsigned int i_b; for (i_b = 0; i_b < 3; i_b++) { if (len_squared_v3v3(fv_a[i_a]->co, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - if (!((1 << i_a) & a_mask)) { - STACK_PUSH(iv_ls_a, fv_a[i_a]); - a_mask |= (1 << i_a); #ifdef USE_DUMP + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT) == 0) { printf(" ('VERT-VERT-A') %d, %d),\n", i_a, BM_elem_index_get(fv_a[i_a])); -#endif } - if (!((1 << i_b) & b_mask)) { - STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); -#ifdef USE_DUMP + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT) == 0) { printf(" ('VERT-VERT-B') %d, %d),\n", i_b, BM_elem_index_get(fv_b[i_b])); -#endif } +#endif + STACK_PUSH_TEST_A(fv_a[i_a]); + STACK_PUSH_TEST_B(fv_b[i_b]); } } } @@ -593,22 +605,25 @@ static void bm_isect_tri_tri( { unsigned int i_a; for (i_a = 0; i_a < 3; i_a++) { - if (!((1 << i_a) & a_mask)) { + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A) == 0) { unsigned int i_b_e0; for (i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) { unsigned int i_b_e1 = (i_b_e0 + 1) % 3; - float fac; - if (((1 << i_b_e0) | (1 << i_b_e1)) & b_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) || + BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) + { continue; - fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co); + } + + const float fac = line_point_factor_v3(fv_a[i_a]->co, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co); if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) { float ix[3]; interp_v3_v3v3(ix, fv_b[i_b_e0]->co, fv_b[i_b_e1]->co, fac); if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_b, fv_a[i_a]); - // STACK_PUSH(iv_ls_a, fv_a[i_a]); - a_mask |= (1 << i_a); + STACK_PUSH_TEST_B(fv_a[i_a]); + // STACK_PUSH_TEST_A(fv_a[i_a]); e = BM_edge_exists(fv_b[i_b_e0], fv_b[i_b_e1]); #ifdef USE_DUMP printf(" ('VERT-EDGE-A', %d, %d),\n", @@ -631,22 +646,25 @@ static void bm_isect_tri_tri( { unsigned int i_b; for (i_b = 0; i_b < 3; i_b++) { - if (!((1 << i_b) & b_mask)) { + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B) == 0) { unsigned int i_a_e0; for (i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) { unsigned int i_a_e1 = (i_a_e0 + 1) % 3; - float fac; - if (((1 << i_a_e0) | (1 << i_a_e1)) & a_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) || + BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) + { continue; - fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co); + } + + const float fac = line_point_factor_v3(fv_b[i_b]->co, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co); if ((fac > 0.0f - s->epsilon.eps) && (fac < 1.0f + s->epsilon.eps)) { float ix[3]; interp_v3_v3v3(ix, fv_a[i_a_e0]->co, fv_a[i_a_e1]->co, fac); if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { BMEdge *e; - STACK_PUSH(iv_ls_a, fv_b[i_b]); - // STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); + STACK_PUSH_TEST_A(fv_b[i_b]); + // STACK_PUSH_NOTEST(iv_ls_b, fv_b[i_b]); e = BM_edge_exists(fv_a[i_a_e0], fv_a[i_a_e1]); #ifdef USE_DUMP printf(" ('VERT-EDGE-B', %d, %d),\n", @@ -680,17 +698,15 @@ static void bm_isect_tri_tri( // second check for verts intersecting the triangle for (i_a = 0; i_a < 3; i_a++) { - float ix[3]; - if ((1 << i_a) & a_mask) + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a], VERT_VISIT_A)) { continue; + } + + float ix[3]; if (isect_point_tri_v3(fv_a[i_a]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_a[i_a]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex(iv_ls_a, STACK_SIZE(iv_ls_a), fv_a[i_a]) == -1); - BLI_assert(BLI_array_findindex(iv_ls_b, STACK_SIZE(iv_ls_b), fv_a[i_a]) == -1); - - STACK_PUSH(iv_ls_a, fv_a[i_a]); - STACK_PUSH(iv_ls_b, fv_a[i_a]); - a_mask |= (1 << i_a); + STACK_PUSH_TEST_A(fv_a[i_a]); + STACK_PUSH_TEST_B(fv_a[i_a]); #ifdef USE_DUMP printf(" 'VERT TRI-A',\n"); #endif @@ -709,18 +725,15 @@ static void bm_isect_tri_tri( tri_v3_scale(UNPACK3(t_scale), 1.0f - s->epsilon.eps2x); for (i_b = 0; i_b < 3; i_b++) { - float ix[3]; - if ((1 << i_b) & b_mask) + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b], VERT_VISIT_B)) { continue; + } + float ix[3]; if (isect_point_tri_v3(fv_b[i_b]->co, UNPACK3(t_scale), ix)) { if (len_squared_v3v3(ix, fv_b[i_b]->co) <= s->epsilon.eps2x_sq) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), fv_b[i_b]) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), fv_b[i_b]) == -1); - - STACK_PUSH(iv_ls_a, fv_b[i_b]); - STACK_PUSH(iv_ls_b, fv_b[i_b]); - b_mask |= (1 << i_b); + STACK_PUSH_TEST_A(fv_b[i_b]); + STACK_PUSH_TEST_B(fv_b[i_b]); #ifdef USE_DUMP printf(" 'VERT TRI-B',\n"); #endif @@ -735,7 +748,7 @@ static void bm_isect_tri_tri( #ifdef USE_DUMP printf("# OVERLAP\n"); #endif - return; + goto finally; } normal_tri_v3(f_a_nor, UNPACK3(f_a_cos)); @@ -744,37 +757,42 @@ static void bm_isect_tri_tri( /* edge-tri & edge-edge * -------------------- */ { - unsigned int i_e0; - for (i_e0 = 0; i_e0 < 3; i_e0++) { - unsigned int i_e1 = (i_e0 + 1) % 3; + for (unsigned int i_a_e0 = 0; i_a_e0 < 3; i_a_e0++) { + unsigned int i_a_e1 = (i_a_e0 + 1) % 3; enum ISectType side; BMVert *iv; - if (((1 << i_e0) | (1 << i_e1)) & a_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_a[i_a_e0], VERT_VISIT_A) || + BM_ELEM_API_FLAG_TEST(fv_a[i_a_e1], VERT_VISIT_A)) + { continue; - iv = bm_isect_edge_tri(s, fv_a[i_e0], fv_a[i_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); + } + + iv = bm_isect_edge_tri(s, fv_a[i_a_e0], fv_a[i_a_e1], fv_b, b_index, f_b_cos, f_b_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST_A(iv); + STACK_PUSH_TEST_B(iv); #ifdef USE_DUMP printf(" ('EDGE-TRI-A', %d),\n", side); #endif } } - for (i_e0 = 0; i_e0 < 3; i_e0++) { - unsigned int i_e1 = (i_e0 + 1) % 3; + for (unsigned int i_b_e0 = 0; i_b_e0 < 3; i_b_e0++) { + unsigned int i_b_e1 = (i_b_e0 + 1) % 3; enum ISectType side; BMVert *iv; - if (((1 << i_e0) | (1 << i_e1)) & b_mask) + + if (BM_ELEM_API_FLAG_TEST(fv_b[i_b_e0], VERT_VISIT_B) || + BM_ELEM_API_FLAG_TEST(fv_b[i_b_e1], VERT_VISIT_B)) + { continue; - iv = bm_isect_edge_tri(s, fv_b[i_e0], fv_b[i_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); + } + + iv = bm_isect_edge_tri(s, fv_b[i_b_e0], fv_b[i_b_e1], fv_a, a_index, f_a_cos, f_a_nor, &side); if (iv) { - BLI_assert(BLI_array_findindex((void **)iv_ls_a, STACK_SIZE(iv_ls_a), iv) == -1); - BLI_assert(BLI_array_findindex((void **)iv_ls_b, STACK_SIZE(iv_ls_b), iv) == -1); - STACK_PUSH(iv_ls_a, iv); - STACK_PUSH(iv_ls_b, iv); + STACK_PUSH_TEST_A(iv); + STACK_PUSH_TEST_B(iv); #ifdef USE_DUMP printf(" ('EDGE-TRI-B', %d),\n", side); #endif @@ -827,6 +845,15 @@ static void bm_isect_tri_tri( // BLI_assert(len(ie_vs) <= 2) } } + +finally: + for (i = 0; i < STACK_SIZE(iv_ls_a); i++) { + BM_ELEM_API_FLAG_DISABLE(iv_ls_a[i], VERT_VISIT_A); \ + } + for (i = 0; i < STACK_SIZE(iv_ls_b); i++) { + BM_ELEM_API_FLAG_DISABLE(iv_ls_b[i], VERT_VISIT_B); \ + } + } #ifdef USE_BVH diff --git a/source/blender/collada/DocumentImporter.cpp b/source/blender/collada/DocumentImporter.cpp index 3a709da78e1..226f319cefd 100644 --- a/source/blender/collada/DocumentImporter.cpp +++ b/source/blender/collada/DocumentImporter.cpp @@ -416,7 +416,7 @@ Object *DocumentImporter::create_instance_node(Object *source_ob, COLLADAFW::Nod { fprintf(stderr, "create <instance_node> under node id=%s from node id=%s\n", instance_node ? instance_node->getOriginalId().c_str() : NULL, source_node ? source_node->getOriginalId().c_str() : NULL); - Object *obn = BKE_object_copy(source_ob); + Object *obn = BKE_object_copy(G.main, source_ob); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); BKE_scene_base_add(sce, obn); @@ -904,6 +904,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia i++; } } + // EMISSION // color if (ef->getEmission().isColor()) { @@ -919,8 +920,22 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia i++; } } - - if (ef->getOpacity().isTexture()) { + + // TRANSPARENT + // color + if (ef->getOpacity().isColor()) { + col = ef->getTransparent().getColor(); + float alpha = ef->getTransparency().getFloatValue(); + if (col.isValid()) { + alpha *= col.getAlpha(); // Assuming A_ONE opaque mode + } + if (col.isValid() || alpha < 1.0) { + ma->alpha = alpha; + ma->mode |= MA_ZTRANSP | MA_TRANSP; + } + } + // texture + else if (ef->getOpacity().isTexture()) { COLLADAFW::Texture ctex = ef->getOpacity().getTexture(); mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); if (mtex != NULL) { @@ -930,22 +945,7 @@ void DocumentImporter::write_profile_COMMON(COLLADAFW::EffectCommon *ef, Materia ma->mode |= MA_ZTRANSP | MA_TRANSP; } } - // TRANSPARENT - // color -#if 0 - if (ef->getOpacity().isColor()) { - // XXX don't know what to do here - } - // texture - else if (ef->getOpacity().isTexture()) { - ctex = ef->getOpacity().getTexture(); - if (mtex != NULL) mtex->mapto &= MAP_ALPHA; - else { - mtex = create_texture(ef, ctex, ma, i, texindex_texarray_map); - if (mtex != NULL) mtex->mapto = MAP_ALPHA; - } - } -#endif + material_texture_mapping_map[ma] = texindex_texarray_map; } diff --git a/source/blender/collada/EffectExporter.cpp b/source/blender/collada/EffectExporter.cpp index 13dc1eda580..76b51148509 100644 --- a/source/blender/collada/EffectExporter.cpp +++ b/source/blender/collada/EffectExporter.cpp @@ -30,6 +30,7 @@ #include <set> #include "COLLADASWEffectProfile.h" +#include "COLLADAFWColorOrTexture.h" #include "EffectExporter.h" #include "DocumentExporter.h" @@ -217,9 +218,9 @@ void EffectsExporter::operator()(Material *ma, Object *ob) // transparency if (ma->mode & MA_TRANSP) { // Tod: because we are in A_ONE mode transparency is calculated like this: - ep.setTransparency(ma->alpha, false, "transparency"); - // cot = getcol(1.0f, 1.0f, 1.0f, 1.0f); - // ep.setTransparent(cot); + cot = getcol(1.0f, 1.0f, 1.0f, ma->alpha); + ep.setTransparent(cot); + ep.setOpaque(COLLADASW::EffectProfile::A_ONE); } // emission diff --git a/source/blender/collada/ErrorHandler.cpp b/source/blender/collada/ErrorHandler.cpp index b271604f839..98aa85f8a9b 100644 --- a/source/blender/collada/ErrorHandler.cpp +++ b/source/blender/collada/ErrorHandler.cpp @@ -79,7 +79,7 @@ bool ErrorHandler::handleError(const COLLADASaxFWL::IError *error) COLLADASaxFWL::SaxFWLError *saxFWLError = (COLLADASaxFWL::SaxFWLError *) error; /* * Accept non critical errors as warnings (i.e. texture not found) - * This makes the importer more gracefull, so it now imports what makes sense. + * This makes the importer more graceful, so it now imports what makes sense. */ if (saxFWLError->getSeverity() == COLLADASaxFWL::IError::SEVERITY_ERROR_NONCRITICAL) { isError = false; diff --git a/source/blender/collada/MeshImporter.cpp b/source/blender/collada/MeshImporter.cpp index 6085b66a8b8..6ff6de33d56 100644 --- a/source/blender/collada/MeshImporter.cpp +++ b/source/blender/collada/MeshImporter.cpp @@ -172,8 +172,7 @@ void UVDataWrapper::getUV(int uv_index, float *uv) } } -VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata){ -} +VCOLDataWrapper::VCOLDataWrapper(COLLADAFW::MeshVertexData& vdata) : mVData(&vdata) {} void VCOLDataWrapper::get_vcol(int v_index, MLoopCol *mloopcol) { diff --git a/source/blender/collada/collada_utils.cpp b/source/blender/collada/collada_utils.cpp index f0984fbc127..abe5130b9c1 100644 --- a/source/blender/collada/collada_utils.cpp +++ b/source/blender/collada/collada_utils.cpp @@ -357,8 +357,11 @@ void bc_triangulate_mesh(Mesh *me) bool use_beauty = false; bool tag_only = false; int quad_method = MOD_TRIANGULATE_QUAD_SHORTEDGE; /* XXX: The triangulation method selection could be offered in the UI */ - - BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default); + + const struct BMeshCreateParams bm_create_params = {0}; + BMesh *bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &bm_create_params); BMeshFromMeshParams bm_from_me_params = {0}; bm_from_me_params.calc_face_normal = true; BM_mesh_bm_from_me(bm, me, &bm_from_me_params); @@ -370,8 +373,8 @@ void bc_triangulate_mesh(Mesh *me) } /* -* A bone is a leaf when it has no children or all children are not connected. -*/ + * A bone is a leaf when it has no children or all children are not connected. + */ bool bc_is_leaf_bone(Bone *bone) { for (Bone *child = (Bone *)bone->childbase.first; child; child = child->next) { @@ -410,10 +413,10 @@ int bc_set_layer(int bitfield, int layer, bool enable) } /** -* BoneExtended is a helper class needed for the Bone chain finder -* See ArmatureImporter::fix_leaf_bones() -* and ArmatureImporter::connect_bone_chains() -**/ + * BoneExtended is a helper class needed for the Bone chain finder + * See ArmatureImporter::fix_leaf_bones() + * and ArmatureImporter::connect_bone_chains() + */ BoneExtended::BoneExtended(EditBone *aBone) { @@ -536,8 +539,8 @@ void BoneExtended::set_bone_layers(std::string layerString, std::vector<std::str } /* If numeric layers and labeled layers are used in parallel (unlikely), - we get a potential mixup. Just leave as is for now. - */ + * we get a potential mixup. Just leave as is for now. + */ this->bone_layers = bc_set_layer(this->bone_layers, pos); } diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index a513954ee0d..ad40b4851fb 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -95,9 +95,9 @@ public: void execute(WorkPackage *work); /** - * @brief determine an image format - * @param memorybuffer - */ + * @brief determine an image format + * @param memorybuffer + */ static const cl_image_format *determineImageFormat(MemoryBuffer *memoryBuffer); cl_context getContext() { return this->m_context; } diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cpp index e5b9f58ee93..39147f3ab84 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cpp @@ -187,7 +187,7 @@ void WorkScheduler::schedule(ExecutionGroup *group, int chunkNumber) { WorkPackage *package = new WorkPackage(group, chunkNumber); #if COM_CURRENT_THREADING_MODEL == COM_TM_NOTHREAD - CPUDevice device; + CPUDevice device(0); device.execute(package); delete package; #elif COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE @@ -277,6 +277,7 @@ bool WorkScheduler::hasGPUDevices() #endif } +#if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE static void CL_CALLBACK clContextError(const char *errinfo, const void * /*private_info*/, size_t /*cb*/, @@ -284,6 +285,7 @@ static void CL_CALLBACK clContextError(const char *errinfo, { printf("OPENCL error: %s\n", errinfo); } +#endif void WorkScheduler::initialize(bool use_opencl, int num_cpu_threads) { diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cpp index 220b4e908a6..caafdfe8f0c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ b/source/blender/compositor/operations/COM_MaskOperation.cpp @@ -1,5 +1,4 @@ /* - * Copyright 2012, Blender Foundation. * * This program is free software; you can redistribute it and/or @@ -94,7 +93,7 @@ void MaskOperation::initExecution() frame_iter += frame_step; } - BKE_mask_free_nolib(mask_temp); + BKE_mask_free(mask_temp); MEM_freeN(mask_temp); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder.cc b/source/blender/depsgraph/intern/builder/deg_builder.cc index b6c3d56eac0..7ca2ef05a36 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/build/deg_builder.cc +/** \file blender/depsgraph/intern/builder/deg_builder.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder.h b/source/blender/depsgraph/intern/builder/deg_builder.h index 6b02ccfcf6f..43167cc6acb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder.h +++ b/source/blender/depsgraph/intern/builder/deg_builder.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/build/deg_builder.h +/** \file blender/depsgraph/intern/builder/deg_builder.h * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index c383cae7ba7..9c0f88a8042 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_build_nodes.cc +/** \file blender/depsgraph/intern/builder/deg_builder_nodes.cc * \ingroup depsgraph * * Methods for constructing depsgraph's nodes @@ -331,15 +331,16 @@ void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; + /* object itself */ + build_object(bmain, scene, base, ob); + /* object that this is a proxy for */ // XXX: the way that proxies work needs to be completely reviewed! if (ob->proxy) { ob->proxy->proxy_from = ob; + build_object(bmain, scene, base, ob->proxy); } - /* object itself */ - build_object(bmain, scene, base, ob); - /* Object dupligroup. */ if (ob->dup_group) { build_group(bmain, scene, base, ob->dup_group); @@ -433,12 +434,12 @@ void DepsgraphNodeBuilder::build_object(Main *bmain, Scene *scene, Base *base, O { if (ob->id.tag & LIB_TAG_DOIT) { IDDepsNode *id_node = m_graph->find_id_node(&ob->id); - id_node->layers = base->lay; + id_node->layers |= base->lay; return; } IDDepsNode *id_node = add_id_node(&ob->id); - id_node->layers = base->lay; + id_node->layers |= base->lay; ob->customdata_mask = 0; /* standard components */ @@ -477,7 +478,7 @@ void DepsgraphNodeBuilder::build_object(Main *bmain, Scene *scene, Base *base, O } case OB_ARMATURE: /* Pose */ - if (ob->id.lib != NULL && ob->proxy_from != NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { build_proxy_rig(ob); } else { @@ -524,12 +525,6 @@ void DepsgraphNodeBuilder::build_object(Main *bmain, Scene *scene, Base *base, O if (ob->gpd) { build_gpencil(ob->gpd); } - - if (ob->proxy != NULL) { - add_operation_node(&ob->id, DEPSNODE_TYPE_PROXY, DEPSOP_TYPE_POST, - function_bind(BKE_object_eval_proxy_backlink, _1, ob), - DEG_OPCODE_PLACEHOLDER, "Parameters Eval"); - } } void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob) @@ -1024,11 +1019,6 @@ void DepsgraphNodeBuilder::build_obdata_geom(Main *bmain, Scene *scene, Object * // TODO: "Done" operation - /* ShapeKeys */ - Key *key = BKE_key_from_object(ob); - if (key) - build_shapekeys(key); - /* Modifiers */ if (ob->modifiers.first) { ModifierData *md; @@ -1072,6 +1062,12 @@ void DepsgraphNodeBuilder::build_obdata_geom(Main *bmain, Scene *scene, Object * return; } + /* ShapeKeys */ + Key *key = BKE_key_from_object(ob); + if (key) { + build_shapekeys(key); + } + build_animdata(obdata); /* nodes for result of obdata's evaluation, and geometry evaluation on object */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc index 0e78df52ff8..f870a33fb68 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_pchanmap.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.h +/** \file blender/depsgraph/intern/builder/deg_builder_pchanmap.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc index 16a708f31d5..17d36c9645d 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.cc @@ -349,18 +349,12 @@ void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene) for (Base *base = (Base *)scene->base.first; base; base = base->next) { Object *ob = base->object; - /* Object that this is a proxy for. - * Just makes sure backlink is correct. - */ - if (ob->proxy) { - ob->proxy->proxy_from = ob; - } - /* object itself */ build_object(bmain, scene, ob); /* object that this is a proxy for */ if (ob->proxy) { + ob->proxy->proxy_from = ob; build_object(bmain, scene, ob->proxy); /* TODO(sergey): This is an inverted relation, matches old depsgraph * behavior and need to be investigated if it still need to be inverted. @@ -524,7 +518,7 @@ void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *o } case OB_ARMATURE: /* Pose */ - if (ob->id.lib != NULL && ob->proxy_from != NULL) { + if (ID_IS_LINKED_DATABLOCK(ob) && ob->proxy_from != NULL) { build_proxy_rig(ob); } else { @@ -1010,6 +1004,12 @@ void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu) } } else { + if (dtar->id == id) { + /* Ignore input dependency if we're driving properties of the same ID, + * otherwise we'll be ending up in a cyclic dependency here. + */ + continue; + } /* resolve path to get node */ RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : ""); add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]"); @@ -1159,7 +1159,7 @@ void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob) OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name); /* XXX: if particle system is later re-enabled, we must do full rebuild? */ - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; /* TODO(sergey): Are all particle systems depends on time? @@ -1398,7 +1398,8 @@ void DepsgraphRelationBuilder::build_ik_pose(Object *ob, OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result"); - } else { + } + else { OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE); add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result"); } @@ -1515,20 +1516,20 @@ void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob) } /* IK Solvers... - * - These require separate processing steps are pose-level - * to be executed between chains of bones (i.e. once the - * base transforms of a bunch of bones is done) - * - * - We build relations for these before the dependencies - * between ops in the same component as it is necessary - * to check whether such bones are in the same IK chain - * (or else we get weird issues with either in-chain - * references, or with bones being parented to IK'd bones) - * - * Unsolved Issues: - * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building - * - Animated chain-lengths are a problem... - */ + * - These require separate processing steps are pose-level + * to be executed between chains of bones (i.e. once the + * base transforms of a bunch of bones is done) + * + * - We build relations for these before the dependencies + * between ops in the same component as it is necessary + * to check whether such bones are in the same IK chain + * (or else we get weird issues with either in-chain + * references, or with bones being parented to IK'd bones) + * + * Unsolved Issues: + * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building + * - Animated chain-lengths are a problem... + */ RootPChanMap root_map; bool pose_depends_on_local_transform = false; for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) { diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index dc8d1a3d9c0..8a03d552dae 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -42,7 +42,6 @@ #include "BLI_utildefines.h" #include "BLI_string.h" -#include "intern/depsgraph_types.h" #include "intern/nodes/deg_node.h" #include "intern/nodes/deg_node_operation.h" @@ -274,7 +273,8 @@ private: /* Utilities for Builders ----------------------------------------------------- */ template <typename KeyType> -OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) { +OperationDepsNode *DepsgraphRelationBuilder::find_operation_node(const KeyType& key) +{ DepsNode *node = find_node(key); return node != NULL ? node->get_exit_operation() : NULL; } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc index 0322ef7fa1d..76cd81f1b8f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_transitive.cc @@ -99,7 +99,7 @@ void deg_graph_transitive_reduction(Depsgraph *graph) /* Remove redundant paths to the target. */ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin(); it_rel != target->inlinks.end(); - ) + ) { DepsRelation *rel = *it_rel; /* Increment in advance, so we can safely remove the relation. */ diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc index 97208939e57..4ce91516c84 100644 --- a/source/blender/depsgraph/intern/depsgraph_type_defines.cc +++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc @@ -136,13 +136,15 @@ static const char *stringify_opcode(eDepsOperation_Code opcode) return "UNKNOWN"; } -DepsOperationStringifier::DepsOperationStringifier() { +DepsOperationStringifier::DepsOperationStringifier() +{ for (int i = 0; i < DEG_NUM_OPCODES; ++i) { names_[i] = stringify_opcode((eDepsOperation_Code)i); } } -const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) { +const char *DepsOperationStringifier::operator[](eDepsOperation_Code opcode) +{ BLI_assert((opcode > 0) && (opcode < DEG_NUM_OPCODES)); if (opcode >= 0 && opcode < DEG_NUM_OPCODES) { return names_[opcode]; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index 198cd349002..3024d625846 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_eval.cc +/** \file blender/depsgraph/intern/eval/deg_eval.cc * \ingroup depsgraph * * Evaluation engine entrypoints for Depsgraph Engine. diff --git a/source/blender/depsgraph/intern/eval/deg_eval.h b/source/blender/depsgraph/intern/eval/deg_eval.h index 0d42f63433f..92f87b03803 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.h +++ b/source/blender/depsgraph/intern/eval/deg_eval.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/eval/deg_eval.cc +/** \file blender/depsgraph/intern/eval/deg_eval.h * \ingroup depsgraph * * Evaluation engine entrypoints for Depsgraph Engine. diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc index fda665b0db4..f9e1504b3ce 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsgraph_tag.cc +/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc * \ingroup depsgraph * * Core routines for how the Depsgraph works. @@ -85,9 +85,6 @@ static void flush_init_func(void *data_v, int i) id_node->done = 0; comp_node->done = 0; node->scheduled = false; - if (comp_node->type == DEPSNODE_TYPE_PROXY) { - node->flag |= DEPSOP_FLAG_NEEDS_UPDATE; - } } /* Flush updates from tagged nodes outwards until all affected nodes diff --git a/source/blender/depsgraph/intern/eval/deg_eval_flush.h b/source/blender/depsgraph/intern/eval/deg_eval_flush.h index 8912aebee7d..ecd3a5ec660 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_flush.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_flush.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/eval/deg_eval_flush.cc +/** \file blender/depsgraph/intern/eval/deg_eval_flush.h * \ingroup depsgraph * * Core routines for how the Depsgraph works. diff --git a/source/blender/depsgraph/intern/nodes/deg_node.cc b/source/blender/depsgraph/intern/nodes/deg_node.cc index 78293f7f483..db807d22b89 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode.cc +/** \file blender/depsgraph/intern/nodes/deg_node.cc * \ingroup depsgraph */ @@ -181,6 +181,11 @@ void IDDepsNode::init(const ID *id, const string &UNUSED(subdata)) this->layers = (1 << 20) - 1; this->eval_flags = 0; + /* For object we initialize layers to layer from base. */ + if (GS(id) == ID_OB) { + this->layers = 0; + } + components = BLI_ghash_new(id_deps_node_hash_key, id_deps_node_hash_key_cmp, "Depsgraph id components hash"); diff --git a/source/blender/depsgraph/intern/nodes/deg_node.h b/source/blender/depsgraph/intern/nodes/deg_node.h index d79d3d2348d..416996052c9 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node.h +++ b/source/blender/depsgraph/intern/nodes/deg_node.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode.h +/** \file depsgraph/intern/nodes/deg_node.h * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.cc b/source/blender/depsgraph/intern/nodes/deg_node_component.cc index 8e74317cfa2..6ac45c99798 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_component.cc +/** \file blender/depsgraph/intern/nodes/deg_node_component.cc * \ingroup depsgraph */ @@ -116,10 +116,10 @@ string ComponentDepsNode::identifier() const { string &idname = this->owner->name; - char typebuf[7]; + char typebuf[16]; sprintf(typebuf, "(%d)", type); - char layers[7]; + char layers[16]; sprintf(layers, "%d", this->layers); return string(typebuf) + name + " : " + idname + " (Layers: " + layers + ")"; @@ -256,7 +256,7 @@ OperationDepsNode *ComponentDepsNode::get_entry_operation() entry_operation = op_node; return op_node; } - else if(operations.size() == 1) { + else if (operations.size() == 1) { return operations[0]; } return NULL; @@ -279,7 +279,7 @@ OperationDepsNode *ComponentDepsNode::get_exit_operation() exit_operation = op_node; return op_node; } - else if(operations.size() == 1) { + else if (operations.size() == 1) { return operations[0]; } return NULL; diff --git a/source/blender/depsgraph/intern/nodes/deg_node_component.h b/source/blender/depsgraph/intern/nodes/deg_node_component.h index 6ff4345d28b..6f62d91cd79 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_component.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_component.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_component.h +/** \file blender/depsgraph/intern/nodes/deg_node_component.h * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc index a9f9703bb3b..5847af29ac2 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.cc +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.cc @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_operation.cc +/** \file blender/depsgraph/intern/nodes/deg_node_operation.cc * \ingroup depsgraph */ diff --git a/source/blender/depsgraph/intern/nodes/deg_node_operation.h b/source/blender/depsgraph/intern/nodes/deg_node_operation.h index f03078fc3db..598393054db 100644 --- a/source/blender/depsgraph/intern/nodes/deg_node_operation.h +++ b/source/blender/depsgraph/intern/nodes/deg_node_operation.h @@ -24,7 +24,7 @@ * ***** END GPL LICENSE BLOCK ***** */ -/** \file blender/depsgraph/intern/depsnode_operation.h +/** \file blender/depsgraph/intern/nodes/deg_node_operation.h * \ingroup depsgraph */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 8822c8511de..af9b0a176f5 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -2119,7 +2119,7 @@ static int animchannels_clean_empty_exec(bContext *C, wmOperator *UNUSED(op)) /* remove AnimData? */ if (action_empty && nla_empty && drivers_empty) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); } } @@ -2356,7 +2356,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec } else { ymin = 0.0f; - ymax = (float)(-ACHANNEL_HEIGHT); + ymax = (float)(-ACHANNEL_HEIGHT(ac)); } /* convert border-region to view coordinates */ @@ -2372,7 +2372,7 @@ static void borderselect_anim_channels(bAnimContext *ac, rcti *rect, short selec if (ac->datatype == ANIMCONT_NLA) ymin = ymax - NLACHANNEL_STEP(snla); else - ymin = ymax - ACHANNEL_STEP; + ymin = ymax - ACHANNEL_STEP(ac); /* if channel is within border-select region, alter it */ if (!((ymax < rectf.ymin) || (ymin > rectf.ymax))) { @@ -2573,7 +2573,7 @@ static int animchannels_channel_get(bAnimContext *ac, const int mval[2]) UI_view2d_listview_view_to_cell(v2d, NLACHANNEL_NAMEWIDTH, NLACHANNEL_STEP(snla), 0, (float)NLACHANNEL_HEIGHT_HALF(snla), x, y, NULL, &channel_index); } else { - UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); + UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); } return channel_index; @@ -2705,6 +2705,10 @@ static int mouse_anim_channels(bContext *C, bAnimContext *ac, int channel_index, if ((adt) && (adt->flag & ADT_UI_SELECTED)) adt->flag |= ADT_UI_ACTIVE; + /* ensure we exit editmode on whatever object was active before to avoid getting stuck there - T48747 */ + if (ob != sce->obedit) + ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); + notifierFlags |= (ND_ANIMCHAN | NA_SELECTED); break; } @@ -2988,7 +2992,7 @@ static int animchannels_mouseclick_invoke(bContext *C, wmOperator *op, const wmE * ACHANNEL_HEIGHT_HALF. */ UI_view2d_region_to_view(v2d, event->mval[0], event->mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); + UI_view2d_listview_view_to_cell(v2d, ACHANNEL_NAMEWIDTH, ACHANNEL_STEP(&ac), 0, (float)ACHANNEL_HEIGHT_HALF(&ac), x, y, NULL, &channel_index); /* handle mouse-click in the relevant channel then */ notifierFlags = mouse_anim_channels(C, &ac, channel_index, selectmode); diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index 86d963da579..0d1a13fa95d 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -71,6 +71,7 @@ #include "DNA_world_types.h" #include "DNA_gpencil_types.h" #include "DNA_object_types.h" +#include "DNA_userdef_types.h" #include "MEM_guardedalloc.h" @@ -97,9 +98,30 @@ #include "ED_anim_api.h" #include "ED_markers.h" +#include "UI_resources.h" /* for TH_KEYFRAME_SCALE lookup */ + /* ************************************************************ */ /* Blender Context <-> Animation Context mapping */ +/* ----------- Private Stuff - General -------------------- */ + +/* Get vertical scaling factor (i.e. typically used for keyframe size) */ +static void animedit_get_yscale_factor(bAnimContext *ac) +{ + bTheme *btheme = UI_GetTheme(); + + /* grab scale factor directly from action editor setting + * NOTE: This theme setting doesn't have an ID, as it cannot be accessed normally + * since it is a float, and the theem settings methods can only handle chars. + */ + ac->yscale_fac = btheme->tact.keyframe_scale_fac; + + /* clamp to avoid problems with uninitialised values... */ + if (ac->yscale_fac < 0.1f) + ac->yscale_fac = 1.0f; + //printf("yscale_fac = %f\n", ac->yscale_fac); +} + /* ----------- Private Stuff - Action Editor ------------- */ /* Get shapekey data being edited (for Action Editor -> ShapeKey mode) */ @@ -352,6 +374,9 @@ bool ANIM_animdata_get_context(const bContext *C, bAnimContext *ac) ac->spacetype = (sa) ? sa->spacetype : 0; ac->regiontype = (ar) ? ar->regiontype : 0; + /* initialise default y-scale factor */ + animedit_get_yscale_factor(ac); + /* get data context info */ // XXX: if the below fails, try to grab this info from context instead... (to allow for scripting) return ANIM_animdata_context_getdata(ac); @@ -1255,7 +1280,7 @@ static size_t animfilter_action(bAnimContext *ac, ListBase *anim_data, bDopeShee /* don't include anything from this action if it is linked in from another file, * and we're getting stuff for editing... */ - if ((filter_mode & ANIMFILTER_FOREDIT) && (act->id.lib)) + if ((filter_mode & ANIMFILTER_FOREDIT) && ID_IS_LINKED_DATABLOCK(act)) return 0; /* do groups */ @@ -2709,11 +2734,97 @@ static size_t animdata_filter_dopesheet_scene(bAnimContext *ac, ListBase *anim_d return items; } + +/* Helper for animdata_filter_dopesheet() - For checking if an object should be included or not */ +static bool animdata_filter_base_is_ok(bDopeSheet *ads, Scene *scene, Base *base, int filter_mode) +{ + Object *ob = base->object; + + if (base->object == NULL) + return false; + + /* firstly, check if object can be included, by the following factors: + * - if only visible, must check for layer and also viewport visibility + * --> while tools may demand only visible, user setting takes priority + * as user option controls whether sets of channels get included while + * tool-flag takes into account collapsed/open channels too + * - if only selected, must check if object is selected + * - there must be animation data to edit (this is done recursively as we + * try to add the channels) + */ + if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { + /* layer visibility - we check both object and base, since these may not be in sync yet */ + if ((scene->lay & (ob->lay | base->lay)) == 0) + return false; + + /* outliner restrict-flag */ + if (ob->restrictflag & OB_RESTRICT_VIEW) + return false; + } + + /* if only F-Curves with visible flags set can be shown, check that + * datablock hasn't been set to invisible + */ + if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { + if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) + return false; + } + + /* check selection and object type filters */ + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/)) { + /* only selected should be shown */ + return false; + } + + /* check if object belongs to the filtering group if option to filter + * objects by the grouped status is on + * - used to ease the process of doing multiple-character choreographies + */ + if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { + if (BKE_group_object_exists(ads->filter_grp, ob) == 0) + return false; + } + + /* no reason to exclude this object... */ + return true; +} + +/* Helper for animdata_filter_ds_sorted_bases() - Comparison callback for two Base pointers... */ +static int ds_base_sorting_cmp(const void *base1_ptr, const void *base2_ptr) +{ + const Base *b1 = *((const Base **)base1_ptr); + const Base *b2 = *((const Base **)base2_ptr); + + return strcmp(b1->object->id.name + 2, b2->object->id.name + 2); +} + +/* Get a sorted list of all the bases - for inclusion in dopesheet (when drawing channels) */ +static Base **animdata_filter_ds_sorted_bases(bDopeSheet *ads, Scene *scene, int filter_mode, size_t *r_usable_bases) +{ + /* Create an array with space for all the bases, but only containing the usable ones */ + size_t tot_bases = BLI_listbase_count(&scene->base); + size_t num_bases = 0; + + Base **sorted_bases = MEM_mallocN(sizeof(Base *) * tot_bases, "Dopesheet Usable Sorted Bases"); + for (Base *base = scene->base.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { + sorted_bases[num_bases++] = base; + } + } + + /* Sort this list of pointers (based on the names) */ + qsort(sorted_bases, num_bases, sizeof(Base *), ds_base_sorting_cmp); + + /* Return list of sorted bases */ + *r_usable_bases = num_bases; + return sorted_bases; +} + + // TODO: implement pinning... (if and when pinning is done, what we need to do is to provide freeing mechanisms - to protect against data that was deleted) static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, bDopeSheet *ads, int filter_mode) { - Scene *sce = (Scene *)ads->source; - Base *base; + Scene *scene = (Scene *)ads->source; size_t items = 0; /* check that we do indeed have a scene */ @@ -2733,56 +2844,45 @@ static size_t animdata_filter_dopesheet(bAnimContext *ac, ListBase *anim_data, b } /* scene-linked animation - e.g. world, compositing nodes, scene anim (including sequencer currently) */ - items += animdata_filter_dopesheet_scene(ac, anim_data, ads, sce, filter_mode); - - /* loop over all bases (i.e.objects) in the scene */ - for (base = sce->base.first; base; base = base->next) { - /* check if there's an object (all the relevant checks are done in the ob-function) */ - if (base->object) { - Object *ob = base->object; - - /* firstly, check if object can be included, by the following factors: - * - if only visible, must check for layer and also viewport visibility - * --> while tools may demand only visible, user setting takes priority - * as user option controls whether sets of channels get included while - * tool-flag takes into account collapsed/open channels too - * - if only selected, must check if object is selected - * - there must be animation data to edit (this is done recursively as we - * try to add the channels) - */ - if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { - /* layer visibility - we check both object and base, since these may not be in sync yet */ - if ((sce->lay & (ob->lay | base->lay)) == 0) continue; - - /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEW) continue; - } - - /* if only F-Curves with visible flags set can be shown, check that - * datablock hasn't been set to invisible - */ - if (filter_mode & ANIMFILTER_CURVE_VISIBLE) { - if ((ob->adt) && (ob->adt->flag & ADT_CURVES_NOT_VISIBLE)) - continue; + items += animdata_filter_dopesheet_scene(ac, anim_data, ads, scene, filter_mode); + + /* If filtering for channel drawing, we want the objects in alphabetical order, + * to make it easier to predict where items are in the hierarchy + * - This order only really matters if we need to show all channels in the list (e.g. for drawing) + * (XXX: What about lingering "active" flags? The order may now become unpredictable) + * - Don't do this if this behaviour has been turned off (i.e. due to it being too slow) + * - Don't do this if there's just a single object + */ + if ((filter_mode & ANIMFILTER_LIST_CHANNELS) && !(ads->flag & ADS_FLAG_NO_DB_SORT) && + (scene->base.first != scene->base.last)) + { + /* Filter list of bases (i.e. objects), sort them, then add their contents normally... */ + // TODO: Cache the old sorted order - if the set of bases hasn't changed, don't re-sort... + Base **sorted_bases; + size_t num_bases; + + sorted_bases = animdata_filter_ds_sorted_bases(ads, scene, filter_mode, &num_bases); + if (sorted_bases) { + /* Add the necessary channels for these bases... */ + for (size_t i = 0; i < num_bases; i++) { + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, sorted_bases[i], filter_mode); } - /* check selection and object type filters */ - if ( (ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & SELECT) /*|| (base == sce->basact)*/) ) { - /* only selected should be shown */ - continue; - } + // TODO: store something to validate whether any changes are needed? - /* check if object belongs to the filtering group if option to filter - * objects by the grouped status is on - * - used to ease the process of doing multiple-character choreographies - */ - if (ads->filterflag & ADS_FILTER_ONLYOBGROUP) { - if (BKE_group_object_exists(ads->filter_grp, ob) == 0) - continue; + /* free temporary data */ + MEM_freeN(sorted_bases); + } + } + else { + /* Filter and add contents of each base (i.e. object) without them sorting first + * NOTE: This saves performance in cases where order doesn't matter + */ + for (Base *base = scene->base.first; base; base = base->next) { + if (animdata_filter_base_is_ok(ads, scene, base, filter_mode)) { + /* since we're still here, this object should be usable */ + items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); } - - /* since we're still here, this object should be usable */ - items += animdata_filter_dopesheet_ob(ac, anim_data, ads, base, filter_mode); } } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index ae6894ac546..fc6f4036d02 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -192,7 +192,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) #define HSV_BANDWIDTH 0.3f /* used to determine the color of F-Curves with FCURVE_COLOR_AUTO_RAINBOW set */ -//void fcurve_rainbow (unsigned int cur, unsigned int tot, float *out) +// void fcurve_rainbow(unsigned int cur, unsigned int tot, float *out) void getcolor_fcurve_rainbow(int cur, int tot, float out[3]) { float hsv[3], fac; diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index a82cca9e52a..21c25f829b1 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -158,7 +158,7 @@ static int add_driver_with_target( ReportList *UNUSED(reports), ID *dst_id, const char dst_path[], int dst_index, ID *src_id, const char src_path[], int src_index, - PointerRNA *UNUSED(dst_ptr), PropertyRNA *dst_prop, + PointerRNA *dst_ptr, PropertyRNA *dst_prop, PointerRNA *src_ptr, PropertyRNA *src_prop, short flag, int driver_type) { @@ -207,11 +207,15 @@ static int add_driver_with_target( /* Create a driver variable for the target * - For transform properties, we want to automatically use "transform channel" instead * (The only issue is with quat rotations vs euler channels...) + * - To avoid problems with transform properties depending on the final transform that they + * control (thus creating pseudo-cycles - see T48734), we don't use transform channels + * when both the source and destinations are in same places. */ dvar = driver_add_new_variable(driver); if (ELEM(src_ptr->type, &RNA_Object, &RNA_PoseBone) && - (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_"))) + (STREQ(prop_name, "location") || STREQ(prop_name, "scale") || STRPREFIX(prop_name, "rotation_")) && + (src_ptr->data != dst_ptr->data)) { /* Transform Channel */ DriverTarget *dtar; diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 6f1883cff55..6e776953356 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -40,6 +40,7 @@ #include "MEM_guardedalloc.h" #include "BLI_dlrbTree.h" +#include "BLI_math.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -282,6 +283,9 @@ static ActKeyBlock *bezts_to_new_actkeyblock(BezTriple *prev, BezTriple *beztn) ab->sel = (BEZT_ISSEL_ANY(prev) || BEZT_ISSEL_ANY(beztn)) ? SELECT : 0; ab->modified = 1; + if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) + ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD; + return ab; } @@ -305,16 +309,28 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt } - /* check if block needed - same value(s)? - * -> firstly, handles must have same central value as each other - * -> secondly, handles which control that section of the curve must be constant - */ + /* check if block needed */ if (prev == NULL) return; - if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return; - - if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return; - if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return; + if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) { + /* Animator tagged a "moving hold" + * - Previous key must also be tagged as a moving hold, otherwise + * we're just dealing with the first of a pair, and we don't + * want to be creating any phantom holds... + */ + if (BEZKEYTYPE(prev) != BEZT_KEYTYPE_MOVEHOLD) + return; + } + else { + /* Check for same values... + * - Handles must have same central value as each other + * - Handles which control that section of the curve must be constant + */ + if (IS_EQF(beztn->vec[1][1], prev->vec[1][1]) == 0) return; + + if (IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) == 0) return; + if (IS_EQF(prev->vec[1][1], prev->vec[2][1]) == 0) return; + } /* if there are no blocks already, just add as root */ if (blocks->root == NULL) { @@ -340,7 +356,13 @@ static void add_bezt_to_keyblocks_list(DLRBT_Tree *blocks, BezTriple *first_bezt */ if (IS_EQT(ab->start, prev->vec[1][0], BEZT_BINARYSEARCH_THRESH)) { /* set selection status and 'touched' status */ - if (BEZT_ISSEL_ANY(beztn)) ab->sel = SELECT; + if (BEZT_ISSEL_ANY(beztn)) + ab->sel = SELECT; + + /* XXX: only when the first one was a moving hold? */ + if (BEZKEYTYPE(beztn) == BEZT_KEYTYPE_MOVEHOLD) + ab->flag |= ACTKEYBLOCK_FLAG_MOVING_HOLD; + ab->modified++; /* done... no need to insert */ @@ -485,7 +507,27 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, /* tweak size of keyframe shape according to type of keyframe * - 'proper' keyframes have key_type = 0, so get drawn at full size */ - hsize -= 0.5f * key_type; + switch (key_type) { + case BEZT_KEYTYPE_KEYFRAME: /* must be full size */ + break; + + case BEZT_KEYTYPE_BREAKDOWN: /* slightly smaller than normal keyframe */ + hsize *= 0.85f; + break; + + case BEZT_KEYTYPE_MOVEHOLD: /* slightly smaller than normal keyframes (but by less than for breakdowns) */ + //hsize *= 0.72f; + hsize *= 0.95f; + break; + + case BEZT_KEYTYPE_EXTREME: /* slightly larger */ + hsize *= 1.2f; + break; + + default: + hsize -= 0.5f * key_type; + break; + } /* adjust view transform before starting */ glTranslatef(x, y, 0.0f); @@ -518,6 +560,15 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, else UI_GetThemeColor4fv(TH_KEYTYPE_JITTER, inner_col); break; } + case BEZT_KEYTYPE_MOVEHOLD: /* similar to traditional keyframes, but different... */ + { + /* XXX: Should these get their own theme options instead? */ + if (sel) UI_GetThemeColorShade4fv(TH_STRIP_SELECT, 35, inner_col); + else UI_GetThemeColorShade4fv(TH_STRIP, 50, inner_col); + + inner_col[3] = 1.0f; /* full opacity, to avoid problems with visual glitches */ + break; + } case BEZT_KEYTYPE_KEYFRAME: /* traditional yellowish frames (default theme) */ default: { @@ -557,13 +608,16 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, glTranslatef(-x, -y, 0.0f); } -static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, short channelLocked) +static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, float ypos, float yscale_fac, bool channelLocked) { ActKeyColumn *ak; ActKeyBlock *ab; float alpha; float xscale; - float iconsize = U.widget_unit / 4.0f; + + const float iconsize = (U.widget_unit / 4.0f) * yscale_fac; + const float mhsize = iconsize * 0.7f; + glEnable(GL_BLEND); /* get View2D scaling factor */ @@ -576,6 +630,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa /* draw keyblocks */ if (blocks) { float sel_color[4], unsel_color[4]; + float sel_mhcol[4], unsel_mhcol[4]; /* cache colours first */ UI_GetThemeColor4fv(TH_STRIP_SELECT, sel_color); @@ -584,16 +639,32 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa sel_color[3] *= alpha; unsel_color[3] *= alpha; + copy_v4_v4(sel_mhcol, sel_color); + sel_mhcol[3] *= 0.8f; + copy_v4_v4(unsel_mhcol, unsel_color); + unsel_mhcol[3] *= 0.8f; + /* NOTE: the tradeoff for changing colors between each draw is dwarfed by the cost of checking validity */ for (ab = blocks->first; ab; ab = ab->next) { if (actkeyblock_is_valid(ab, keys)) { - /* draw block */ - if (ab->sel) - glColor4fv(sel_color); - else - glColor4fv(unsel_color); - - glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize); + if (ab->flag & ACTKEYBLOCK_FLAG_MOVING_HOLD) { + /* draw "moving hold" long-keyframe block - slightly smaller */ + if (ab->sel) + glColor4fv(sel_mhcol); + else + glColor4fv(unsel_mhcol); + + glRectf(ab->start, ypos - mhsize, ab->end, ypos + mhsize); + } + else { + /* draw standard long-keyframe block */ + if (ab->sel) + glColor4fv(sel_color); + else + glColor4fv(unsel_color); + + glRectf(ab->start, ypos - iconsize, ab->end, ypos + iconsize); + } } } } @@ -619,7 +690,7 @@ static void draw_keylist(View2D *v2d, DLRBT_Tree *keys, DLRBT_Tree *blocks, floa /* *************************** Channel Drawing Funcs *************************** */ -void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos) +void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; @@ -631,13 +702,13 @@ void draw_summary_channel(View2D *v2d, bAnimContext *ac, float ypos) BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, 0); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos) +void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; @@ -649,13 +720,13 @@ void draw_scene_channel(View2D *v2d, bDopeSheet *ads, Scene *sce, float ypos) BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, 0); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos) +void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; @@ -667,19 +738,19 @@ void draw_object_channel(View2D *v2d, bDopeSheet *ads, Object *ob, float ypos) BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, 0); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos) +void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; - short locked = (fcu->flag & FCURVE_PROTECTED) || - ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || - ((adt && adt->action) && (adt->action->id.lib)); + bool locked = (fcu->flag & FCURVE_PROTECTED) || + ((fcu->grp) && (fcu->grp->flag & AGRP_PROTECTED)) || + ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); @@ -689,18 +760,18 @@ void draw_fcurve_channel(View2D *v2d, AnimData *adt, FCurve *fcu, float ypos) BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, locked); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos) +void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; - short locked = (agrp->flag & AGRP_PROTECTED) || - ((adt && adt->action) && (adt->action->id.lib)); + bool locked = (agrp->flag & AGRP_PROTECTED) || + ((adt && adt->action) && ID_IS_LINKED_DATABLOCK(adt->action)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); @@ -710,17 +781,17 @@ void draw_agroup_channel(View2D *v2d, AnimData *adt, bActionGroup *agrp, float y BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, locked); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos) +void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos, float yscale_fac) { DLRBT_Tree keys, blocks; - short locked = (act && act->id.lib != NULL); + bool locked = (act && ID_IS_LINKED_DATABLOCK(act)); BLI_dlrbTree_init(&keys); BLI_dlrbTree_init(&blocks); @@ -730,13 +801,13 @@ void draw_action_channel(View2D *v2d, AnimData *adt, bAction *act, float ypos) BLI_dlrbTree_linkedlist_sync(&keys); BLI_dlrbTree_linkedlist_sync(&blocks); - draw_keylist(v2d, &keys, &blocks, ypos, locked); + draw_keylist(v2d, &keys, &blocks, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); BLI_dlrbTree_free(&blocks); } -void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos) +void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos, float yscale_fac) { DLRBT_Tree keys; @@ -746,38 +817,42 @@ void draw_gpencil_channel(View2D *v2d, bDopeSheet *ads, bGPdata *gpd, float ypos BLI_dlrbTree_linkedlist_sync(&keys); - draw_keylist(v2d, &keys, NULL, ypos, 0); + draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, false); BLI_dlrbTree_free(&keys); } -void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos) +void draw_gpl_channel(View2D *v2d, bDopeSheet *ads, bGPDlayer *gpl, float ypos, float yscale_fac) { DLRBT_Tree keys; + bool locked = (gpl->flag & GP_LAYER_LOCKED) != 0; + BLI_dlrbTree_init(&keys); gpl_to_keylist(ads, gpl, &keys); BLI_dlrbTree_linkedlist_sync(&keys); - draw_keylist(v2d, &keys, NULL, ypos, (gpl->flag & GP_LAYER_LOCKED)); + draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked); BLI_dlrbTree_free(&keys); } -void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos) +void draw_masklay_channel(View2D *v2d, bDopeSheet *ads, MaskLayer *masklay, float ypos, float yscale_fac) { DLRBT_Tree keys; - + + bool locked = (masklay->flag & MASK_LAYERFLAG_LOCKED) != 0; + BLI_dlrbTree_init(&keys); - + mask_to_keylist(ads, masklay, &keys); - + BLI_dlrbTree_linkedlist_sync(&keys); - - draw_keylist(v2d, &keys, NULL, ypos, (masklay->flag & MASK_LAYERFLAG_LOCKED)); - + + draw_keylist(v2d, &keys, NULL, ypos, yscale_fac, locked); + BLI_dlrbTree_free(&keys); } diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 08a7355694b..4571df0f077 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -539,10 +539,10 @@ static short ok_bezier_region(KeyframeEditData *ked, BezTriple *bezt) } /** - * only called from #ok_bezier_region_lasso + * Called from #ok_bezier_region_lasso and #ok_bezier_channel_lasso */ -static bool bezier_region_lasso_test( - const struct KeyframeEdit_LassoData *data_lasso, +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_lasso->rectf_scaled, xy)) { @@ -564,7 +564,7 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_lasso_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_lasso_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -575,11 +575,38 @@ static short ok_bezier_region_lasso(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_lasso(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for lasso customdata (KeyframeEdit_LassoData) */ + if (ked->data) { + KeyframeEdit_LassoData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_lasso_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + /** - * only called from #ok_bezier_region_circle + * Called from #ok_bezier_region_circle and #ok_bezier_channel_circle */ -static bool bezier_region_circle_test( - const struct KeyframeEdit_CircleData *data_circle, +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, const float xy[2]) { if (BLI_rctf_isect_pt_v(data_circle->rectf_scaled, xy)) { @@ -602,7 +629,7 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) if (ked->data) { short ok = 0; -#define KEY_CHECK_OK(_index) bezier_region_circle_test(ked->data, bezt->vec[_index]) +#define KEY_CHECK_OK(_index) keyframe_region_circle_test(ked->data, bezt->vec[_index]) KEYFRAME_OK_CHECKS(KEY_CHECK_OK); #undef KEY_CHECK_OK @@ -613,6 +640,33 @@ static short ok_bezier_region_circle(KeyframeEditData *ked, BezTriple *bezt) return 0; } +static short ok_bezier_channel_circle(KeyframeEditData *ked, BezTriple *bezt) +{ + /* check for circle select customdata (KeyframeEdit_CircleData) */ + if (ked->data) { + KeyframeEdit_CircleData *data = ked->data; + float pt[2]; + + /* late-binding remap of the x values (for summary channels) */ + /* XXX: Ideally we reset, but it should be fine just leaving it as-is + * as the next channel will reset it properly, while the next summary-channel + * curve will also reset by itself... + */ + if (ked->iterflags & (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP)) { + data->rectf_scaled->xmin = ked->f1; + data->rectf_scaled->xmax = ked->f2; + } + + /* only use the x-coordinate of the point; the y is the channel range... */ + pt[0] = bezt->vec[1][0]; + pt[1] = ked->channel_y; + + if (keyframe_region_circle_test(data, pt)) + return KEYFRAME_OK_KEY; + } + return 0; +} + KeyframeEditFunc ANIM_editkeyframes_ok(short mode) { @@ -634,6 +688,10 @@ KeyframeEditFunc ANIM_editkeyframes_ok(short mode) return ok_bezier_region_lasso; case BEZT_OK_REGION_CIRCLE: /* only if the point falls within KeyframeEdit_CircleData defined data */ return ok_bezier_region_circle; + case BEZT_OK_CHANNEL_LASSO: /* same as BEZT_OK_REGION_LASSO, but we're only using the x-value of the points */ + return ok_bezier_channel_lasso; + case BEZT_OK_CHANNEL_CIRCLE: /* same as BEZT_OK_REGION_CIRCLE, but we're only using the x-value of the points */ + return ok_bezier_channel_circle; default: /* nothing was ok */ return NULL; } @@ -1150,6 +1208,13 @@ static short set_keytype_jitter(KeyframeEditData *UNUSED(ked), BezTriple *bezt) return 0; } +static short set_keytype_moving_hold(KeyframeEditData *UNUSED(ked), BezTriple *bezt) +{ + if (bezt->f2 & SELECT) + BEZKEYTYPE(bezt) = BEZT_KEYTYPE_MOVEHOLD; + return 0; +} + /* Set the interpolation type of the selected BezTriples in each F-Curve to the specified one */ KeyframeEditFunc ANIM_editkeyframes_keytype(short code) { @@ -1163,6 +1228,9 @@ KeyframeEditFunc ANIM_editkeyframes_keytype(short code) case BEZT_KEYTYPE_JITTER: /* jitter keyframe */ return set_keytype_jitter; + case BEZT_KEYTYPE_MOVEHOLD: /* moving hold */ + return set_keytype_moving_hold; + case BEZT_KEYTYPE_KEYFRAME: /* proper keyframe */ default: return set_keytype_keyframe; diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 66b3a63c669..0c0f54f0179 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -1069,6 +1069,9 @@ short insert_keyframe(ReportList *reports, ID *id, bAction *act, const char grou if (ELEM(RNA_property_subtype(prop), PROP_TRANSLATION, PROP_XYZ, PROP_EULER, PROP_COLOR, PROP_COORDS)) { fcu->color_mode = FCURVE_COLOR_AUTO_RGB; } + else if (RNA_property_subtype(prop), PROP_QUATERNION) { + fcu->color_mode = FCURVE_COLOR_AUTO_YRGB; + } } /* insert keyframe */ diff --git a/source/blender/editors/armature/armature_utils.c b/source/blender/editors/armature/armature_utils.c index 6306926e0b2..6979a324b69 100644 --- a/source/blender/editors/armature/armature_utils.c +++ b/source/blender/editors/armature/armature_utils.c @@ -424,7 +424,9 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone for (curBone = bones->first; curBone; curBone = curBone->next) { eBone = MEM_callocN(sizeof(EditBone), "make_editbone"); - /* Copy relevant data from bone to eBone */ + /* Copy relevant data from bone to eBone + * Keep selection logic in sync with ED_armature_sync_selection. + */ eBone->parent = parent; BLI_strncpy(eBone->name, curBone->name, sizeof(eBone->name)); eBone->flag = curBone->flag; @@ -435,11 +437,11 @@ EditBone *make_boneList(ListBase *edbo, ListBase *bones, EditBone *parent, Bone eBone->flag |= BONE_TIPSEL; if (eBone->parent && (eBone->flag & BONE_CONNECTED)) { eBone->parent->flag |= BONE_TIPSEL; - eBone->flag &= ~BONE_ROOTSEL; /* this is ignored when there is a connected parent, so unset it */ - } - else { - eBone->flag |= BONE_ROOTSEL; } + + /* For connected bones, take care when changing the selection when we have a connected parent, + * this flag is a copy of '(eBone->parent->flag & BONE_TIPSEL)'. */ + eBone->flag |= BONE_ROOTSEL; } else { /* if the bone is not selected, but connected to its parent diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index a929507929f..5015829f868 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -86,7 +86,7 @@ void ED_armature_enter_posemode(bContext *C, Base *base) ReportList *reports = CTX_wm_reports(C); Object *ob = base->object; - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { BKE_report(reports, RPT_WARNING, "Cannot pose libdata"); return; } diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index dca9aa3e446..d9a3efa765c 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -183,7 +183,7 @@ static int has_poselib_pose_data_poll(bContext *C) static int has_poselib_pose_data_for_editing_poll(bContext *C) { Object *ob = get_poselib_object(C); - return (ob && ob->poselib && !ob->poselib->id.lib); + return (ob && ob->poselib && !ID_IS_LINKED_DATABLOCK(ob->poselib)); } /* ----------------------------------- */ @@ -385,7 +385,7 @@ static int poselib_add_poll(bContext *C) if (ED_operator_posemode(C)) { Object *ob = get_poselib_object(C); if (ob) { - if ((ob->poselib == NULL) || (ob->poselib->id.lib == 0)) { + if ((ob->poselib == NULL) || !ID_IS_LINKED_DATABLOCK(ob->poselib)) { return true; } } diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index 420f72fedb3..72b48a32477 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -1301,7 +1301,7 @@ static int separate_exec(bContext *C, wmOperator *op) DAG_relations_tag_update(bmain); newob = newbase->object; - newcu = newob->data = BKE_curve_copy(oldcu); + newcu = newob->data = BKE_curve_copy(bmain, oldcu); newcu->editnurb = NULL; id_us_min(&oldcu->id); /* because new curve is a copy: reduce user count */ @@ -6034,9 +6034,8 @@ int join_curve_exec(bContext *C, wmOperator *op) BLI_movelisttolist(&cu->nurb, &tempbase); DAG_relations_tag_update(bmain); // because we removed object(s), call before editmode! - - ED_object_editmode_enter(C, EM_WAITCURSOR); - ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); + + DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index a0453f9694d..a61f863b61e 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -77,7 +77,7 @@ static struct { /* We could have the undo API pass in the previous state, for now store a local list */ ListBase local_links; -} uf_arraystore = {NULL}; +} uf_arraystore = {{NULL}}; /** * \param create: When false, only free the arrays. diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index a49b3362155..738496a67c6 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -205,6 +205,36 @@ void ED_gplayer_frames_select_border(bGPDlayer *gpl, float min, float max, short } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_gplayer_frames_select_region(KeyframeEditData *ked, bGPDlayer *gpl, short tool, short select_mode) +{ + bGPDframe *gpf; + + if (gpl == NULL) + return; + + /* only select frames which are within the region */ + for (gpf = gpl->frames.first; gpf; gpf = gpf->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = gpf->framenum; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + gpframe_select(gpf, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index bd1697b9a54..ac49a51c716 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -652,7 +652,7 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) /* identifiers */ ot->name = "Delete Active Frame"; ot->idname = "GPENCIL_OT_active_frame_delete"; - ot->description = "Delete the active frame for the active Grease Pencil datablock"; + ot->description = "Delete the active frame for the active Grease Pencil Layer"; ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -661,6 +661,64 @@ void GPENCIL_OT_active_frame_delete(wmOperatorType *ot) ot->poll = gp_actframe_delete_poll; } +/* **************** Delete All Active Frames ****************** */ + +static int gp_actframe_delete_all_poll(bContext *C) +{ + bGPdata *gpd = ED_gpencil_data_get_active(C); + + /* 1) There must be grease pencil data + * 2) Hopefully some of the layers have stuff we can use + */ + return (gpd && gpd->layers.first); +} + +static int gp_actframe_delete_all_exec(bContext *C, wmOperator *op) +{ + Scene *scene = CTX_data_scene(C); + bool success = false; + + CTX_DATA_BEGIN(C, bGPDlayer *, gpl, editable_gpencil_layers) + { + /* try to get the "active" frame - but only if it actually occurs on this frame */ + bGPDframe *gpf = gpencil_layer_getframe(gpl, CFRA, 0); + + if (gpf == NULL) + continue; + + /* delete it... */ + gpencil_layer_delframe(gpl, gpf); + + /* we successfully modified something */ + success = true; + } + CTX_DATA_END; + + /* updates */ + if (success) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + return OPERATOR_FINISHED; + } + else { + BKE_report(op->reports, RPT_ERROR, "No active frame(s) to delete"); + return OPERATOR_CANCELLED; + } +} + +void GPENCIL_OT_active_frames_delete_all(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Delete All Active Frames"; + ot->idname = "GPENCIL_OT_active_frames_delete_all"; + ot->description = "Delete the active frame(s) of all editable Grease Pencil layers"; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* callbacks */ + ot->exec = gp_actframe_delete_all_exec; + ot->poll = gp_actframe_delete_all_poll; +} + /* ******************* Delete Operator ************************ */ typedef enum eGP_DeleteMode { diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index dd28f6ac531..53fb33eeb9b 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -218,6 +218,7 @@ void GPENCIL_OT_unlock_all(struct wmOperatorType *ot); void GPENCIL_OT_layer_isolate(struct wmOperatorType *ot); void GPENCIL_OT_active_frame_delete(struct wmOperatorType *ot); +void GPENCIL_OT_active_frames_delete_all(struct wmOperatorType *ot); void GPENCIL_OT_convert(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index 405b673c42b..65ee1122b56 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -105,7 +105,7 @@ static void ed_keymap_gpencil_general(wmKeyConfig *keyconf) /* Delete Active Frame - For easier video tutorials/review sessions */ /* NOTE: This works even when not in EditMode */ - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, 0, DKEY); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, 0, DKEY); } /* ==================== */ @@ -238,7 +238,7 @@ static void ed_keymap_gpencil_editing(wmKeyConfig *keyconf) WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", XKEY, KM_PRESS, KM_CTRL, 0); WM_keymap_add_item(keymap, "GPENCIL_OT_dissolve", DELKEY, KM_PRESS, KM_CTRL, 0); - WM_keymap_add_item(keymap, "GPENCIL_OT_active_frame_delete", XKEY, KM_PRESS, KM_SHIFT, 0); + WM_keymap_add_item(keymap, "GPENCIL_OT_active_frames_delete_all", XKEY, KM_PRESS, KM_SHIFT, 0); /* copy + paste */ WM_keymap_add_item(keymap, "GPENCIL_OT_copy", CKEY, KM_PRESS, KM_CTRL, 0); @@ -364,6 +364,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_layer_isolate); WM_operatortype_append(GPENCIL_OT_active_frame_delete); + WM_operatortype_append(GPENCIL_OT_active_frames_delete_all); WM_operatortype_append(GPENCIL_OT_convert); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index fba2f30e715..a570d586f50 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -97,7 +97,8 @@ typedef enum eGP_StrokeAdd_Result { typedef enum eGPencil_PaintFlags { GP_PAINTFLAG_FIRSTRUN = (1 << 0), /* operator just started */ GP_PAINTFLAG_STROKEADDED = (1 << 1), - GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2) + GP_PAINTFLAG_V3D_ERASER_DEPTH = (1 << 2), + GP_PAINTFLAG_SELECTMASK = (1 << 3), } eGPencil_PaintFlags; @@ -813,18 +814,21 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, BLI_freelinkN(&gpf->strokes, gps); } else if (gps->totpoints == 1) { - gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - - /* do boundbox check first */ - if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { - /* only check if point is inside */ - if (len_v2v2_int(mval, pc1) <= radius) { - /* free stroke */ - // XXX: pressure sensitive eraser should apply here too? - MEM_freeN(gps->points); - if (gps->triangles) - MEM_freeN(gps->triangles); - BLI_freelinkN(&gpf->strokes, gps); + /* only process if it hasn't been masked out... */ + if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { + gp_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); + + /* do boundbox check first */ + if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { + /* only check if point is inside */ + if (len_v2v2_int(mval, pc1) <= radius) { + /* free stroke */ + // XXX: pressure sensitive eraser should apply here too? + MEM_freeN(gps->points); + if (gps->triangles) + MEM_freeN(gps->triangles); + BLI_freelinkN(&gpf->strokes, gps); + } } } } @@ -862,6 +866,11 @@ static void gp_stroke_eraser_dostroke(tGPsdata *p, pt1 = gps->points + i; pt2 = gps->points + i + 1; + /* only process if it hasn't been masked out... */ + if ((p->flags & GP_PAINTFLAG_SELECTMASK) && !(gps->points->flag & GP_SPOINT_SELECT)) + continue; + + /* get coordinates of point in screenspace */ gp_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gp_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); @@ -1199,6 +1208,7 @@ static void gp_session_cleanup(tGPsdata *p) static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) { Scene *scene = p->scene; + ToolSettings *ts = scene->toolsettings; /* get active layer (or add a new one if non-existent) */ p->gpl = gpencil_layer_getactive(p->gpd); @@ -1242,6 +1252,15 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) /* Ensure this gets set... */ p->gpf = p->gpl->actframe; + /* Restrict eraser to only affecting selected strokes, if the "selection mask" is on + * (though this is only available in editmode) + */ + if (p->gpd->flag & GP_DATA_STROKE_EDITMODE) { + if (ts->gp_sculpt.flag & GP_BRUSHEDIT_FLAG_SELECT_MASK) { + p->flags |= GP_PAINTFLAG_SELECTMASK; + } + } + if (p->gpf == NULL) { p->status = GP_STATUS_ERROR; //if (G.debug & G_DEBUG) @@ -1251,7 +1270,6 @@ static void gp_paint_initstroke(tGPsdata *p, eGPencil_PaintModes paintmode) } else { /* Drawing Modes - Add a new frame if needed on the active layer */ - ToolSettings *ts = p->scene->toolsettings; short add_frame_mode; if (ts->gpencil_flags & GP_TOOL_FLAG_RETAIN_LAST) diff --git a/source/blender/editors/gpencil/gpencil_undo.c b/source/blender/editors/gpencil/gpencil_undo.c index c39a3aa5cfc..f9b479ca03d 100644 --- a/source/blender/editors/gpencil/gpencil_undo.c +++ b/source/blender/editors/gpencil/gpencil_undo.c @@ -43,7 +43,9 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" +#include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_main.h" #include "ED_gpencil.h" @@ -151,7 +153,7 @@ void gpencil_undo_push(bGPdata *gpd) /* create new undo node */ undo_node = MEM_callocN(sizeof(bGPundonode), "gpencil undo node"); - undo_node->gpd = gpencil_data_duplicate(gpd, true); + undo_node->gpd = gpencil_data_duplicate(G.main, gpd, true); cur_node = undo_node; diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index b2c6107ab61..d62625baaa4 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -552,8 +552,8 @@ bool gp_smooth_stroke(bGPDstroke *gps, int i, float inf, bool affect_pressure) } /* Only affect endpoints by a fraction of the normal strength, - * to prevent the stroke from shrinking too much - */ + * to prevent the stroke from shrinking too much + */ if ((i == 0) || (i == gps->totpoints - 1)) { inf *= 0.1f; } diff --git a/source/blender/editors/include/ED_anim_api.h b/source/blender/editors/include/ED_anim_api.h index 27e1051a336..0940f594482 100644 --- a/source/blender/editors/include/ED_anim_api.h +++ b/source/blender/editors/include/ED_anim_api.h @@ -74,6 +74,7 @@ typedef struct bAnimContext { short mode; /* editor->mode */ short spacetype; /* sa->spacetype */ short regiontype; /* active region -> type (channels or main) */ + struct ScrArea *sa; /* editor host */ struct SpaceLink *sl; /* editor data */ struct ARegion *ar; /* region within editor */ @@ -85,6 +86,8 @@ typedef struct bAnimContext { ListBase *markers; /* active set of markers */ struct ReportList *reports; /* pointer to current reports list */ + + float yscale_fac; /* scale factor for height of channels (i.e. based on the size of keyframes) */ } bAnimContext; /* Main Data container types */ @@ -331,11 +334,11 @@ typedef enum eAnimFilter_Flags { /* -------------- Channel Defines -------------- */ /* channel heights */ -#define ACHANNEL_FIRST (-0.8f * U.widget_unit) -#define ACHANNEL_HEIGHT (0.8f * U.widget_unit) -#define ACHANNEL_HEIGHT_HALF (0.4f * U.widget_unit) -#define ACHANNEL_SKIP (0.1f * U.widget_unit) -#define ACHANNEL_STEP (ACHANNEL_HEIGHT + ACHANNEL_SKIP) +#define ACHANNEL_FIRST(ac) (-0.8f * (ac)->yscale_fac * U.widget_unit) +#define ACHANNEL_HEIGHT(ac) (0.8f * (ac)->yscale_fac * U.widget_unit) +#define ACHANNEL_HEIGHT_HALF(ac) (0.4f * (ac)->yscale_fac * U.widget_unit) +#define ACHANNEL_SKIP (0.1f * U.widget_unit) +#define ACHANNEL_STEP(ac) (ACHANNEL_HEIGHT(ac) + ACHANNEL_SKIP) /* channel widths */ #define ACHANNEL_NAMEWIDTH (10 * U.widget_unit) @@ -347,7 +350,6 @@ typedef enum eAnimFilter_Flags { /* -------------- NLA Channel Defines -------------- */ /* NLA channel heights */ -// XXX: NLACHANNEL_FIRST isn't used? #define NLACHANNEL_FIRST (-0.8f * U.widget_unit) #define NLACHANNEL_HEIGHT(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.8f * U.widget_unit) : (1.2f * U.widget_unit)) #define NLACHANNEL_HEIGHT_HALF(snla) ((snla && (snla->flag & SNLA_NOSTRIPCURVES)) ? (0.4f * U.widget_unit) : (0.6f * U.widget_unit)) diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h index 9a987d7618c..64c16605dec 100644 --- a/source/blender/editors/include/ED_buttons.h +++ b/source/blender/editors/include/ED_buttons.h @@ -37,6 +37,4 @@ bool ED_texture_context_check_particles(const struct bContext *C); bool ED_texture_context_check_linestyle(const struct bContext *C); bool ED_texture_context_check_others(const struct bContext *C); -void ED_buttons_id_unref(struct SpaceButs *sbuts, const struct ID *id); - #endif /* __ED_BUTTONS_H__ */ diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 80f930a0c30..92acfa6c1d2 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -109,7 +109,7 @@ int ED_file_extension_icon(const char *path); void ED_file_read_bookmarks(void); -void ED_file_change_dir(struct bContext *C, const bool checkdir); +void ED_file_change_dir(struct bContext *C); /* File menu stuff */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 255827db373..de5ab80a88f 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -42,6 +42,7 @@ struct bGPDlayer; struct bGPDframe; struct bGPDstroke; struct bAnimContext; +struct KeyframeEditData; struct PointerRNA; struct wmWindowManager; struct wmKeyConfig; @@ -120,6 +121,7 @@ void ED_gplayer_make_cfra_list(struct bGPDlayer *gpl, ListBase *elems, bool only bool ED_gplayer_frame_select_check(struct bGPDlayer *gpl); void ED_gplayer_frame_select_set(struct bGPDlayer *gpl, short mode); void ED_gplayer_frames_select_border(struct bGPDlayer *gpl, float min, float max, short select_mode); +void ED_gplayer_frames_select_region(struct KeyframeEditData *ked, struct bGPDlayer *gpl, short tool, short select_mode); void ED_gpencil_select_frames(struct bGPDlayer *gpl, short select_mode); void ED_gpencil_select_frame(struct bGPDlayer *gpl, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_keyframes_draw.h b/source/blender/editors/include/ED_keyframes_draw.h index 7d163da0db0..b1f3f012e09 100644 --- a/source/blender/editors/include/ED_keyframes_draw.h +++ b/source/blender/editors/include/ED_keyframes_draw.h @@ -80,7 +80,7 @@ typedef struct ActKeyBlock { /* key-block info */ char sel; - short handle_type; + short flag; float val; float start, end; @@ -89,6 +89,12 @@ typedef struct ActKeyBlock { short totcurve; } ActKeyBlock; +/* ActKeyBlock - Flag */ +typedef enum eActKeyBlock_Flag { + /* Key block represents a moving hold */ + ACTKEYBLOCK_FLAG_MOVING_HOLD = (1 << 0), +} eActKeyBlock_Flag; + /* *********************** Keyframe Drawing ****************************** */ /* options for keyframe shape drawing */ @@ -108,23 +114,23 @@ void draw_keyframe_shape(float x, float y, float xscale, float hsize, short sel, /* Channel Drawing ------------------ */ /* F-Curve */ -void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos); +void draw_fcurve_channel(struct View2D *v2d, struct AnimData *adt, struct FCurve *fcu, float ypos, float yscale_fac); /* Action Group Summary */ -void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos); +void draw_agroup_channel(struct View2D *v2d, struct AnimData *adt, struct bActionGroup *agrp, float ypos, float yscale_fac); /* Action Summary */ -void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos); +void draw_action_channel(struct View2D *v2d, struct AnimData *adt, struct bAction *act, float ypos, float yscale_fac); /* Object Summary */ -void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos); +void draw_object_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Object *ob, float ypos, float yscale_fac); /* Scene Summary */ -void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos); +void draw_scene_channel(struct View2D *v2d, struct bDopeSheet *ads, struct Scene *sce, float ypos, float yscale_fac); /* DopeSheet Summary */ -void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos); +void draw_summary_channel(struct View2D *v2d, struct bAnimContext *ac, float ypos, float yscale_fac); /* Grease Pencil datablock summary */ -void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos); +void draw_gpencil_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPdata *gpd, float ypos, float yscale_fac); /* Grease Pencil Layer */ -void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos); +void draw_gpl_channel(struct View2D *v2d, struct bDopeSheet *ads, struct bGPDlayer *gpl, float ypos, float yscale_fac); /* Mask Layer */ -void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos); +void draw_masklay_channel(struct View2D *v2d, struct bDopeSheet *ads, struct MaskLayer *masklay, float ypos, float yscale_fac); /* Keydata Generation --------------- */ /* F-Curve */ diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index fae3e3677a0..c0eb88cd982 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -45,14 +45,21 @@ struct Scene; /* bezt validation */ typedef enum eEditKeyframes_Validate { + /* Frame range */ BEZT_OK_FRAME = 1, BEZT_OK_FRAMERANGE, + /* Selection status */ BEZT_OK_SELECTED, + /* Values (y-val) only */ BEZT_OK_VALUE, BEZT_OK_VALUERANGE, + /* For graph editor keyframes (2D tests) */ BEZT_OK_REGION, BEZT_OK_REGION_LASSO, BEZT_OK_REGION_CIRCLE, + /* Only for keyframes a certain Dopesheet channel */ + BEZT_OK_CHANNEL_LASSO, + BEZT_OK_CHANNEL_CIRCLE, } eEditKeyframes_Validate; /* ------------ */ @@ -97,20 +104,20 @@ typedef enum eEditKeyframes_Mirror { } eEditKeyframes_Mirror; /* use with BEZT_OK_REGION_LASSO */ -struct KeyframeEdit_LassoData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_LassoData { + rctf *rectf_scaled; const rctf *rectf_view; const int (*mcords)[2]; int mcords_tot; -}; +} KeyframeEdit_LassoData; /* use with BEZT_OK_REGION_CIRCLE */ -struct KeyframeEdit_CircleData { - const rctf *rectf_scaled; +typedef struct KeyframeEdit_CircleData { + rctf *rectf_scaled; const rctf *rectf_view; float mval[2]; float radius_squared; -}; +} KeyframeEdit_CircleData; /* ************************************************ */ @@ -157,7 +164,8 @@ typedef struct KeyframeEditData { /* current iteration data */ struct FCurve *fcu; /* F-Curve that is being iterated over */ int curIndex; /* index of current keyframe being iterated over */ - + float channel_y; /* y-position of midpoint of the channel (for the dopesheet) */ + /* flags */ eKeyframeVertOk curflags; /* current flags for the keyframe we're reached in the iteration process */ eKeyframeIterFlags iterflags; /* settings for iteration process */ @@ -258,6 +266,18 @@ short bezt_to_cfraelem(KeyframeEditData *ked, struct BezTriple *bezt); */ void bezt_remap_times(KeyframeEditData *ked, struct BezTriple *bezt); +/* ------ 1.5-D Region Testing Uitls (Lasso/Circle Select) ------- */ +/* XXX: These are temporary, until we can unify GP/Mask Keyframe handling and standard FCurve Keyframe handling */ + +bool keyframe_region_lasso_test( + const KeyframeEdit_LassoData *data_lasso, + const float xy[2]); + +bool keyframe_region_circle_test( + const KeyframeEdit_CircleData *data_circle, + const float xy[2]); + + /* ************************************************ */ /* Destructive Editing API (keyframes_general.c) */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index 81e2558e765..602e203a381 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -325,18 +325,18 @@ bool ANIM_driver_vars_paste(struct ReportList *reports, struct FCurve *fcu, bool /* Notes: * - All the defines for this (User-Pref settings and Per-Scene settings) * are defined in DNA_userdef_types.h - * - Scene settings take presidence over those for userprefs, with old files + * - Scene settings take precedence over those for userprefs, with old files * inheriting userpref settings for the scene settings * - "On/Off + Mode" are stored per Scene, but "settings" are currently stored * as userprefs */ /* Auto-Keying macros for use by various tools */ -/* check if auto-keyframing is enabled (per scene takes presidence) */ +/* check if auto-keyframing is enabled (per scene takes precedence) */ #define IS_AUTOKEY_ON(scene) ((scene) ? (scene->toolsettings->autokey_mode & AUTOKEY_ON) : (U.autokey_mode & AUTOKEY_ON)) -/* check the mode for auto-keyframing (per scene takes presidence) */ +/* check the mode for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_MODE(scene, mode) ((scene) ? (scene->toolsettings->autokey_mode == AUTOKEY_MODE_##mode) : (U.autokey_mode == AUTOKEY_MODE_##mode)) -/* check if a flag is set for auto-keyframing (per scene takes presidence) */ +/* check if a flag is set for auto-keyframing (per scene takes precedence) */ #define IS_AUTOKEY_FLAG(scene, flag) \ ((scene) ? \ ((scene->toolsettings->autokey_flag & AUTOKEY_FLAG_##flag) || (U.autokey_flag & AUTOKEY_FLAG_##flag)) \ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 1f13b46ff2a..2ab788d5e2a 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -35,6 +35,7 @@ struct bContext; struct wmKeyConfig; struct MaskLayer; struct MaskLayerShape; +struct KeyframeEditData; /* mask_edit.c */ void ED_mask_get_size(struct ScrArea *sa, int *width, int *height); @@ -80,6 +81,7 @@ void ED_masklayer_make_cfra_list(struct MaskLayer *masklay, ListBase *elems, boo bool ED_masklayer_frame_select_check(struct MaskLayer *masklay); void ED_masklayer_frame_select_set(struct MaskLayer *masklay, short mode); void ED_masklayer_frames_select_border(struct MaskLayer *masklay, float min, float max, short select_mode); +void ED_masklayer_frames_select_region(struct KeyframeEditData *ked, struct MaskLayer *masklay, short tool, short select_mode); void ED_mask_select_frames(struct MaskLayer *masklay, short select_mode); void ED_mask_select_frame(struct MaskLayer *masklay, int selx, short select_mode); diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 7fe9a0c320c..f7b9d6b4f9e 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -103,8 +103,6 @@ void ED_node_set_active(struct Main *bmain, struct bNodeTree *ntree, struct bNod void ED_node_composite_job(const struct bContext *C, struct bNodeTree *nodetree, struct Scene *scene_owner); -void ED_node_id_unref(struct SpaceNode *snode, const ID *id); - /* node_ops.c */ void ED_operatormacros_node(void); diff --git a/source/blender/editors/include/ED_outliner.h b/source/blender/editors/include/ED_outliner.h index af4af8e2f5d..73ee2542247 100644 --- a/source/blender/editors/include/ED_outliner.h +++ b/source/blender/editors/include/ED_outliner.h @@ -27,10 +27,4 @@ #ifndef __ED_OUTLINER_H__ #define __ED_OUTLINER_H__ -struct ID; -struct SpaceOops; - -/* Used to check whether a given texture context is valid in current context. */ -void ED_outliner_id_unref(struct SpaceOops *so, const struct ID *id); - #endif /* __ED_OUTLINER_H__ */ diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index baf4ed574cf..7944b434057 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -75,7 +75,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( SnapObjectContext *ED_transform_snap_object_context_create_view3d( struct Main *bmain, struct Scene *scene, int flag, /* extra args for view3d */ - struct ARegion *ar, struct View3D *v3d); + const struct ARegion *ar, const struct View3D *v3d); void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); /* callbacks to filter how snap works */ diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index f143ea478c6..b6b80b93e0b 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -43,7 +43,7 @@ void ED_editors_exit(struct bContext *C); bool ED_editors_flush_edits(const struct bContext *C, bool for_render); -void ED_spacedata_id_unref(struct SpaceLink *sl, const struct ID *id); +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, struct ID *old_id, struct ID *new_id); void ED_OT_flush_edits(struct wmOperatorType *ot); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index c23c2eed890..48c1e2d1996 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -208,14 +208,18 @@ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *ar, const fl eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *ar, const float co[3], float r_co[2], const eV3DProjTest flag); float ED_view3d_calc_zfac(const struct RegionView3D *rv3d, const float co[3], bool *r_flip); -bool ED_view3d_win_to_ray(const struct ARegion *ar, struct View3D *v3d, const float mval[2], - float ray_start[3], float ray_normal[3], const bool do_clip); -bool ED_view3d_win_to_ray_ex(const struct ARegion *ar, struct View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); +bool ED_view3d_clip_segment(const struct RegionView3D *rv3d, float ray_start[3], float ray_end[3]); +bool ED_view3d_win_to_ray( + const struct ARegion *ar, const struct View3D *v3d, const float mval[2], + float ray_start[3], float ray_normal[3], const bool do_clip); +bool ED_view3d_win_to_ray_ex( + const struct ARegion *ar, const struct View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip); void ED_view3d_global_to_vector(const struct RegionView3D *rv3d, const float coord[3], float vec[3]); void ED_view3d_win_to_3d(const struct ARegion *ar, const float depth_pt[3], const float mval[2], float out[3]); void ED_view3d_win_to_3d_int(const struct ARegion *ar, const float depth_pt[3], const int mval[2], float out[3]); void ED_view3d_win_to_delta(const struct ARegion *ar, const float mval[2], float out[3], const float zfac); +void ED_view3d_win_to_origin(const struct ARegion *ar, const float mval[2], float out[3]); void ED_view3d_win_to_vector(const struct ARegion *ar, const float mval[2], float out[3]); bool ED_view3d_win_to_segment(const struct ARegion *ar, struct View3D *v3d, const float mval[2], float r_ray_start[3], float r_ray_end[3], const bool do_clip); @@ -403,4 +407,6 @@ void ED_view3d_shade_update(struct Main *bmain, struct Scene *scene, struct View #define V3D_IS_ZBUF(v3d) \ (((v3d)->flag & V3D_ZBUF_SELECT) && ((v3d)->drawtype > OB_WIRE)) +void ED_view3d_id_remap(struct View3D *v3d, const struct ID *old_id, struct ID *new_id); + #endif /* __ED_VIEW3D_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index 2c80701bf69..d85b60dcc43 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1020,6 +1020,7 @@ DEF_VICO(KEYTYPE_KEYFRAME_VEC) DEF_VICO(KEYTYPE_BREAKDOWN_VEC) DEF_VICO(KEYTYPE_EXTREME_VEC) DEF_VICO(KEYTYPE_JITTER_VEC) +DEF_VICO(KEYTYPE_MOVING_HOLD_VEC) DEF_VICO(COLORSET_01_VEC) DEF_VICO(COLORSET_02_VEC) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 9aad340d2fb..a623f5cfb9c 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -1020,12 +1020,18 @@ bool UI_context_copy_to_selected_list( /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); -void UI_context_active_but_prop_get(const struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index); +void UI_context_active_but_prop_get( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index); void UI_context_active_but_prop_handle(struct bContext *C); struct wmOperator *UI_context_active_operator_get(const struct bContext *C); void UI_context_update_anim_flag(const struct bContext *C); -void UI_context_active_but_prop_get_filebrowser(const struct bContext *C, struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); -void UI_context_active_but_prop_get_templateID(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop); +void UI_context_active_but_prop_get_filebrowser( + const struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, bool *r_is_undo); +void UI_context_active_but_prop_get_templateID( + struct bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop); /* Styled text draw */ void UI_fontstyle_set(const struct uiFontStyle *fs); diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index dc843952229..a81221ed54b 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -347,6 +347,8 @@ void UI_GetThemeColorShade3ubv(int colorid, int offset, unsigned char col[3]) // get four color values, scaled to 0.0-1.0 range void UI_GetThemeColor4fv(int colorid, float col[4]); +// get four color values, range 0.0-1.0, complete with shading offset for the RGB components +void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]); // get the 3 or 4 byte values void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index fac1267cc62..cbe8654ceb6 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1138,7 +1138,7 @@ static bool ui_but_event_property_operator_string(const bContext *C, uiBut *but, * as new items are added to the menu later on. It also optimises efficiency - * a radial menu is best kept symmetrical, with as large an angle between * items as possible, so that the gestural mouse movements can be fast and inexact. - + * * It starts off with two opposite sides for the first two items * then joined by the one below for the third (this way, even with three items, * the menu seems to still be 'in order' reading left to right). Then the fourth is @@ -2576,9 +2576,11 @@ static void ui_set_but_soft_range(uiBut *but) } else if (but->poin && (but->pointype & UI_BUT_POIN_TYPES)) { float value = ui_but_value_get(but); - CLAMP(value, but->hardmin, but->hardmax); - but->softmin = min_ff(but->softmin, value); - but->softmax = max_ff(but->softmax, value); + if (isfinite(value)) { + CLAMP(value, but->hardmin, but->hardmax); + but->softmin = min_ff(but->softmin, value); + but->softmax = max_ff(but->softmax, value); + } } else { BLI_assert(0); @@ -4323,7 +4325,7 @@ uiBut *uiDefSearchBut(uiBlock *block, void *arg, int retval, int icon, int maxle /** - * \param sfunc, bfunc: both get it as \a arg. + * \param search_func, bfunc: both get it as \a arg. * \param arg: user value, * \param active: when set, button opens with this item visible and selected. */ diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 72a6a04feec..9ce863dc8f7 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -734,24 +734,50 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), CLAMP(max, rect.ymin, rect.ymax); fdrawline(rect.xmax - 3, min, rect.xmax - 3, max); } + /* RGB (3 channel) */ + else if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) { + glBlendFunc(GL_ONE, GL_ONE); + + glEnableClientState(GL_VERTEX_ARRAY); + + glPushMatrix(); + + glTranslatef(rect.xmin, yofs, 0.f); + glScalef(w, h, 0.f); + + glColor3fv( colors_alpha[0] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + + glColor3fv( colors_alpha[1] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - /* RGB / YCC (3 channels) */ + glColor3fv( colors_alpha[2] ); + glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); + glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); + + glDisableClientState(GL_VERTEX_ARRAY); + glPopMatrix(); + } + /* PARADE / YCC (3 channels) */ else if (ELEM(scopes->wavefrm_mode, - SCOPES_WAVEFRM_RGB, + SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_YCC_601, SCOPES_WAVEFRM_YCC_709, - SCOPES_WAVEFRM_YCC_JPEG)) + SCOPES_WAVEFRM_YCC_JPEG + )) { - int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB); - + int rgb = (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB_PARADE); + glBlendFunc(GL_ONE, GL_ONE); - + glPushMatrix(); glEnableClientState(GL_VERTEX_ARRAY); - + glTranslatef(rect.xmin, yofs, 0.f); glScalef(w3, h, 0.f); - + glColor3fv((rgb) ? colors_alpha[0] : colorsycc_alpha[0]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_1); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); @@ -760,19 +786,19 @@ void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wcol), glColor3fv((rgb) ? colors_alpha[1] : colorsycc_alpha[1]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_2); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - + glTranslatef(1.f, 0.f, 0.f); glColor3fv((rgb) ? colors_alpha[2] : colorsycc_alpha[2]); glVertexPointer(2, GL_FLOAT, 0, scopes->waveform_3); glDrawArrays(GL_POINTS, 0, scopes->waveform_tot); - + glDisableClientState(GL_VERTEX_ARRAY); glPopMatrix(); - - - /* min max */ + } + /* min max */ + if (scopes->wavefrm_mode != SCOPES_WAVEFRM_LUMA ) { for (int c = 0; c < 3; c++) { - if (scopes->wavefrm_mode == SCOPES_WAVEFRM_RGB) + if (ELEM(scopes->wavefrm_mode, SCOPES_WAVEFRM_RGB_PARADE, SCOPES_WAVEFRM_RGB)) glColor3f(colors[c][0] * 0.75f, colors[c][1] * 0.75f, colors[c][2] * 0.75f); else glColor3f(colorsycc[c][0] * 0.75f, colorsycc[c][1] * 0.75f, colorsycc[c][2] * 0.75f); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 2cbc56b14d3..ac7b6428217 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -805,7 +805,7 @@ static int depthdropper_init(bContext *C, wmOperator *op) RegionView3D *rv3d = CTX_wm_region_view3d(C); if (rv3d && rv3d->persp == RV3D_CAMOB) { View3D *v3d = CTX_wm_view3d(C); - if (v3d->camera && v3d->camera->data && (((ID *)v3d->camera->data)->lib == NULL)) { + if (v3d->camera && v3d->camera->data && !ID_IS_LINKED_DATABLOCK(v3d->camera->data)) { RNA_id_pointer_create(v3d->camera->data, &ddr->ptr); ddr->prop = RNA_struct_find_property(&ddr->ptr, "dof_distance"); } diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 133487e1846..11703208b2a 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1057,7 +1057,9 @@ static void ui_multibut_free(uiHandleButtonData *data, uiBlock *block) } } -static bool ui_multibut_states_tag(uiBut *but_active, uiHandleButtonData *data, const wmEvent *event) +static bool ui_multibut_states_tag( + uiBut *but_active, + uiHandleButtonData *data, const wmEvent *event) { uiBut *but; float seg[2][2]; @@ -1668,7 +1670,9 @@ static bool ui_but_contains_point_px_icon(uiBut *but, ARegion *ar, const wmEvent return BLI_rcti_isect_pt(&rect, x, y); } -static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static bool ui_but_drag_init( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { /* prevent other WM gestures to start while we try to drag */ WM_gestures_remove(C); @@ -1740,11 +1744,16 @@ static bool ui_but_drag_init(bContext *C, uiBut *but, uiHandleButtonData *data, } } else { - wmDrag *drag; + wmDrag *drag = WM_event_start_drag( + C, but->icon, but->dragtype, but->dragpoin, + ui_but_value_get(but), WM_DRAG_NOP); - drag = WM_event_start_drag(C, but->icon, but->dragtype, but->dragpoin, ui_but_value_get(but), WM_DRAG_NOP); - if (but->imb) - WM_event_drag_image(drag, but->imb, but->imb_scale, BLI_rctf_size_x(&but->rect), BLI_rctf_size_y(&but->rect)); + if (but->imb) { + WM_event_drag_image( + drag, but->imb, but->imb_scale, + BLI_rctf_size_x(&but->rect), + BLI_rctf_size_y(&but->rect)); + } } return true; } @@ -1872,11 +1881,15 @@ static void ui_but_smart_controller_add(bContext *C, uiBut *from, uiBut *to) /* (3) add a new controller */ if (WM_operator_name_call(C, "LOGIC_OT_controller_add", WM_OP_EXEC_DEFAULT, &props_ptr) & OPERATOR_FINISHED) { cont = (bController *)ob->controllers.last; - cont->type = CONT_LOGIC_AND; /* Quick fix to make sure we always have an AND controller. It might be nicer to make sure the operator gives us the right one though... */ + /* Quick fix to make sure we always have an AND controller. + * It might be nicer to make sure the operator gives us the right one though... */ + cont->type = CONT_LOGIC_AND; /* (4) link the sensor->controller->actuator */ tmp_but = MEM_callocN(sizeof(uiBut), "uiBut"); - UI_but_link_set(tmp_but, (void **)&cont, (void ***)&(cont->links), &(cont->totlinks), from->link->tocode, (int)to->hardmin); + UI_but_link_set( + tmp_but, (void **)&cont, (void ***)&(cont->links), + &cont->totlinks, from->link->tocode, (int)to->hardmin); tmp_but->hardmin = from->link->tocode; tmp_but->poin = (char *)cont; @@ -3180,7 +3193,9 @@ static void ui_textedit_prev_but(uiBlock *block, uiBut *actbut, uiHandleButtonDa } -static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int retval = WM_UI_HANDLER_CONTINUE; bool changed = false, inbox = false, update = false; @@ -3233,7 +3248,8 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle if (data->searchbox) inbox = ui_searchbox_inside(data->searchbox, event->x, event->y); - /* for double click: we do a press again for when you first click on button (selects all text, no cursor pos) */ + /* for double click: we do a press again for when you first click on button + * (selects all text, no cursor pos) */ if (event->val == KM_PRESS || event->val == KM_DBL_CLICK) { float mx, my; @@ -3477,7 +3493,9 @@ static void ui_do_but_textedit(bContext *C, uiBlock *block, uiBut *but, uiHandle ED_region_tag_redraw(data->region); } -static void ui_do_but_textedit_select(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static void ui_do_but_textedit_select( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, retval = WM_UI_HANDLER_CONTINUE; @@ -3682,7 +3700,9 @@ static uiBut *ui_but_list_row_text_activate( /* ***************** events for different button types *************** */ -static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BUT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (event->type == LEFTMOUSE && event->val == KM_PRESS) { @@ -3713,7 +3733,9 @@ static int ui_do_but_BUT(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HOTKEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3776,7 +3798,9 @@ static int ui_do_but_HOTKEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_KEYEVT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3802,7 +3826,9 @@ static int ui_do_but_KEYEVT(bContext *C, uiBut *but, uiHandleButtonData *data, c return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TEX( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { if (ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY) && event->val == KM_PRESS) { @@ -3830,7 +3856,9 @@ static int ui_do_but_TEX(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SEARCH_UNLINK( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { uiButExtraIconType extra_icon_type; @@ -3877,7 +3905,9 @@ static int ui_do_but_SEARCH_UNLINK(bContext *C, uiBlock *block, uiBut *but, uiHa return ui_do_but_TEX(C, block, but, data, event); } -static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TOG( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { #ifdef USE_DRAG_TOGGLE if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -3944,7 +3974,9 @@ static int ui_do_but_TOG(bContext *C, uiBut *but, uiHandleButtonData *data, cons return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_EXIT(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_EXIT( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -4092,7 +4124,7 @@ static float ui_numedit_apply_snap( static bool ui_numedit_but_NUM( uiBut *but, uiHandleButtonData *data, - int mx, + int mx, const bool is_motion, const enum eSnapType snap, float fac) { float deler, tempf, softmin, softmax, softrange; @@ -4100,8 +4132,10 @@ static bool ui_numedit_but_NUM( bool changed = false; const bool is_float = ui_but_is_float(but); - /* prevent unwanted drag adjustments */ - if (ui_but_dragedit_update_mval(data, mx) == false) { + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ + if ((is_motion || data->draglock) && + (ui_but_dragedit_update_mval(data, mx) == false)) + { return changed; } @@ -4242,7 +4276,9 @@ static bool ui_numedit_but_NUM( return changed; } -static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_NUM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; /* mouse location scaled to fit the UI */ int screen_mx, screen_my; /* mouse location kept at screen pixel coords */ @@ -4324,6 +4360,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); const enum eSnapType snap = ui_event_to_snap(event); float fac; @@ -4335,8 +4372,9 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton fac = 1.0f; if (event->shift) fac /= 10.0f; - if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), snap, fac)) + if (ui_numedit_but_NUM(but, data, (ui_but_is_cursor_warp(but) ? screen_mx : mx), is_motion, snap, fac)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { if (data->multi_data.init == BUTTON_MULTI_INIT_ENABLE) { @@ -4430,7 +4468,7 @@ static int ui_do_but_NUM(bContext *C, uiBlock *block, uiBut *but, uiHandleButton static bool ui_numedit_but_SLI( uiBut *but, uiHandleButtonData *data, - int mx, const bool is_horizontal, + int mx, const bool is_horizontal, const bool is_motion, const bool snap, const bool shift) { float deler, f, tempf, softmin, softmax, softrange; @@ -4440,8 +4478,9 @@ static bool ui_numedit_but_SLI( /* note, 'offs' is really from the widget drawing rounded corners see 'widget_numslider' */ float offs; - /* prevent unwanted drag adjustments */ + /* prevent unwanted drag adjustments, test motion so modifier keys refresh. */ if ((but->type != UI_BTYPE_SCROLL) && + (is_motion || data->draglock) && (ui_but_dragedit_update_mval(data, mx) == false)) { return changed; @@ -4541,7 +4580,9 @@ static bool ui_numedit_but_SLI( return changed; } -static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SLI( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, click = 0; int retval = WM_UI_HANDLER_CONTINUE; @@ -4634,12 +4675,14 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton } } else if ((event->type == MOUSEMOVE) || ui_event_is_snap(event)) { + const bool is_motion = (event->type == MOUSEMOVE); #ifdef USE_DRAG_MULTINUM data->multi_data.drag_dir[0] += abs(data->draglastx - mx); data->multi_data.drag_dir[1] += abs(data->draglasty - my); #endif - if (ui_numedit_but_SLI(but, data, mx, true, event->ctrl != 0, event->shift != 0)) + if (ui_numedit_but_SLI(but, data, mx, true, is_motion, event->ctrl != 0, event->shift != 0)) { ui_numedit_apply(C, block, but, data); + } #ifdef USE_DRAG_MULTINUM else if (data->multi_data.has_mbuts) { @@ -4722,7 +4765,9 @@ static int ui_do_but_SLI(bContext *C, uiBlock *block, uiBut *but, uiHandleButton return retval; } -static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_SCROLL( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my /*, click = 0 */; int retval = WM_UI_HANDLER_CONTINUE; @@ -4765,8 +4810,10 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut button_activate_state(C, but, BUTTON_STATE_EXIT); } else if (event->type == MOUSEMOVE) { - if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, false, false)) + const bool is_motion = (event->type == MOUSEMOVE); + if (ui_numedit_but_SLI(but, data, (horizontal) ? mx : my, horizontal, is_motion, false, false)) { ui_numedit_apply(C, block, but, data); + } } retval = WM_UI_HANDLER_BREAK; @@ -4775,7 +4822,9 @@ static int ui_do_but_SCROLL(bContext *C, uiBlock *block, uiBut *but, uiHandleBut return retval; } -static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_GRIP( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; int retval = WM_UI_HANDLER_CONTINUE; @@ -4826,7 +4875,9 @@ static int ui_do_but_GRIP(bContext *C, uiBlock *block, uiBut *but, uiHandleButto return retval; } -static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LISTROW( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* hack to pass on ctrl+click and double click to overlapping text @@ -4846,7 +4897,9 @@ static int ui_do_but_LISTROW(bContext *C, uiBut *but, uiHandleButtonData *data, return ui_do_but_EXIT(C, but, data, event); } -static int ui_do_but_BLOCK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_BLOCK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { @@ -5021,7 +5074,9 @@ static void ui_palette_set_active(uiBut *but) } } -static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLOR( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { if (data->state == BUTTON_STATE_HIGHLIGHT) { /* first handle click on icondrag type button */ @@ -5154,7 +5209,9 @@ static int ui_do_but_COLOR(bContext *C, uiBut *but, uiHandleButtonData *data, co return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_UNITVEC(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_UNITVEC( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5431,7 +5488,9 @@ static void ui_ndofedit_but_HSVCUBE( ui_but_v3_set(but, data->vec); } -static int ui_do_but_HSVCUBE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCUBE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -5607,8 +5666,7 @@ static bool ui_numedit_but_HSVCIRCLE( ui_color_picker_to_rgb_v(hsv, rgb); if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (rgb[0] || rgb[1] || rgb[2])) { - normalize_v3(rgb); - mul_v3_fl(rgb, but->a2); + normalize_v3_length(rgb, but->a2); } if (use_display_colorspace) @@ -5684,8 +5742,7 @@ static void ui_ndofedit_but_HSVCIRCLE( ui_color_picker_to_rgb_v(hsv, data->vec); if ((but->flag & UI_BUT_VEC_SIZE_LOCK) && (data->vec[0] || data->vec[1] || data->vec[2])) { - normalize_v3(data->vec); - mul_v3_fl(data->vec, but->a2); + normalize_v3_length(data->vec, but->a2); } if (use_display_colorspace) @@ -5695,7 +5752,9 @@ static void ui_ndofedit_but_HSVCIRCLE( } -static int ui_do_but_HSVCIRCLE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HSVCIRCLE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorPicker *cpicker = but->custom_data; float *hsv = cpicker->color_data; @@ -5823,7 +5882,9 @@ static bool ui_numedit_but_COLORBAND(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_COLORBAND(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_COLORBAND( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { ColorBand *coba; CBData *cbd; @@ -5999,7 +6060,9 @@ static bool ui_numedit_but_CURVE( return changed; } -static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_CURVE( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my, a; bool changed = false; @@ -6014,20 +6077,15 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt CurveMapping *cumap = (CurveMapping *)but->poin; CurveMap *cuma = cumap->cm + cumap->cur; CurveMapPoint *cmp; - float fx, fy, zoomx, zoomy, offsx, offsy; - float dist, mindist = 200.0f; // 14 pixels radius + const float m_xy[2] = {mx, my}; + float dist_min_sq = SQUARE(14.0f); /* 14 pixels radius */ int sel = -1; - zoomx = BLI_rctf_size_x(&but->rect) / BLI_rctf_size_x(&cumap->curr); - zoomy = BLI_rctf_size_y(&but->rect) / BLI_rctf_size_y(&cumap->curr); - offsx = cumap->curr.xmin; - offsy = cumap->curr.ymin; - if (event->ctrl) { - fx = ((float)mx - but->rect.xmin) / zoomx + offsx; - fy = ((float)my - but->rect.ymin) / zoomy + offsy; + float f_xy[2]; + BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy); - curvemap_insert(cuma, fx, fy); + curvemap_insert(cuma, f_xy[0], f_xy[1]); curvemapping_changed(cumap, false); changed = true; } @@ -6035,33 +6093,37 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt /* check for selecting of a point */ cmp = cuma->curve; /* ctrl adds point, new malloc */ for (a = 0; a < cuma->totpoint; a++) { - fx = but->rect.xmin + zoomx * (cmp[a].x - offsx); - fy = but->rect.ymin + zoomy * (cmp[a].y - offsy); - dist = (fx - mx) * (fx - mx) + (fy - my) * (fy - my); - if (dist < mindist) { + float f_xy[2]; + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[a].x); + const float dist_sq = len_squared_v2v2(m_xy, f_xy); + if (dist_sq < dist_min_sq) { sel = a; - mindist = dist; + dist_min_sq = dist_sq; } } if (sel == -1) { int i; + float f_xy[2], f_xy_prev[2]; /* if the click didn't select anything, check if it's clicked on the * curve itself, and if so, add a point */ - fx = ((float)mx - but->rect.xmin) / zoomx + offsx; - fy = ((float)my - but->rect.ymin) / zoomy + offsy; - cmp = cuma->table; - /* loop through the curve segment table and find what's near the mouse. - * 0.05 is kinda arbitrary, but seems to be what works nicely. */ - for (i = 0; i <= CM_TABLE; i++) { - if ((fabsf(fx - cmp[i].x) < 0.05f) && - (fabsf(fy - cmp[i].y) < 0.05f)) - { - - curvemap_insert(cuma, fx, fy); + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[0].x); + + /* with 160px height 8px should translate to the old 0.05 coefficient at no zoom */ + dist_min_sq = SQUARE(8.0f); + + /* loop through the curve segment table and find what's near the mouse. */ + for (i = 1; i <= CM_TABLE; i++) { + copy_v2_v2(f_xy_prev, f_xy); + BLI_rctf_transform_pt_v(&but->rect, &cumap->curr, f_xy, &cmp[i].x); + + if (dist_squared_to_line_segment_v2(m_xy, f_xy_prev, f_xy) < dist_min_sq) { + BLI_rctf_transform_pt_v(&cumap->curr, &but->rect, f_xy, m_xy); + + curvemap_insert(cuma, f_xy[0], f_xy[1]); curvemapping_changed(cumap, false); changed = true; @@ -6070,10 +6132,11 @@ static int ui_do_but_CURVE(bContext *C, uiBlock *block, uiBut *but, uiHandleButt cmp = cuma->curve; /* find newly added point and make it 'sel' */ - for (a = 0; a < cuma->totpoint; a++) - if (cmp[a].x == fx) + for (a = 0; a < cuma->totpoint; a++) { + if (cmp[a].x == f_xy[0]) { sel = a; - + } + } break; } } @@ -6167,7 +6230,9 @@ static bool ui_numedit_but_HISTOGRAM(uiBut *but, uiHandleButtonData *data, int m return changed; } -static int ui_do_but_HISTOGRAM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_HISTOGRAM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6240,7 +6305,9 @@ static bool ui_numedit_but_WAVEFORM(uiBut *but, uiHandleButtonData *data, int mx return changed; } -static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_WAVEFORM( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6294,7 +6361,9 @@ static int ui_do_but_WAVEFORM(bContext *C, uiBlock *block, uiBut *but, uiHandleB return WM_UI_HANDLER_CONTINUE; } -static int ui_do_but_LINK(bContext *C, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_LINK( + bContext *C, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { VECCOPY2D(but->linkto, event->mval); @@ -6357,7 +6426,9 @@ static bool ui_numedit_but_TRACKPREVIEW( return changed; } -static int ui_do_but_TRACKPREVIEW(bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) +static int ui_do_but_TRACKPREVIEW( + bContext *C, uiBlock *block, uiBut *but, + uiHandleButtonData *data, const wmEvent *event) { int mx, my; @@ -6853,7 +6924,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) WM_operator_properties_create(&ptr_props, "WM_OT_doc_view"); RNA_string_set(&ptr_props, "doc_id", buf); - uiItemFullO(layout, "WM_OT_doc_view", CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), + uiItemFullO(layout, "WM_OT_doc_view", + CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Online Python Reference"), ICON_NONE, ptr_props.data, WM_OP_EXEC_DEFAULT, 0); /* XXX inactive option, not for public! */ @@ -6862,7 +6934,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) RNA_string_set(&ptr_props, "doc_id", buf); RNA_string_set(&ptr_props, "doc_new", RNA_property_description(but->rnaprop)); - uiItemFullO(layout, "WM_OT_doc_edit", "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); + uiItemFullO(layout, "WM_OT_doc_edit", + "Submit Description", ICON_NONE, ptr_props.data, WM_OP_INVOKE_DEFAULT, 0); #endif } } @@ -7442,7 +7515,8 @@ static bool ui_but_contains_point_px(ARegion *ar, uiBut *but, int x, int y) /** * Can we mouse over the button or is it hidden/disabled/layout. - * Note: ctrl is kind of a hack currently, so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. + * \note ctrl is kind of a hack currently, + * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. */ static bool ui_but_is_interactive(const uiBut *but, const bool labeledit) { @@ -7636,7 +7710,9 @@ static void button_activate_state(bContext *C, uiBut *but, uiHandleButtonState s if (but->block->auto_open == true) { /* test for toolbox */ time = 1; } - else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || but->block->auto_open == true) { + else if ((but->block->flag & UI_BLOCK_LOOP && but->type != UI_BTYPE_BLOCK) || + (but->block->auto_open == true)) + { time = 5 * U.menuthreshold2; } else if (U.uiflag & USER_MENUOPENAUTO) { @@ -8013,20 +8089,21 @@ uiBut *UI_context_active_but_get(const struct bContext *C) } /* helper function for insert keyframe, reset to default, etc operators */ -void UI_context_active_but_prop_get(const bContext *C, struct PointerRNA *ptr, struct PropertyRNA **prop, int *index) +void UI_context_active_but_prop_get( + const bContext *C, + struct PointerRNA *r_ptr, struct PropertyRNA **r_prop, int *r_index) { uiBut *activebut = ui_context_rna_button_active(C); - memset(ptr, 0, sizeof(*ptr)); - if (activebut && activebut->rnapoin.data) { - *ptr = activebut->rnapoin; - *prop = activebut->rnaprop; - *index = activebut->rnaindex; + *r_ptr = activebut->rnapoin; + *r_prop = activebut->rnaprop; + *r_index = activebut->rnaindex; } else { - *prop = NULL; - *index = 0; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; + *r_index = 0; } } @@ -8721,8 +8798,7 @@ static bool ui_mouse_motion_towards_check( float delta[2]; sub_v2_v2v2(delta, oldp, cent); - normalize_v2(delta); - mul_v2_fl(delta, MENU_TOWARDS_WIGGLE_ROOM); + normalize_v2_length(delta, MENU_TOWARDS_WIGGLE_ROOM); add_v2_v2(oldp, delta); } @@ -9812,10 +9888,17 @@ static int ui_handle_menus_recursive( retval = ui_pie_handler(C, event, menu); } else if (event->type == LEFTMOUSE || event->val != KM_DBL_CLICK) { + bool handled = false; + if (listbox) { - retval = ui_handle_list_event(C, event, menu->region, listbox); + int retval_test = ui_handle_list_event(C, event, menu->region, listbox); + if (retval_test != WM_UI_HANDLER_CONTINUE) { + retval = retval_test; + handled = true; + } } - if (retval == WM_UI_HANDLER_CONTINUE) { + + if (handled == false) { retval = ui_handle_menu_event( C, event, menu, level, is_parent_inside, is_parent_menu, is_floating); diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index 6dc60f1d70b..4107414a240 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -505,6 +505,11 @@ static void vicon_keytype_jitter_draw(int x, int y, int w, int h, float alpha) vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_JITTER); } +static void vicon_keytype_moving_hold_draw(int x, int y, int w, int h, float alpha) +{ + vicon_keytype_draw_wrapper(x, y, w, h, alpha, BEZT_KEYTYPE_MOVEHOLD); +} + static void vicon_colorset_draw(int index, int x, int y, int w, int h, float UNUSED(alpha)) { bTheme *btheme = UI_GetTheme(); @@ -792,6 +797,7 @@ static void init_internal_icons(void) def_internal_vicon(VICO_KEYTYPE_BREAKDOWN_VEC, vicon_keytype_breakdown_draw); def_internal_vicon(VICO_KEYTYPE_EXTREME_VEC, vicon_keytype_extreme_draw); def_internal_vicon(VICO_KEYTYPE_JITTER_VEC, vicon_keytype_jitter_draw); + def_internal_vicon(VICO_KEYTYPE_MOVING_HOLD_VEC, vicon_keytype_moving_hold_draw); def_internal_vicon(VICO_COLORSET_01_VEC, vicon_colorset_draw_01); def_internal_vicon(VICO_COLORSET_02_VEC, vicon_colorset_draw_02); @@ -1055,6 +1061,9 @@ static void icon_create_rect(struct PreviewImage *prv_img, enum eIconSizes size) } } +static void ui_id_preview_image_render_size( + const bContext *C, Scene *scene, ID *id, PreviewImage *pi, int size, const bool use_job); + void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool big) { Icon *icon = BKE_icon_get(icon_id); @@ -1070,22 +1079,20 @@ void ui_icon_ensure_deferred(const bContext *C, const int icon_id, const bool bi } if (di) { - if (di->type == ICON_TYPE_PREVIEW) { - PreviewImage *prv = (icon->type != 0) ? BKE_previewimg_id_ensure((ID *)icon->obj) : icon->obj; - - if (prv) { - const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; - - if (!prv->use_deferred || prv->rect[size] || (prv->flag[size] & PRV_USER_EDITED)) { - return; + switch (di->type) { + case ICON_TYPE_PREVIEW: + { + ID *id = (icon->type != 0) ? icon->obj : NULL; + PreviewImage *prv = id ? BKE_previewimg_id_ensure(id) : icon->obj; + + if (prv) { + const int size = big ? ICON_SIZE_PREVIEW : ICON_SIZE_ICON; + + if (id || prv->use_deferred) { + ui_id_preview_image_render_size(C, NULL, id, prv, size, true); + } } - - icon_create_rect(prv, size); - - /* Always using job (background) version. */ - ED_preview_icon_job(C, prv, NULL, prv->rect[size], prv->w[size], prv->h[size]); - - prv->flag[size] &= ~PRV_CHANGED; + break; } } } diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index ff29a6f8e33..1af6d902b18 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -416,7 +416,7 @@ bool UI_context_copy_to_selected_list( if ((id_data == NULL) || (id_data->tag & LIB_TAG_DOIT) == 0 || - (id_data->lib) || + ID_IS_LINKED_DATABLOCK(id_data) || (GS(id_data->name) != id_code)) { BLI_remlink(&lb, link); diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index 85e32144bcd..79961eae79d 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1765,8 +1765,8 @@ void UI_panel_category_draw_all(ARegion *ar, const char *category_id_active) /* tab highlight (3d look) */ glColor3ubv(is_active ? theme_col_tab_highlight : theme_col_tab_highlight_inactive); ui_panel_category_draw_tab(GL_LINE_STRIP, rct->xmin, rct->ymin, rct->xmax, rct->ymax, - tab_curve_radius, roundboxtype, true, false, - is_active ? theme_col_back : theme_col_tab_inactive); + tab_curve_radius, roundboxtype, true, false, + is_active ? theme_col_back : theme_col_tab_inactive); } /* tab blackline */ diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index d4d3e1af1fd..2caf52cf8dc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -110,7 +110,7 @@ bool ui_but_menu_step_poll(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_MENU); - /* currenly only RNA buttons */ + /* currently only RNA buttons */ return ((but->menu_step_func != NULL) || (but->rnaprop && RNA_property_type(but->rnaprop) == PROP_ENUM)); } @@ -454,7 +454,7 @@ static uiTooltipData *ui_tooltip_data_from_button(bContext *C, uiBut *but) if (but->rnapoin.id.data) { ID *id = but->rnapoin.id.data; - if (id->lib) { + if (ID_IS_LINKED_DATABLOCK(id)) { BLI_snprintf(data->lines[data->totline], sizeof(data->lines[0]), TIP_("Library: %s"), id->lib->name); data->format[data->totline].color_id = UI_TIP_LC_NORMAL; data->totline++; @@ -3331,6 +3331,11 @@ void UI_popup_block_close(bContext *C, wmWindow *win, uiBlock *block) if (win) { UI_popup_handlers_remove(&win->modalhandlers, block->handle); ui_popup_block_free(C, block->handle); + + /* In the case we have nested popups, closing one may need to redraw anorher, see: T48874 */ + for (ARegion *ar = win->screen->regionbase.first; ar; ar = ar->next) { + ED_region_tag_refresh_ui(ar); + } } } } diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 423c48e5f55..8b41302b5bb 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -417,6 +417,11 @@ void uiStyleInit(void) blf_mono_font = -1; } + if (blf_mono_font_render != -1) { + BLF_unload_id(blf_mono_font_render); + blf_mono_font_render = -1; + } + font = U.uifonts.first; /* default builtin */ @@ -516,7 +521,12 @@ void uiStyleInit(void) BLF_size(blf_mono_font, 12 * U.pixelsize, 72); - /* second for rendering else we get threading problems */ + /** + * Second for rendering else we get threading problems, + * + * \note This isn't good that the render font depends on the preferences, + * keep for now though, since without this there is no way to display many unicode chars. + */ if (blf_mono_font_render == -1) blf_mono_font_render = BLF_load_mem_unique("monospace", monofont_ttf, monofont_size); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 9f0c4b16523..aec4065adaf 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -232,15 +232,17 @@ static uiBlock *id_search_menu(bContext *C, ARegion *ar, void *arg_litem) /* This is for browsing and editing the ID-blocks used */ /* for new/open operators */ -void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, PropertyRNA **prop) +void UI_context_active_but_prop_get_templateID( + bContext *C, + PointerRNA *r_ptr, PropertyRNA **r_prop) { TemplateID *template; ARegion *ar = CTX_wm_region(C); uiBlock *block; uiBut *but; - memset(ptr, 0, sizeof(*ptr)); - *prop = NULL; + memset(r_ptr, 0, sizeof(*r_ptr)); + *r_prop = NULL; if (!ar) return; @@ -251,8 +253,8 @@ void UI_context_active_but_prop_get_templateID(bContext *C, PointerRNA *ptr, Pro if ((but->flag & (UI_BUT_LAST_ACTIVE | UI_ACTIVE))) { if (but->func_argN) { template = but->func_argN; - *ptr = template->ptr; - *prop = template->prop; + *r_ptr = template->ptr; + *r_prop = template->prop; return; } } @@ -300,7 +302,7 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - if (id_make_local(id, false)) { + if (id_make_local(CTX_data_main(C), id, false, false)) { /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); @@ -453,7 +455,7 @@ static void template_ID( else { but = uiDefIconBut(block, UI_BTYPE_BUT, 0, ICON_LIBRARY_DATA_DIRECT, 0, 0, UI_UNIT_X, UI_UNIT_Y, NULL, 0, 0, 0, 0, TIP_("Direct linked library datablock, click to make local")); - if (!id_make_local(id, true /* test */) || (idfrom && idfrom->lib)) + if (!id_make_local(CTX_data_main(C), id, true /* test */, false) || (idfrom && idfrom->lib)) UI_but_flag_enable(but, UI_BUT_DISABLED); } @@ -473,7 +475,7 @@ static void template_ID( UI_but_funcN_set(but, template_id_cb, MEM_dupallocN(template), SET_INT_IN_POINTER(UI_ID_ALONE)); if (/* test only */ - (id_copy(id, NULL, true) == false) || + (id_copy(CTX_data_main(C), id, NULL, true) == false) || (idfrom && idfrom->lib) || (!editable) || /* object in editmode - don't change data */ @@ -972,7 +974,7 @@ static uiLayout *draw_modifier( } UI_block_lock_clear(block); - UI_block_lock_set(block, ob && ob->id.lib, ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(block, ob && ID_IS_LINKED_DATABLOCK(ob), ERROR_LIBDATA_MESSAGE); if (!ELEM(md->type, eModifierType_Fluidsim, eModifierType_Softbody, eModifierType_ParticleSystem, eModifierType_Cloth, eModifierType_Smoke)) @@ -1019,7 +1021,7 @@ uiLayout *uiTemplateModifier(uiLayout *layout, bContext *C, PointerRNA *ptr) return NULL; } - UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE); /* find modifier and draw it */ cageIndex = modifiers_getCageIndex(scene, ob, &lastCageIndex, 0); @@ -1247,7 +1249,7 @@ uiLayout *uiTemplateConstraint(uiLayout *layout, PointerRNA *ptr) return NULL; } - UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ob->id.lib), ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(uiLayoutGetBlock(layout), (ob && ID_IS_LINKED_DATABLOCK(ob)), ERROR_LIBDATA_MESSAGE); /* hrms, the temporal constraint should not draw! */ if (con->type == CONSTRAINT_TYPE_KINEMATIC) { @@ -1609,7 +1611,7 @@ void uiTemplateColorRamp(uiLayout *layout, PointerRNA *ptr, const char *propname block = uiLayoutAbsoluteBlock(layout); id = cptr.id.data; - UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE); colorband_buttons_layout(layout, block, cptr.data, &rect, cb, expand); @@ -2261,7 +2263,7 @@ void uiTemplateCurveMapping( cb->prop = prop; id = cptr.id.data; - UI_block_lock_set(block, (id && id->lib), ERROR_LIBDATA_MESSAGE); + UI_block_lock_set(block, (id && ID_IS_LINKED_DATABLOCK(id)), ERROR_LIBDATA_MESSAGE); curvemap_buttons_layout(layout, &cptr, type, levels, brush, neg_slope, cb); diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 5098e701638..02981b543f3 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3042,7 +3042,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) { /* Now we reduce alpha of the inner color (i.e. the color shown) - * so that this setting can look greyed out, while retaining + * so that this setting can look grayed out, while retaining * the checkboard (for transparent values). This is needed * here as the effects of ui_widget_color_disabled() are overwritten. */ diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index e2e2413c717..c8ff335f2a0 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -1011,6 +1011,8 @@ void ui_theme_init_default(void) rgba_char_args_set(btheme->tact.keyborder, 0, 0, 0, 255); rgba_char_args_set(btheme->tact.keyborder_select, 0, 0, 0, 255); + btheme->tact.keyframe_scale_fac = 1.0f; + /* space nla */ btheme->tnla = btheme->tact; @@ -1471,6 +1473,30 @@ void UI_GetThemeColor3ubv(int colorid, unsigned char col[3]) col[2] = cp[2]; } +/* get the color, range 0.0-1.0, complete with shading offset */ +void UI_GetThemeColorShade4fv(int colorid, int offset, float col[4]) +{ + int r, g, b, a; + const unsigned char *cp; + + cp = UI_ThemeGetColorPtr(theme_active, theme_spacetype, colorid); + + r = offset + (int) cp[0]; + CLAMP(r, 0, 255); + g = offset + (int) cp[1]; + CLAMP(g, 0, 255); + b = offset + (int) cp[2]; + CLAMP(b, 0, 255); + + a = (int) cp[3]; /* no shading offset... */ + CLAMP(a, 0, 255); + + col[0] = ((float)r) / 255.0f; + col[1] = ((float)g) / 255.0f; + col[2] = ((float)b) / 255.0f; + col[3] = ((float)a) / 255.0f; +} + /* get the color, in char pointer */ void UI_GetThemeColor4ubv(int colorid, unsigned char col[4]) { @@ -2699,6 +2725,14 @@ void init_userdef_do_versions(void) } } } + + if (!USER_VERSION_ATLEAST(277, 2)) { + bTheme *btheme; + for (btheme = U.themes.first; btheme; btheme = btheme->next) { + if (btheme->tact.keyframe_scale_fac < 0.1f) + btheme->tact.keyframe_scale_fac = 1.0f; + } + } /** * Include next version bump. diff --git a/source/blender/editors/io/io_collada.c b/source/blender/editors/io/io_collada.c index 3803221b496..b74c4b5f526 100644 --- a/source/blender/editors/io/io_collada.c +++ b/source/blender/editors/io/io_collada.c @@ -400,7 +400,7 @@ static int wm_collada_import_exec(bContext *C, wmOperator *op) C, filename, import_units, find_chains, - auto_connect, + auto_connect, fix_orientation, min_chain_length)) { diff --git a/source/blender/editors/mask/mask_editaction.c b/source/blender/editors/mask/mask_editaction.c index bcf9ee5c88d..16147bdc7f8 100644 --- a/source/blender/editors/mask/mask_editaction.c +++ b/source/blender/editors/mask/mask_editaction.c @@ -201,6 +201,36 @@ void ED_masklayer_frames_select_border(MaskLayer *masklay, float min, float max, } } +/* select the frames in this layer that occur within the lasso/circle region specified */ +void ED_masklayer_frames_select_region(KeyframeEditData *ked, MaskLayer *masklay, short tool, short select_mode) +{ + MaskLayerShape *masklay_shape; + + if (masklay == NULL) + return; + + /* only select frames which are within the region */ + for (masklay_shape = masklay->splines_shapes.first; masklay_shape; masklay_shape = masklay_shape->next) { + /* construct a dummy point coordinate to do this testing with */ + float pt[2] = {0}; + + pt[0] = masklay_shape->frame; + pt[1] = ked->channel_y; + + /* check the necessary regions */ + if (tool == BEZT_OK_CHANNEL_LASSO) { + /* Lasso */ + if (keyframe_region_lasso_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + else if (tool == BEZT_OK_CHANNEL_CIRCLE) { + /* Circle */ + if (keyframe_region_circle_test(ked->data, pt)) + masklayshape_select(masklay_shape, select_mode); + } + } +} + /* ***************************************** */ /* Frame Editing Tools */ diff --git a/source/blender/editors/mesh/editface.c b/source/blender/editors/mesh/editface.c index 01be8f848aa..c4e87614732 100644 --- a/source/blender/editors/mesh/editface.c +++ b/source/blender/editors/mesh/editface.c @@ -53,6 +53,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_draw.h" #include "GPU_buffers.h" /* own include */ @@ -433,7 +434,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, bool select, bool exten if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/mesh/editmesh_extrude.c b/source/blender/editors/mesh/editmesh_extrude.c index 1dfb1cddd2c..d4c49833c2c 100644 --- a/source/blender/editors/mesh/editmesh_extrude.c +++ b/source/blender/editors/mesh/editmesh_extrude.c @@ -287,8 +287,7 @@ static int edbm_extrude_repeat_exec(bContext *C, wmOperator *op) short a; /* dvec */ - normalize_v3_v3(dvec, rv3d->persinv[2]); - mul_v3_fl(dvec, offs); + normalize_v3_v3_length(dvec, rv3d->persinv[2], offs); /* base correction */ copy_m3_m4(bmat, obedit->obmat); diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 69588928253..281a8b2a02d 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -563,7 +563,7 @@ static BMEdge *bm_face_split_edge_find( if (UNLIKELY(BM_edge_exists(v_pivot, l_iter->e->v1) || BM_edge_exists(v_pivot, l_iter->e->v2))) { - /* very unlikley but will cause complications splicing the verts together, + /* very unlikely but will cause complications splicing the verts together, * so just skip this case */ ok = false; } diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 0fd56fbcc4e..a84b8d9dcc8 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2283,7 +2283,7 @@ static void knife_make_face_cuts(KnifeTool_OpData *kcd, BMFace *f, ListBase *kfe BMEdge **edge_array = BLI_array_alloca(edge_array, edge_array_len); - /* point to knife edges we've created edges in, edge_array aligned */ + /* point to knife edges we've created edges in, edge_array aligned */ KnifeEdge **kfe_array = BLI_array_alloca(kfe_array, edge_array_len); BLI_assert(BLI_gset_size(kcd->edgenet.edge_visit) == 0); diff --git a/source/blender/editors/mesh/editmesh_rip.c b/source/blender/editors/mesh/editmesh_rip.c index 9e71e646b1a..2cdb00286aa 100644 --- a/source/blender/editors/mesh/editmesh_rip.c +++ b/source/blender/editors/mesh/editmesh_rip.c @@ -153,8 +153,7 @@ static float edbm_rip_edge_side_measure( ED_view3d_project_float_v2_m4(ar, e->v2->co, e_v2_co, projectMat); sub_v2_v2v2(vec, cent, mid); - normalize_v2(vec); - mul_v2_fl(vec, 0.01f); + normalize_v2_length(vec, 0.01f); /* rather then adding to both verts, subtract from the mouse */ sub_v2_v2v2(fmval_tweak, fmval, vec); @@ -396,7 +395,7 @@ static void edbm_ripsel_deselect_helper(BMesh *bm, EdgeLoopPair *eloop_pairs, * return an un-ordered array of loop pairs * use for rebuilding face-fill * - * \note the method currenly used fails for edges with 3+ face users and gives + * \note the method currently used fails for edges with 3+ face users and gives * nasty holes in the mesh, there isnt a good way of knowing ahead of time * which loops will be split apart (its possible to figure out but quite involved). * So for now this is a known limitation of current rip-fill option. @@ -463,7 +462,7 @@ static void edbm_tagged_loop_pairs_do_fill_faces(BMesh *bm, UnorderedLoopPair *u if ((ulp->l_pair[0] && ulp->l_pair[1]) && (ulp->l_pair[0]->e != ulp->l_pair[1]->e)) { - /* time has come to make a face! */ + /* time has come to make a face! */ BMVert *v_shared = BM_edge_share_vert(ulp->l_pair[0]->e, ulp->l_pair[1]->e); BMFace *f, *f_example = ulp->l_pair[0]->f; BMLoop *l_iter; diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 84ae35fae6e..5d5731a7e16 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -2453,7 +2453,7 @@ static void select_linked_delimit_begin(BMesh *bm, int delimit) const bool is_walk_ok = ( (select_linked_delimit_test(e, delimit, &delimit_data) == false)); - BMO_elem_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); + BMO_edge_flag_set(bm, e, BMO_ELE_TAG, is_walk_ok); } } } @@ -2496,7 +2496,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) if (delimit) { BMEdge *e; BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { - if (!BMO_elem_flag_test(bm, e, BMO_ELE_TAG)) { + if (!BMO_edge_flag_test(bm, e, BMO_ELE_TAG)) { BM_elem_flag_disable(e->v1, BM_ELEM_TAG); BM_elem_flag_disable(e->v2, BM_ELEM_TAG); } @@ -2552,7 +2552,7 @@ static int edbm_select_linked_exec(bContext *C, wmOperator *op) BM_ITER_MESH (e, &iter, em->bm, BM_EDGES_OF_MESH) { BM_elem_flag_set( e, BM_ELEM_TAG, - (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_elem_flag_test(bm, e, BMO_ELE_TAG))); + (BM_elem_flag_test(e, BM_ELEM_SELECT) && BMO_edge_flag_test(bm, e, BMO_ELE_TAG))); } } else { diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index efe179790da..3a7a8fb883b 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -49,6 +49,7 @@ #include "BKE_material.h" #include "BKE_context.h" +#include "BKE_deform.h" #include "BKE_depsgraph.h" #include "BKE_report.h" #include "BKE_texture.h" @@ -79,6 +80,8 @@ #include "mesh_intern.h" /* own include */ +#include "bmesh_tools.h" + #define USE_FACE_CREATE_SEL_EXTEND static int edbm_subdivide_exec(bContext *C, wmOperator *op) @@ -2910,7 +2913,7 @@ static int edbm_knife_cut_exec(bContext *C, wmOperator *op) } } - BMO_elem_flag_set(bm, be, ELE_EDGE_CUT, is_cut); + BMO_edge_flag_set(bm, be, ELE_EDGE_CUT, is_cut); } @@ -2982,7 +2985,9 @@ static Base *mesh_separate_tagged(Main *bmain, Scene *scene, Base *base_old, BMe Object *obedit = base_old->object; BMesh *bm_new; - bm_new = BM_mesh_create(&bm_mesh_allocsize_default); + bm_new = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_elem_toolflags_ensure(bm_new); /* needed for 'duplicate' bmo */ CustomData_copy(&bm_old->vdata, &bm_new->vdata, CD_MASK_BMESH, CD_CALLOC, 0); @@ -3290,11 +3295,13 @@ static int edbm_separate_exec(bContext *C, wmOperator *op) Object *ob = base_iter->object; if (ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->id.lib == NULL) { + if (!ID_IS_LINKED_DATABLOCK(me)) { BMesh *bm_old = NULL; int retval_iter = 0; - bm_old = BM_mesh_create(&bm_mesh_allocsize_default); + bm_old = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_bm_from_me(bm_old, me, (&(struct BMeshFromMeshParams){0})); @@ -3975,6 +3982,196 @@ void MESH_OT_tris_convert_to_quads(wmOperatorType *ot) join_triangle_props(ot); } + +/* -------------------------------------------------------------------- */ + +/** \name Decimate + * + * \note The function to decimate is intended for use as a modifier, + * while its handy allow access as a tool - this does cause access to be a little awkward + * (passing selection as weights for eg). + * + * \{ */ + +static int edbm_decimate_exec(bContext *C, wmOperator *op) +{ + Object *obedit = CTX_data_edit_object(C); + BMEditMesh *em = BKE_editmesh_from_object(obedit); + BMesh *bm = em->bm; + + const float ratio = RNA_float_get(op->ptr, "ratio"); + bool use_vertex_group = RNA_boolean_get(op->ptr, "use_vertex_group"); + const float vertex_group_factor = RNA_float_get(op->ptr, "vertex_group_factor"); + const bool invert_vertex_group = RNA_boolean_get(op->ptr, "invert_vertex_group"); + const bool use_symmetry = RNA_boolean_get(op->ptr, "use_symmetry"); + const float symmetry_eps = 0.00002f; + const int symmetry_axis = use_symmetry ? RNA_enum_get(op->ptr, "symmetry_axis") : -1; + + /* nop */ + if (ratio == 1.0f) { + return OPERATOR_FINISHED; + } + + float *vweights = MEM_mallocN(sizeof(*vweights) * bm->totvert, __func__); + { + const int cd_dvert_offset = CustomData_get_offset(&bm->vdata, CD_MDEFORMVERT); + const int defbase_act = obedit->actdef - 1; + + if (use_vertex_group && (cd_dvert_offset == -1)) { + BKE_report(op->reports, RPT_WARNING, "No active vertex group"); + use_vertex_group = false; + } + + BMIter iter; + BMVert *v; + int i; + BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) { + float weight = 0.0f; + if (BM_elem_flag_test(v, BM_ELEM_SELECT)) { + if (use_vertex_group) { + const MDeformVert *dv = BM_ELEM_CD_GET_VOID_P(v, cd_dvert_offset); + weight = defvert_find_weight(dv, defbase_act); + if (invert_vertex_group) { + weight = 1.0 - weight; + } + } + else { + weight = 1.0f; + } + } + + vweights[i] = weight; + BM_elem_index_set(v, i); /* set_inline */ + } + bm->elem_index_dirty &= ~BM_VERT; + } + + float ratio_adjust; + + if ((bm->totface == bm->totfacesel) || (ratio == 0.0f)) { + ratio_adjust = ratio; + } + else { + /** + * Calculate a new ratio based on faces that could be remoevd during decimation. + * needed so 0..1 has a meaningful range when operating on the selection. + * + * This doesn't have to be totally accurate, + * but needs to be greater than the number of selected faces + */ + + int totface_basis = 0; + int totface_adjacent = 0; + BMIter iter; + BMFace *f; + BM_ITER_MESH (f, &iter, bm, BM_FACES_OF_MESH) { + /* count faces during decimation, ngons are triangulated */ + const int f_len = f->len > 4 ? (f->len - 2) : 1; + totface_basis += f_len; + + BMLoop *l_iter, *l_first; + l_iter = l_first = BM_FACE_FIRST_LOOP(f); + do { + if (vweights[BM_elem_index_get(l_iter->v)] != 0.0f) { + totface_adjacent += f_len; + break; + } + } while ((l_iter = l_iter->next) != l_first); + } + + ratio_adjust = ratio; + ratio_adjust = 1.0f - ratio_adjust; + ratio_adjust *= (float)totface_adjacent / (float)totface_basis; + ratio_adjust = 1.0f - ratio_adjust; + } + + BM_mesh_decimate_collapse( + em->bm, ratio_adjust, vweights, vertex_group_factor, false, + symmetry_axis, symmetry_eps); + + MEM_freeN(vweights); + + { + short selectmode = em->selectmode; + if ((selectmode & (SCE_SELECT_VERTEX | SCE_SELECT_EDGE)) == 0) { + /* ensure we flush edges -> faces */ + selectmode |= SCE_SELECT_EDGE; + } + EDBM_selectmode_flush_ex(em, selectmode); + } + + EDBM_update_generic(em, true, true); + + return OPERATOR_FINISHED; +} + + +static bool edbm_decimate_check(bContext *UNUSED(C), wmOperator *UNUSED(op)) +{ + return true; +} + + +static void edbm_decimate_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout, *box, *row, *col; + PointerRNA ptr; + + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + + uiItemR(layout, &ptr, "ratio", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + uiItemR(box, &ptr, "use_vertex_group", 0, NULL, ICON_NONE); + col = uiLayoutColumn(box, false); + uiLayoutSetActive(col, RNA_boolean_get(&ptr, "use_vertex_group")); + uiItemR(col, &ptr, "vertex_group_factor", 0, NULL, ICON_NONE); + uiItemR(col, &ptr, "invert_vertex_group", 0, NULL, ICON_NONE); + + box = uiLayoutBox(layout); + uiItemR(box, &ptr, "use_symmetry", 0, NULL, ICON_NONE); + row = uiLayoutRow(box, true); + uiLayoutSetActive(row, RNA_boolean_get(&ptr, "use_symmetry")); + uiItemR(row, &ptr, "symmetry_axis", UI_ITEM_R_EXPAND, NULL, ICON_NONE); +} + + +void MESH_OT_decimate(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Decimate Geometry"; + ot->idname = "MESH_OT_decimate"; + ot->description = "Simplify geometry by collapsing edges"; + + /* api callbacks */ + ot->exec = edbm_decimate_exec; + ot->check = edbm_decimate_check; + ot->ui = edbm_decimate_ui; + ot->poll = ED_operator_editmesh; + + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Note, keep in sync with 'rna_def_modifier_decimate' */ + RNA_def_float(ot->srna, "ratio", 1.0f, 0.0f, 1.0f, "Ratio", "", 0.0f, 1.0f); + + RNA_def_boolean(ot->srna, "use_vertex_group", false, "Vertex Group", + "Use active vertex group as an influence"); + RNA_def_float(ot->srna, "vertex_group_factor", 1.0f, 0.0f, 1000.0f, "Weight", + "Vertex group strength", 0.0f, 10.0f); + RNA_def_boolean(ot->srna, "invert_vertex_group", false, "Invert", + "Invert vertex group influence"); + + RNA_def_boolean(ot->srna, "use_symmetry", false, "Symmetry", + "Maintain symmetry on an axis"); + + RNA_def_enum(ot->srna, "symmetry_axis", rna_enum_axis_xyz_items, 1, "Axis", "Axis of symmetry"); +} + +/** \} */ + + /* -------------------------------------------------------------------- */ /* Dissolve */ diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index 8b16b2a977e..c9814d189a4 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -114,7 +114,7 @@ static struct { TaskPool *task_pool; #endif -} um_arraystore = {NULL}; +} um_arraystore = {{NULL}}; static void um_arraystore_cd_compact( struct CustomData *cdata, const size_t data_len, @@ -563,7 +563,9 @@ static void undoMesh_to_editbtMesh(void *um_v, void *em_v, void *obdata) EDBM_mesh_free(em); - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = true,})); BM_mesh_bm_from_me( bm, &um->me, (&(struct BMeshFromMeshParams){ @@ -637,7 +639,7 @@ static void free_undo(void *um_v) MEM_freeN(me->key); } - BKE_mesh_free(me, false); + BKE_mesh_free(me); MEM_freeN(me); } diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 99be37845ee..4fc61e0912e 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -354,7 +354,9 @@ void EDBM_mesh_make(ToolSettings *ts, Object *ob, const bool add_key_index) BKE_mesh_convert_mfaces_to_mpolys(me); } - bm = BKE_mesh_to_bmesh(me, ob, add_key_index); + bm = BKE_mesh_to_bmesh( + me, ob, add_key_index, + &((struct BMeshCreateParams){.use_toolflags = true,})); if (me->edit_btmesh) { /* this happens when switching shape keys */ @@ -399,10 +401,25 @@ void EDBM_mesh_load(Object *ob) BKE_mesh_tessface_calc(me); #endif - /* free derived mesh. usually this would happen through depsgraph but there + /* Free derived mesh. usually this would happen through depsgraph but there * are exceptions like file save that will not cause this, and we want to - * avoid ending up with an invalid derived mesh then */ - BKE_object_free_derived_caches(ob); + * avoid ending up with an invalid derived mesh then. + * + * Do it for all objects which shares the same mesh datablock, since their + * derived meshes might also be referencing data which was just freed, + * + * Annoying enough, but currently seems most efficient way to avoid access + * of freed data on scene update, especially in cases when there are dependency + * cycles. + */ + for (Object *other_object = G.main->object.first; + other_object != NULL; + other_object = other_object->id.next) + { + if (other_object->data == ob->data) { + BKE_object_free_derived_caches(other_object); + } + } } /** @@ -1423,13 +1440,9 @@ bool BMBVH_EdgeVisible(struct BMBVHTree *tree, BMEdge *e, ARegion *ar, View3D *v sub_v3_v3v3(dir2, origin, co2); sub_v3_v3v3(dir3, origin, co3); - normalize_v3(dir1); - normalize_v3(dir2); - normalize_v3(dir3); - - mul_v3_fl(dir1, epsilon); - mul_v3_fl(dir2, epsilon); - mul_v3_fl(dir3, epsilon); + normalize_v3_length(dir1, epsilon); + normalize_v3_length(dir2, epsilon); + normalize_v3_length(dir3, epsilon); /* offset coordinates slightly along view vectors, to avoid * hitting the faces that own the edge.*/ diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index e0ddc017e93..772bb1bd308 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -511,7 +511,7 @@ static int layers_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data)); } static int mesh_uv_texture_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -759,7 +759,7 @@ static int mesh_customdata_mask_clear_poll(bContext *C) return false; } - if (me->id.lib == NULL) { + if (!ID_IS_LINKED_DATABLOCK(me)) { CustomData *data = GET_CD_DATA(me, vdata); if (CustomData_has_layer(data, CD_PAINT_MASK)) { return true; @@ -813,7 +813,7 @@ static int mesh_customdata_skin_state(bContext *C) if (ob && ob->type == OB_MESH) { Mesh *me = ob->data; - if (me->id.lib == NULL) { + if (!ID_IS_LINKED_DATABLOCK(me)) { CustomData *data = GET_CD_DATA(me, vdata); return CustomData_has_layer(data, CD_MVERT_SKIN); } diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index 08b4d1aee45..300b21a052d 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -216,6 +216,7 @@ void MESH_OT_fill_holes(struct wmOperatorType *ot); void MESH_OT_beautify_fill(struct wmOperatorType *ot); void MESH_OT_quads_convert_to_tris(struct wmOperatorType *ot); void MESH_OT_tris_convert_to_quads(struct wmOperatorType *ot); +void MESH_OT_decimate(struct wmOperatorType *ot); void MESH_OT_dissolve_verts(struct wmOperatorType *ot); void MESH_OT_dissolve_edges(struct wmOperatorType *ot); void MESH_OT_dissolve_faces(struct wmOperatorType *ot); diff --git a/source/blender/editors/mesh/mesh_ops.c b/source/blender/editors/mesh/mesh_ops.c index 2853ae3a84c..697a92f36d1 100644 --- a/source/blender/editors/mesh/mesh_ops.c +++ b/source/blender/editors/mesh/mesh_ops.c @@ -106,6 +106,7 @@ void ED_operatortypes_mesh(void) WM_operatortype_append(MESH_OT_beautify_fill); WM_operatortype_append(MESH_OT_quads_convert_to_tris); WM_operatortype_append(MESH_OT_tris_convert_to_quads); + WM_operatortype_append(MESH_OT_decimate); WM_operatortype_append(MESH_OT_dissolve_verts); WM_operatortype_append(MESH_OT_dissolve_edges); WM_operatortype_append(MESH_OT_dissolve_faces); diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index 1b2d4b7c130..b26989113d4 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -172,7 +172,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) */ if (key) { /* make a duplicate copy that will only be used here... (must remember to free it!) */ - nkey = BKE_key_copy(key); + nkey = BKE_key_copy(bmain, key); /* for all keys in old block, clear data-arrays */ for (kb = key->block.first; kb; kb = kb->next) { @@ -540,7 +540,7 @@ int join_mesh_exec(bContext *C, wmOperator *op) if (matmap) MEM_freeN(matmap); /* other mesh users */ - test_object_materials(bmain, (ID *)me); + test_all_objects_materials(bmain, (ID *)me); /* free temp copy of destination shapekeys (if applicable) */ if (nkey) { @@ -564,21 +564,10 @@ int join_mesh_exec(bContext *C, wmOperator *op) BKE_key_sort(key); } - DAG_relations_tag_update(bmain); // removed objects, need to rebuild dag -#if 0 - ED_object_editmode_enter(C, EM_WAITCURSOR); - ED_object_editmode_exit(C, EM_FREEDATA | EM_WAITCURSOR | EM_DO_UNDO); -#else - /* toggle editmode using lower level functions so this can be called from python */ - EDBM_mesh_make(scene->toolsettings, ob, false); - EDBM_mesh_load(ob); - EDBM_mesh_free(me->edit_btmesh); - MEM_freeN(me->edit_btmesh); - me->edit_btmesh = NULL; DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA); -#endif + WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); return OPERATOR_FINISHED; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 09c9442db54..cc628210e20 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -73,6 +73,7 @@ #include "BKE_lamp.h" #include "BKE_lattice.h" #include "BKE_library.h" +#include "BKE_library_query.h" #include "BKE_key.h" #include "BKE_main.h" #include "BKE_material.h" @@ -1108,12 +1109,18 @@ static void object_delete_check_glsl_update(Object *ob) /* note: now unlinks constraints as well */ void ED_base_object_free_and_unlink(Main *bmain, Scene *scene, Base *base) { - DAG_id_type_tag(bmain, ID_OB); + if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + /* We cannot delete indirectly used object... */ + printf("WARNING, undeletable object '%s', should have been catched before reaching this function!", + base->object->id.name + 2); + return; + } + BKE_scene_base_unlink(scene, base); object_delete_check_glsl_update(base->object); BKE_libblock_free_us(bmain, base->object); - if (scene->basact == base) scene->basact = NULL; MEM_freeN(base); + DAG_id_type_tag(bmain, ID_OB); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -1130,6 +1137,19 @@ static int object_delete_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Base *, base, selected_bases) { + const bool is_indirectly_used = BKE_library_ID_is_indirectly_used(bmain, base->object); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + /* Can this case ever happen? */ + BKE_reportf(op->reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + continue; + } + else if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(op->reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + continue; + } + /* deselect object -- it could be used in other scenes */ base->object->flag &= ~SELECT; @@ -1142,9 +1162,15 @@ static int object_delete_exec(bContext *C, wmOperator *op) Base *base_other; for (scene_iter = bmain->scene.first; scene_iter; scene_iter = scene_iter->id.next) { - if (scene_iter != scene && !(scene_iter->id.lib)) { + if (scene_iter != scene && !ID_IS_LINKED_DATABLOCK(scene_iter)) { base_other = BKE_scene_base_find(scene_iter, base->object); if (base_other) { + if (is_indirectly_used && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(op->reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene_iter->id.name + 2); + break; + } ED_base_object_free_and_unlink(bmain, scene_iter, base_other); } } @@ -1273,7 +1299,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, for (dob = lb->first; dob; dob = dob->next) { Base *basen; - Object *ob = BKE_object_copy(dob->ob); + Object *ob = BKE_object_copy(bmain, dob->ob); /* font duplis can have a totcol without material, we get them from parent * should be implemented better... @@ -1288,7 +1314,7 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, basen->object = ob; /* make sure apply works */ - BKE_animdata_free(&ob->id); + BKE_animdata_free(&ob->id, true); ob->adt = NULL; /* Proxies are not to be copied. */ @@ -1380,7 +1406,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } - /* The same how BKE_object_unlink detects which object proxies to clear. */ if (base->object->transflag & OB_DUPLIGROUP && base->object->dup_group) { for (object = bmain->object.first; object; object = object->id.next) { if (object->proxy_group == base->object) { @@ -1490,11 +1515,12 @@ static int convert_poll(bContext *C) Object *obact = CTX_data_active_object(C); Scene *scene = CTX_data_scene(C); - return (!scene->id.lib && obact && scene->obedit != obact && (obact->flag & SELECT) && !(obact->id.lib)); + return (!ID_IS_LINKED_DATABLOCK(scene) && obact && scene->obedit != obact && + (obact->flag & SELECT) && !ID_IS_LINKED_DATABLOCK(obact)); } /* Helper for convert_exec */ -static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob) +static Base *duplibase_for_convert(Main *bmain, Scene *scene, Base *base, Object *ob) { Object *obn; Base *basen; @@ -1503,7 +1529,7 @@ static Base *duplibase_for_convert(Scene *scene, Base *base, Object *ob) ob = base->object; } - obn = BKE_object_copy(ob); + obn = BKE_object_copy(bmain, ob); DAG_id_tag_update(&ob->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); basen = MEM_mallocN(sizeof(Base), "duplibase"); @@ -1583,7 +1609,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1591,7 +1617,7 @@ static int convert_exec(bContext *C, wmOperator *op) id_us_min(&me->id); /* make a new copy of the mesh */ - newob->data = BKE_mesh_copy(me); + newob->data = BKE_mesh_copy(bmain, me); } else { newob = ob; @@ -1608,7 +1634,7 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, base, NULL); newob = basen->object; /* decrement original mesh's usage count */ @@ -1616,7 +1642,7 @@ static int convert_exec(bContext *C, wmOperator *op) id_us_min(&me->id); /* make a new copy of the mesh */ - newob->data = BKE_mesh_copy(me); + newob->data = BKE_mesh_copy(bmain, me); } else { newob = ob; @@ -1640,14 +1666,14 @@ static int convert_exec(bContext *C, wmOperator *op) ob->flag |= OB_DONE; if (keep_original) { - basen = duplibase_for_convert(scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, base, NULL); newob = basen->object; /* decrement original curve's usage count */ id_us_min(&((Curve *)newob->data)->id); /* make a new copy of the curve */ - newob->data = BKE_curve_copy(ob->data); + newob->data = BKE_curve_copy(bmain, ob->data); } else { newob = ob; @@ -1711,14 +1737,14 @@ static int convert_exec(bContext *C, wmOperator *op) if (target == OB_MESH) { if (keep_original) { - basen = duplibase_for_convert(scene, base, NULL); + basen = duplibase_for_convert(bmain, scene, base, NULL); newob = basen->object; /* decrement original curve's usage count */ id_us_min(&((Curve *)newob->data)->id); /* make a new copy of the curve */ - newob->data = BKE_curve_copy(ob->data); + newob->data = BKE_curve_copy(bmain, ob->data); } else { newob = ob; @@ -1746,7 +1772,7 @@ static int convert_exec(bContext *C, wmOperator *op) if (!(baseob->flag & OB_DONE)) { baseob->flag |= OB_DONE; - basen = duplibase_for_convert(scene, base, baseob); + basen = duplibase_for_convert(bmain, scene, base, baseob); newob = basen->object; mb = newob->data; @@ -1884,7 +1910,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ; /* nothing? */ } else { - obn = BKE_object_copy(ob); + obn = BKE_object_copy(bmain, ob); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); basen = MEM_mallocN(sizeof(Base), "duplibase"); @@ -1915,7 +1941,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (id) { ID_NEW_US(obn->mat[a]) else - obn->mat[a] = BKE_material_copy(obn->mat[a]); + obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]); id_us_min(id); if (dupflag & USER_DUP_ACT) { @@ -1931,7 +1957,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (id) { ID_NEW_US(psys->part) else - psys->part = BKE_particlesettings_copy(psys->part); + psys->part = BKE_particlesettings_copy(bmain, psys->part); if (dupflag & USER_DUP_ACT) { BKE_animdata_copy_id_action(&psys->part->id); @@ -1950,7 +1976,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_MESH) { ID_NEW_US2(obn->data) else { - obn->data = BKE_mesh_copy(obn->data); + obn->data = BKE_mesh_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -1960,7 +1986,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_CURVE) { ID_NEW_US2(obn->data) else { - obn->data = BKE_curve_copy(obn->data); + obn->data = BKE_curve_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -1970,7 +1996,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_SURF) { ID_NEW_US2(obn->data) else { - obn->data = BKE_curve_copy(obn->data); + obn->data = BKE_curve_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -1980,7 +2006,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_FONT) { ID_NEW_US2(obn->data) else { - obn->data = BKE_curve_copy(obn->data); + obn->data = BKE_curve_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -1990,7 +2016,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_MBALL) { ID_NEW_US2(obn->data) else { - obn->data = BKE_mball_copy(obn->data); + obn->data = BKE_mball_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -2000,7 +2026,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_LAMP) { ID_NEW_US2(obn->data) else { - obn->data = BKE_lamp_copy(obn->data); + obn->data = BKE_lamp_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -2013,7 +2039,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_ARM) { ID_NEW_US2(obn->data) else { - obn->data = BKE_armature_copy(obn->data); + obn->data = BKE_armature_copy(bmain, obn->data); BKE_pose_rebuild(obn, obn->data); didit = 1; } @@ -2024,7 +2050,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag != 0) { ID_NEW_US2(obn->data) else { - obn->data = BKE_lattice_copy(obn->data); + obn->data = BKE_lattice_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -2034,7 +2060,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag != 0) { ID_NEW_US2(obn->data) else { - obn->data = BKE_camera_copy(obn->data); + obn->data = BKE_camera_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -2044,7 +2070,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag != 0) { ID_NEW_US2(obn->data) else { - obn->data = BKE_speaker_copy(obn->data); + obn->data = BKE_speaker_copy(bmain, obn->data); didit = 1; } id_us_min(id); @@ -2083,7 +2109,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (id) { ID_NEW_US((*matarar)[a]) else - (*matarar)[a] = BKE_material_copy((*matarar)[a]); + (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]); id_us_min(id); } } @@ -2280,7 +2306,7 @@ static int join_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (!ob || ob->id.lib) return 0; + if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0; if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_ARMATURE)) return ED_operator_screenactive(C); @@ -2333,7 +2359,7 @@ static int join_shapes_poll(bContext *C) { Object *ob = CTX_data_active_object(C); - if (!ob || ob->id.lib) return 0; + if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0; /* only meshes supported at the moment */ if (ob->type == OB_MESH) diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index efd1ebbd51b..db8a4c1960f 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -584,7 +584,7 @@ static int edit_constraint_poll_generic(bContext *C, StructRNA *rna_type) return 0; } - if (ob->id.lib || (ptr.id.data && ((ID *)ptr.id.data)->lib)) { + if (ID_IS_LINKED_DATABLOCK(ob) || (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data))) { CTX_wm_operator_poll_msg_set(C, "Cannot edit library data"); return 0; } @@ -1560,12 +1560,12 @@ void OBJECT_OT_constraints_copy(wmOperatorType *ot) /************************ add constraint operators *********************/ /* get the Object and/or PoseChannel to use as target */ -static short get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, short add) +static bool get_new_constraint_target(bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); bPoseChannel *pchanact = BKE_pose_channel_active(obact); - short only_curve = 0, only_mesh = 0, only_ob = 0; - short found = 0; + bool only_curve = false, only_mesh = false, only_ob = false; + bool found = false; /* clear tar_ob and tar_pchan fields before use * - assume for now that both always exist... @@ -1585,7 +1585,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_ROTLIMIT: case CONSTRAINT_TYPE_SIZELIMIT: case CONSTRAINT_TYPE_SAMEVOL: - return 0; + return false; /* restricted target-type constraints -------------- */ /* NOTE: for these, we cannot try to add a target object if no valid ones are found, since that doesn't work */ @@ -1593,26 +1593,26 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o case CONSTRAINT_TYPE_CLAMPTO: case CONSTRAINT_TYPE_FOLLOWPATH: case CONSTRAINT_TYPE_SPLINEIK: - only_curve = 1; - only_ob = 1; - add = 0; + only_curve = true; + only_ob = true; + add = false; break; /* mesh only? */ case CONSTRAINT_TYPE_SHRINKWRAP: - only_mesh = 1; - only_ob = 1; - add = 0; + only_mesh = true; + only_ob = true; + add = false; break; /* object only - add here is ok? */ case CONSTRAINT_TYPE_RIGIDBODYJOINT: - only_ob = 1; + only_ob = true; break; } /* if the active Object is Armature, and we can search for bones, do so... */ - if ((obact->type == OB_ARMATURE) && (only_ob == 0)) { + if ((obact->type == OB_ARMATURE) && (only_ob == false)) { /* search in list of selected Pose-Channels for target */ CTX_DATA_BEGIN (C, bPoseChannel *, pchan, selected_pose_bones) { @@ -1620,7 +1620,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o if (pchan != pchanact) { *tar_ob = obact; *tar_pchan = pchan; - found = 1; + found = true; break; } @@ -1629,36 +1629,50 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o } /* if not yet found, try selected Objects... */ - if (found == 0) { + if (found == false) { /* search in selected objects context */ CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { /* just use the first object we encounter (that isn't the active object) * and which fulfills the criteria for the object-target that we've got */ - if ((ob != obact) && - ((!only_curve) || (ob->type == OB_CURVE)) && - ((!only_mesh) || (ob->type == OB_MESH))) - { - /* set target */ - *tar_ob = ob; - found = 1; - - /* perform some special operations on the target */ - if (only_curve) { - /* Curve-Path option must be enabled for follow-path constraints to be able to work */ - Curve *cu = (Curve *)ob->data; - cu->flag |= CU_PATH; + if (ob != obact) { + /* for armatures in pose mode, look inside the armature for the active bone + * so that we set up cross-armature constraints with less effort + */ + if ((ob->type == OB_ARMATURE) && (ob->mode & OB_MODE_POSE) && + (!only_curve && !only_mesh)) + { + /* just use the active bone, and assume that it is visible + usable */ + *tar_ob = ob; + *tar_pchan = BKE_pose_channel_active(ob); + found = true; + + break; + } + else if (((!only_curve) || (ob->type == OB_CURVE)) && + ((!only_mesh) || (ob->type == OB_MESH))) + { + /* set target */ + *tar_ob = ob; + found = true; + + /* perform some special operations on the target */ + if (only_curve) { + /* Curve-Path option must be enabled for follow-path constraints to be able to work */ + Curve *cu = (Curve *)ob->data; + cu->flag |= CU_PATH; + } + + break; } - - break; } } CTX_DATA_END; } /* if still not found, add a new empty to act as a target (if allowed) */ - if ((found == 0) && (add)) { + if ((found == false) && (add)) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); Base *base = BASACT, *newbase = NULL; @@ -1692,7 +1706,7 @@ static short get_new_constraint_target(bContext *C, int con_type, Object **tar_o /* make our new target the new object */ *tar_ob = obt; - found = 1; + found = true; } /* return whether there's any target */ diff --git a/source/blender/editors/object/object_data_transfer.c b/source/blender/editors/object/object_data_transfer.c index 47ee6752e51..acee69daab7 100644 --- a/source/blender/editors/object/object_data_transfer.c +++ b/source/blender/editors/object/object_data_transfer.c @@ -300,7 +300,7 @@ static void data_transfer_exec_preprocess_objects( } me = ob->data; - if (me->id.lib) { + if (ID_IS_LINKED_DATABLOCK(me)) { /* Do not transfer to linked data, not supported. */ BKE_reportf(op->reports, RPT_WARNING, "Skipping object '%s', linked data '%s' cannot be modified", ob->id.name + 2, me->id.name + 2); @@ -330,7 +330,7 @@ static bool data_transfer_exec_is_object_valid( me->id.tag &= ~LIB_TAG_DOIT; return true; } - else if (me->id.lib == NULL) { + else if (!ID_IS_LINKED_DATABLOCK(me)) { /* Do not transfer apply operation more than once. */ /* XXX This is not nice regarding vgroups, which are half-Object data... :/ */ BKE_reportf(op->reports, RPT_WARNING, @@ -387,7 +387,7 @@ static int data_transfer_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } - if (reverse_transfer && ((ID *)(ob_src->data))->lib) { + if (reverse_transfer && ID_IS_LINKED_DATABLOCK(ob_src->data)) { /* Do not transfer to linked data, not supported. */ return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 06200778ee5..3dc7d8ebd4b 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -470,7 +470,7 @@ void ED_object_editmode_enter(bContext *C, int flag) View3D *v3d = NULL; bool ok = false; - if (scene->id.lib) return; + if (ID_IS_LINKED_DATABLOCK(scene)) return; if (sa && sa->spacetype == SPACE_VIEW3D) v3d = sa->spacedata.first; @@ -539,7 +539,7 @@ void ED_object_editmode_enter(bContext *C, int flag) * BKE_object_obdata_is_libdata that prevent the bugfix #6614, so * i add this little hack here. */ - if (arm->id.lib) { + if (ID_IS_LINKED_DATABLOCK(arm)) { error_libdata(); return; } @@ -621,7 +621,7 @@ static int editmode_toggle_poll(bContext *C) Object *ob = CTX_data_active_object(C); /* covers proxies too */ - if (ELEM(NULL, ob, ob->data) || ((ID *)ob->data)->lib) + if (ELEM(NULL, ob, ob->data) || ID_IS_LINKED_DATABLOCK(ob->data)) return 0; /* if hidden but in edit mode, we still display */ @@ -848,7 +848,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) Nurb *nu; bool do_depgraph_update = false; - if (scene->id.lib) return; + if (ID_IS_LINKED_DATABLOCK(scene)) return; if (!(ob = OBACT)) return; @@ -946,6 +946,7 @@ static void copy_attr(Main *bmain, Scene *scene, View3D *v3d, short event) cu1 = base->object->data; cu1->spacemode = cu->spacemode; + cu1->align_y = cu->align_y; cu1->spacing = cu->spacing; cu1->linedist = cu->linedist; cu1->shear = cu->shear; @@ -1435,7 +1436,7 @@ static int shade_smooth_exec(bContext *C, wmOperator *op) { data = ob->data; - if (data && data->lib) { + if (data && ID_IS_LINKED_DATABLOCK(data)) { linked_data = true; continue; } @@ -1518,7 +1519,7 @@ static void UNUSED_FUNCTION(image_aspect) (Scene *scene, View3D *v3d) int a, b, done; if (scene->obedit) return; // XXX get from context - if (scene->id.lib) return; + if (ID_IS_LINKED_DATABLOCK(scene)) return; for (base = FIRSTBASE; base; base = base->next) { if (TESTBASELIB(v3d, base)) { diff --git a/source/blender/editors/object/object_group.c b/source/blender/editors/object/object_group.c index 76a8a68c42d..0fe43c44d7d 100644 --- a/source/blender/editors/object/object_group.c +++ b/source/blender/editors/object/object_group.c @@ -43,6 +43,7 @@ #include "BKE_depsgraph.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_object.h" @@ -439,7 +440,7 @@ static int group_link_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; /* Early return check, if the object is already in group - * we could sckip all the dependency check and just consider + * we could skip all the dependency check and just consider * operator is finished. */ if (BKE_group_object_exists(group, ob)) { @@ -527,7 +528,8 @@ static int group_unlink_exec(bContext *C, wmOperator *UNUSED(op)) if (!group) return OPERATOR_CANCELLED; - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false, false); + BKE_libblock_free(bmain, group); WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/editors/object/object_modifier.c b/source/blender/editors/object/object_modifier.c index 264945b00bf..b44ddf925a8 100644 --- a/source/blender/editors/object/object_modifier.c +++ b/source/blender/editors/object/object_modifier.c @@ -817,9 +817,9 @@ int edit_modifier_poll_generic(bContext *C, StructRNA *rna_type, int obtype_flag PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", rna_type); Object *ob = (ptr.id.data) ? ptr.id.data : ED_object_active_context(C); - if (!ob || ob->id.lib) return 0; + if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return 0; if (obtype_flag && ((1 << ob->type) & obtype_flag) == 0) return 0; - if (ptr.id.data && ((ID *)ptr.id.data)->lib) return 0; + if (ptr.id.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0; return 1; } diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index 534e59384ce..7e7e1ef182c 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -365,9 +365,21 @@ void ED_keymap_object(wmKeyConfig *keyconf) WM_keymap_verify_item(keymap, "OBJECT_OT_constraint_add_with_targets", CKEY, KM_PRESS, KM_CTRL | KM_SHIFT, 0); WM_keymap_verify_item(keymap, "OBJECT_OT_constraints_clear", CKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0); - WM_keymap_verify_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); + + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", false); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", false); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", false); + + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_location_clear", GKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", true); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_rotation_clear", RKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", true); + kmi = WM_keymap_add_item(keymap, "OBJECT_OT_scale_clear", SKEY, KM_PRESS, KM_ALT | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "clear_delta", true); + WM_keymap_verify_item(keymap, "OBJECT_OT_origin_clear", OKEY, KM_PRESS, KM_ALT, 0); WM_keymap_add_item(keymap, "OBJECT_OT_hide_view_clear", HKEY, KM_PRESS, KM_ALT, 0); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 2f10f83e276..b3edf1f5e0d 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -291,17 +291,17 @@ static int make_proxy_invoke(bContext *C, wmOperator *op, const wmEvent *event) Object *ob = ED_object_active_context(C); /* sanity checks */ - if (!scene || scene->id.lib || !ob) + if (!scene || ID_IS_LINKED_DATABLOCK(scene) || !ob) return OPERATOR_CANCELLED; /* Get object to work on - use a menu if we need to... */ - if (ob->dup_group && ob->dup_group->id.lib) { + if (ob->dup_group && ID_IS_LINKED_DATABLOCK(ob->dup_group)) { /* gives menu with list of objects in group */ /* proxy_group_objects_menu(C, op, ob, ob->dup_group); */ WM_enum_search_invoke(C, op, event); return OPERATOR_CANCELLED; } - else if (ob->id.lib) { + else if (ID_IS_LINKED_DATABLOCK(ob)) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("OK?"), ICON_QUESTION); uiLayout *layout = UI_popup_menu_layout(pup); @@ -437,7 +437,7 @@ typedef enum eObClearParentTypes { EnumPropertyItem prop_clear_parent_types[] = { {CLEAR_PARENT_ALL, "CLEAR", 0, "Clear Parent", - "Completely clear the parenting relationship, including involved modifiers is any"}, + "Completely clear the parenting relationship, including involved modifiers if any"}, {CLEAR_PARENT_KEEP_TRANSFORM, "CLEAR_KEEP_TRANSFORM", 0, "Clear and Keep Transformation", "As 'Clear Parent', but keep the current visual transformations of the object"}, {CLEAR_PARENT_INVERSE, "CLEAR_INVERSE", 0, "Clear Parent Inverse", @@ -1466,7 +1466,7 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (scene_to->id.lib) { + if (ID_IS_LINKED_DATABLOCK(scene_to)) { BKE_report(op->reports, RPT_ERROR, "Cannot link objects into a linked scene"); return OPERATOR_CANCELLED; } @@ -1564,7 +1564,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) ob_dst->data = obdata_id; /* if amount of material indices changed: */ - test_object_materials(bmain, ob_dst->data); + test_object_materials(ob_dst, ob_dst->data); DAG_id_tag_update(&ob_dst->id, OB_RECALC_DATA); break; @@ -1579,7 +1579,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) case MAKE_LINKS_ANIMDATA: BKE_animdata_copy_id((ID *)ob_dst, (ID *)ob_src, false); if (ob_dst->data && ob_src->data) { - if (obdata_id->lib) { + if (ID_IS_LINKED_DATABLOCK(obdata_id)) { is_lib = true; break; } @@ -1621,7 +1621,7 @@ static int make_links_data_exec(bContext *C, wmOperator *op) Curve *cu_src = ob_src->data; Curve *cu_dst = ob_dst->data; - if (obdata_id->lib) { + if (ID_IS_LINKED_DATABLOCK(obdata_id)) { is_lib = true; break; } @@ -1749,9 +1749,9 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in ob = base->object; if ((base->flag & flag) == flag) { - if (ob->id.lib == NULL && ob->id.us > 1) { + if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) { /* base gets copy of object */ - obn = BKE_object_copy(ob); + obn = BKE_object_copy(bmain, ob); base->object = obn; if (copy_groups) { @@ -1784,7 +1784,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in } if (all_duplicated) { - groupn = BKE_group_copy(group); + groupn = BKE_group_copy(bmain, group); for (go = groupn->gobject.first; go; go = go->next) go->ob = (Object *)go->ob->id.newid; @@ -1821,21 +1821,21 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); } -static void new_id_matar(Material **matar, const int totcol) +static void new_id_matar(Main *bmain, Material **matar, const int totcol) { ID *id; int a; for (a = 0; a < totcol; a++) { id = (ID *)matar[a]; - if (id && id->lib == NULL) { + if (id && !ID_IS_LINKED_DATABLOCK(id)) { if (id->newid) { matar[a] = (Material *)id->newid; id_us_plus(id->newid); id_us_min(id); } else if (id->us > 1) { - matar[a] = BKE_material_copy(matar[a]); + matar[a] = BKE_material_copy(bmain, matar[a]); id_us_min(id); id->newid = (ID *)matar[a]; } @@ -1857,15 +1857,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) for (base = FIRSTBASE; base; base = base->next) { ob = base->object; - if (ob->id.lib == NULL && (base->flag & flag) == flag) { + if (!ID_IS_LINKED_DATABLOCK(ob) && (base->flag & flag) == flag) { id = ob->data; - if (id && id->us > 1 && id->lib == NULL) { + if (id && id->us > 1 && !ID_IS_LINKED_DATABLOCK(id)) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); switch (ob->type) { case OB_LAMP: - ob->data = la = BKE_lamp_copy(ob->data); + ob->data = la = BKE_lamp_copy(bmain, ob->data); for (a = 0; a < MAX_MTEX; a++) { if (la->mtex[a]) { ID_NEW(la->mtex[a]->object); @@ -1873,37 +1873,37 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) } break; case OB_CAMERA: - ob->data = BKE_camera_copy(ob->data); + ob->data = BKE_camera_copy(bmain, ob->data); break; case OB_MESH: - ob->data = me = BKE_mesh_copy(ob->data); + ob->data = me = BKE_mesh_copy(bmain, ob->data); if (me->key) BKE_animdata_copy_id_action((ID *)me->key); break; case OB_MBALL: - ob->data = BKE_mball_copy(ob->data); + ob->data = BKE_mball_copy(bmain, ob->data); break; case OB_CURVE: case OB_SURF: case OB_FONT: - ob->data = cu = BKE_curve_copy(ob->data); + ob->data = cu = BKE_curve_copy(bmain, ob->data); ID_NEW(cu->bevobj); ID_NEW(cu->taperobj); if (cu->key) BKE_animdata_copy_id_action((ID *)cu->key); break; case OB_LATTICE: - ob->data = lat = BKE_lattice_copy(ob->data); + ob->data = lat = BKE_lattice_copy(bmain, ob->data); if (lat->key) BKE_animdata_copy_id_action((ID *)lat->key); break; case OB_ARMATURE: DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - ob->data = BKE_armature_copy(ob->data); + ob->data = BKE_armature_copy(bmain, ob->data); BKE_pose_rebuild(ob, ob->data); break; case OB_SPEAKER: - ob->data = BKE_speaker_copy(ob->data); + ob->data = BKE_speaker_copy(bmain, ob->data); break; default: if (G.debug & G_DEBUG) @@ -1938,14 +1938,14 @@ static void single_object_action_users(Scene *scene, const int flag) for (base = FIRSTBASE; base; base = base->next) { ob = base->object; - if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) { + if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); BKE_animdata_copy_id_action(&ob->id); } } } -static void single_mat_users(Scene *scene, const int flag, const bool do_textures) +static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bool do_textures) { Object *ob; Base *base; @@ -1955,14 +1955,14 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture for (base = FIRSTBASE; base; base = base->next) { ob = base->object; - if (ob->id.lib == NULL && (flag == 0 || (base->flag & SELECT)) ) { + if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */ if (ma->id.us > 1) { - man = BKE_material_copy(ma); + man = BKE_material_copy(bmain, ma); BKE_animdata_copy_id_action(&man->id); man->id.us = 0; @@ -1973,7 +1973,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture if (ma->mtex[b] && (tex = ma->mtex[b]->tex)) { if (tex->id.us > 1) { id_us_min(&tex->id); - tex = BKE_texture_copy(tex); + tex = BKE_texture_copy(bmain, tex); BKE_animdata_copy_id_action(&tex->id); man->mtex[b]->tex = tex; } @@ -1987,7 +1987,7 @@ static void single_mat_users(Scene *scene, const int flag, const bool do_texture } } -static void do_single_tex_user(Tex **from) +static void do_single_tex_user(Main *bmain, Tex **from) { Tex *tex, *texn; @@ -2000,7 +2000,7 @@ static void do_single_tex_user(Tex **from) id_us_min(&tex->id); } else if (tex->id.us > 1) { - texn = BKE_texture_copy(tex); + texn = BKE_texture_copy(bmain, tex); BKE_animdata_copy_id_action(&texn->id); tex->id.newid = (ID *)texn; id_us_min(&tex->id); @@ -2020,7 +2020,7 @@ static void single_tex_users_expand(Main *bmain) if (ma->id.tag & LIB_TAG_NEW) { for (b = 0; b < MAX_MTEX; b++) { if (ma->mtex[b] && ma->mtex[b]->tex) { - do_single_tex_user(&(ma->mtex[b]->tex)); + do_single_tex_user(bmain, &(ma->mtex[b]->tex)); } } } @@ -2030,7 +2030,7 @@ static void single_tex_users_expand(Main *bmain) if (la->id.tag & LIB_TAG_NEW) { for (b = 0; b < MAX_MTEX; b++) { if (la->mtex[b] && la->mtex[b]->tex) { - do_single_tex_user(&(la->mtex[b]->tex)); + do_single_tex_user(bmain, &(la->mtex[b]->tex)); } } } @@ -2040,7 +2040,7 @@ static void single_tex_users_expand(Main *bmain) if (wo->id.tag & LIB_TAG_NEW) { for (b = 0; b < MAX_MTEX; b++) { if (wo->mtex[b] && wo->mtex[b]->tex) { - do_single_tex_user(&(wo->mtex[b]->tex)); + do_single_tex_user(bmain, &(wo->mtex[b]->tex)); } } } @@ -2059,19 +2059,19 @@ static void single_mat_users_expand(Main *bmain) for (ob = bmain->object.first; ob; ob = ob->id.next) if (ob->id.tag & LIB_TAG_NEW) - new_id_matar(ob->mat, ob->totcol); + new_id_matar(bmain, ob->mat, ob->totcol); for (me = bmain->mesh.first; me; me = me->id.next) if (me->id.tag & LIB_TAG_NEW) - new_id_matar(me->mat, me->totcol); + new_id_matar(bmain, me->mat, me->totcol); for (cu = bmain->curve.first; cu; cu = cu->id.next) if (cu->id.tag & LIB_TAG_NEW) - new_id_matar(cu->mat, cu->totcol); + new_id_matar(bmain, cu->mat, cu->totcol); for (mb = bmain->mball.first; mb; mb = mb->id.next) if (mb->id.tag & LIB_TAG_NEW) - new_id_matar(mb->mat, mb->totcol); + new_id_matar(bmain, mb->mat, mb->totcol); /* material imats */ for (ma = bmain->mat.first; ma; ma = ma->id.next) @@ -2104,11 +2104,11 @@ static void make_local_makelocalmaterial(Material *ma) AnimData *adt; int b; - id_make_local(&ma->id, false); + id_make_local(G.main, &ma->id, false, false); for (b = 0; b < MAX_MTEX; b++) if (ma->mtex[b] && ma->mtex[b]->tex) - id_make_local(&ma->mtex[b]->tex->id, false); + id_make_local(G.main, &ma->mtex[b]->tex->id, false, false); adt = BKE_animdata_from_id(&ma->id); if (adt) BKE_animdata_make_local(adt); @@ -2184,7 +2184,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene) bool changed = false; for (ob = bmain->object.first; ob; ob = ob->id.next) { - if (ob->id.lib && (ob->id.us == 0)) { + if (ID_IS_LINKED_DATABLOCK(ob) && (ob->id.us == 0)) { Base *base; id_us_plus(&ob->id); @@ -2237,7 +2237,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } if (ob->id.lib) - id_make_local(&ob->id, false); + id_make_local(bmain, &ob->id, false, false); } CTX_DATA_END; @@ -2259,7 +2259,7 @@ static int make_local_exec(bContext *C, wmOperator *op) id = ob->data; if (id && (ELEM(mode, MAKE_LOCAL_SELECT_OBDATA, MAKE_LOCAL_SELECT_OBDATA_MATERIAL))) { - id_make_local(id, false); + id_make_local(bmain, id, false, false); adt = BKE_animdata_from_id(id); if (adt) BKE_animdata_make_local(adt); @@ -2275,7 +2275,7 @@ static int make_local_exec(bContext *C, wmOperator *op) } for (psys = ob->particlesystem.first; psys; psys = psys->next) - id_make_local(&psys->part->id, false); + id_make_local(bmain, &psys->part->id, false, false); adt = BKE_animdata_from_id(&ob->id); if (adt) BKE_animdata_make_local(adt); @@ -2294,7 +2294,7 @@ static int make_local_exec(bContext *C, wmOperator *op) for (b = 0; b < MAX_MTEX; b++) if (la->mtex[b] && la->mtex[b]->tex) - id_make_local(&la->mtex[b]->tex->id, false); + id_make_local(bmain, &la->mtex[b]->tex->id, false, false); } else { for (a = 0; a < ob->totcol; a++) { @@ -2376,7 +2376,7 @@ static int make_single_user_exec(bContext *C, wmOperator *op) } if (RNA_boolean_get(op->ptr, "material")) { - single_mat_users(scene, flag, RNA_boolean_get(op->ptr, "texture")); + single_mat_users(bmain, scene, flag, RNA_boolean_get(op->ptr, "texture")); } #if 0 /* can't do this separate from materials */ diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 0cbbe46f461..f1b7186f8a1 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -577,7 +577,6 @@ static bool select_grouped_parent(bContext *C) /* Makes parent active and de-sel /* can be NULL if parent in other scene */ if (baspar && BASE_SELECTABLE(v3d, baspar)) { - ED_base_object_select(basact, BA_DESELECT); ED_base_object_select(baspar, BA_SELECT); ED_base_object_activate(C, baspar); changed = true; diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index 39bd34456be..e04114761e4 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -225,7 +225,7 @@ static int shape_key_mode_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT); } static int shape_key_mode_exists_poll(bContext *C) @@ -234,7 +234,7 @@ static int shape_key_mode_exists_poll(bContext *C) ID *data = (ob) ? ob->data : NULL; /* same as shape_key_mode_poll */ - return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT) && + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && ob->mode != OB_MODE_EDIT) && /* check a keyblock exists */ (BKE_keyblock_from_object(ob) != NULL); } @@ -246,14 +246,15 @@ static int shape_key_move_poll(bContext *C) ID *data = (ob) ? ob->data : NULL; Key *key = BKE_key_from_object(ob); - return (ob && !ob->id.lib && data && !data->lib && ob->mode != OB_MODE_EDIT && key && key->totkey > 1); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data) && + ob->mode != OB_MODE_EDIT && key && key->totkey > 1); } static int shape_key_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && data && !data->lib); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data)); } static int shape_key_add_exec(bContext *C, wmOperator *op) diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index d2bbb73b597..4d7d7df0d2f 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -76,60 +76,87 @@ /*************************** Clear Transformation ****************************/ /* clear location of object */ -static void object_clear_loc(Object *ob) +static void object_clear_loc(Object *ob, const bool clear_delta) { /* clear location if not locked */ - if ((ob->protectflag & OB_LOCK_LOCX) == 0) - ob->loc[0] = ob->dloc[0] = 0.0f; - if ((ob->protectflag & OB_LOCK_LOCY) == 0) - ob->loc[1] = ob->dloc[1] = 0.0f; - if ((ob->protectflag & OB_LOCK_LOCZ) == 0) - ob->loc[2] = ob->dloc[2] = 0.0f; + if ((ob->protectflag & OB_LOCK_LOCX) == 0) { + ob->loc[0] = 0.0f; + if (clear_delta) ob->dloc[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_LOCY) == 0) { + ob->loc[1] = 0.0f; + if (clear_delta) ob->dloc[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_LOCZ) == 0) { + ob->loc[2] = 0.0f; + if (clear_delta) ob->dloc[2] = 0.0f; + } } /* clear rotation of object */ -static void object_clear_rot(Object *ob) +static void object_clear_rot(Object *ob, const bool clear_delta) { /* clear rotations that aren't locked */ if (ob->protectflag & (OB_LOCK_ROTX | OB_LOCK_ROTY | OB_LOCK_ROTZ | OB_LOCK_ROTW)) { if (ob->protectflag & OB_LOCK_ROT4D) { /* perform clamping on a component by component basis */ if (ob->rotmode == ROT_MODE_AXISANGLE) { - if ((ob->protectflag & OB_LOCK_ROTW) == 0) - ob->rotAngle = ob->drotAngle = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTX) == 0) - ob->rotAxis[0] = ob->drotAxis[0] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTY) == 0) - ob->rotAxis[1] = ob->drotAxis[1] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) - ob->rotAxis[2] = ob->drotAxis[2] = 0.0f; + if ((ob->protectflag & OB_LOCK_ROTW) == 0) { + ob->rotAngle = 0.0f; + if (clear_delta) ob->drotAngle = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->rotAxis[0] = 0.0f; + if (clear_delta) ob->drotAxis[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->rotAxis[1] = 0.0f; + if (clear_delta) ob->drotAxis[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->rotAxis[2] = 0.0f; + if (clear_delta) ob->drotAxis[2] = 0.0f; + } /* check validity of axis - axis should never be 0,0,0 (if so, then we make it rotate about y) */ if (IS_EQF(ob->rotAxis[0], ob->rotAxis[1]) && IS_EQF(ob->rotAxis[1], ob->rotAxis[2])) ob->rotAxis[1] = 1.0f; - if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2])) + if (IS_EQF(ob->drotAxis[0], ob->drotAxis[1]) && IS_EQF(ob->drotAxis[1], ob->drotAxis[2]) && clear_delta) ob->drotAxis[1] = 1.0f; } else if (ob->rotmode == ROT_MODE_QUAT) { - if ((ob->protectflag & OB_LOCK_ROTW) == 0) - ob->quat[0] = ob->dquat[0] = 1.0f; - if ((ob->protectflag & OB_LOCK_ROTX) == 0) - ob->quat[1] = ob->dquat[1] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTY) == 0) - ob->quat[2] = ob->dquat[2] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) - ob->quat[3] = ob->dquat[3] = 0.0f; - + if ((ob->protectflag & OB_LOCK_ROTW) == 0) { + ob->quat[0] = 1.0f; + if (clear_delta) ob->dquat[0] = 1.0f; + } + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->quat[1] = 0.0f; + if (clear_delta) ob->dquat[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->quat[2] = 0.0f; + if (clear_delta) ob->dquat[2] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->quat[3] = 0.0f; + if (clear_delta) ob->dquat[3] = 0.0f; + } /* TODO: does this quat need normalizing now? */ } else { /* the flag may have been set for the other modes, so just ignore the extra flag... */ - if ((ob->protectflag & OB_LOCK_ROTX) == 0) - ob->rot[0] = ob->drot[0] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTY) == 0) - ob->rot[1] = ob->drot[1] = 0.0f; - if ((ob->protectflag & OB_LOCK_ROTZ) == 0) - ob->rot[2] = ob->drot[2] = 0.0f; + if ((ob->protectflag & OB_LOCK_ROTX) == 0) { + ob->rot[0] = 0.0f; + if (clear_delta) ob->drot[0] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTY) == 0) { + ob->rot[1] = 0.0f; + if (clear_delta) ob->drot[1] = 0.0f; + } + if ((ob->protectflag & OB_LOCK_ROTZ) == 0) { + ob->rot[2] = 0.0f; + if (clear_delta) ob->drot[2] = 0.0f; + } } } else { @@ -175,34 +202,34 @@ static void object_clear_rot(Object *ob) else { if (ob->rotmode == ROT_MODE_QUAT) { unit_qt(ob->quat); - unit_qt(ob->dquat); + if (clear_delta) unit_qt(ob->dquat); } else if (ob->rotmode == ROT_MODE_AXISANGLE) { unit_axis_angle(ob->rotAxis, &ob->rotAngle); - unit_axis_angle(ob->drotAxis, &ob->drotAngle); + if (clear_delta) unit_axis_angle(ob->drotAxis, &ob->drotAngle); } else { zero_v3(ob->rot); - zero_v3(ob->drot); + if (clear_delta) zero_v3(ob->drot); } } } /* clear scale of object */ -static void object_clear_scale(Object *ob) +static void object_clear_scale(Object *ob, const bool clear_delta) { /* clear scale factors which are not locked */ if ((ob->protectflag & OB_LOCK_SCALEX) == 0) { - ob->dscale[0] = 1.0f; ob->size[0] = 1.0f; + if (clear_delta) ob->dscale[0] = 1.0f; } if ((ob->protectflag & OB_LOCK_SCALEY) == 0) { - ob->dscale[1] = 1.0f; ob->size[1] = 1.0f; + if (clear_delta) ob->dscale[1] = 1.0f; } if ((ob->protectflag & OB_LOCK_SCALEZ) == 0) { - ob->dscale[2] = 1.0f; ob->size[2] = 1.0f; + if (clear_delta) ob->dscale[2] = 1.0f; } } @@ -210,10 +237,12 @@ static void object_clear_scale(Object *ob) /* generic exec for clear-transform operators */ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, - void (*clear_func)(Object *), const char default_ksName[]) + void (*clear_func)(Object *, const bool), + const char default_ksName[]) { Scene *scene = CTX_data_scene(C); KeyingSet *ks; + const bool clear_delta = RNA_boolean_get(op->ptr, "clear_delta"); /* sanity checks */ if (ELEM(NULL, clear_func, default_ksName)) { @@ -231,10 +260,10 @@ static int object_clear_transform_generic_exec(bContext *C, wmOperator *op, { if (!(ob->mode & OB_MODE_WEIGHT_PAINT)) { /* run provided clearing function */ - clear_func(ob); - + clear_func(ob, clear_delta); + ED_autokeyframe_object(C, scene, ob, ks); - + /* tag for updates */ DAG_id_tag_update(&ob->id, OB_RECALC_OB); } @@ -268,6 +297,11 @@ void OBJECT_OT_location_clear(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + + /* properties */ + ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", + "Clear delta location in addition to clearing the normal location transform"); } static int object_rotation_clear_exec(bContext *C, wmOperator *op) @@ -288,6 +322,10 @@ void OBJECT_OT_rotation_clear(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", + "Clear delta rotation in addition to clearing the normal rotation transform"); } static int object_scale_clear_exec(bContext *C, wmOperator *op) @@ -308,6 +346,10 @@ void OBJECT_OT_scale_clear(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + ot->prop = RNA_def_boolean(ot->srna, "clear_delta", false, "Clear Delta", + "Clear delta scale in addition to clearing the normal scale transform"); } /* --------------- */ @@ -391,7 +433,7 @@ static int apply_objects_internal(bContext *C, ReportList *reports, bool apply_l changed = false; } - if (obdata->lib) { + if (ID_IS_LINKED_DATABLOCK(obdata)) { BKE_reportf(reports, RPT_ERROR, "Cannot apply to library data: Object \"%s\", %s \"%s\", aborting", ob->id.name + 2, BKE_idcode_to_name(GS(obdata->name)), obdata->name + 2); @@ -792,7 +834,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) if (ob->data == NULL) { /* special support for dupligroups */ if ((ob->transflag & OB_DUPLIGROUP) && ob->dup_group && (ob->dup_group->id.tag & LIB_TAG_DOIT) == 0) { - if (ob->dup_group->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob->dup_group)) { tot_lib_error++; } else { @@ -817,7 +859,7 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) } } } - else if (((ID *)ob->data)->lib) { + else if (ID_IS_LINKED_DATABLOCK(ob->data)) { tot_lib_error++; } diff --git a/source/blender/editors/object/object_vgroup.c b/source/blender/editors/object/object_vgroup.c index 414cc476be5..ad41fb23a69 100644 --- a/source/blender/editors/object/object_vgroup.c +++ b/source/blender/editors/object/object_vgroup.c @@ -2447,8 +2447,8 @@ static int vertex_group_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && - data && !data->lib && + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && + data && !ID_IS_LINKED_DATABLOCK(data) && OB_TYPE_SUPPORT_VGROUP(ob->type) && ob->defbase.first); } @@ -2457,7 +2457,8 @@ static int vertex_group_supported_poll(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && OB_TYPE_SUPPORT_VGROUP(ob->type) && data && !data->lib); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && OB_TYPE_SUPPORT_VGROUP(ob->type) && + data && !ID_IS_LINKED_DATABLOCK(data)); } static int vertex_group_mesh_poll(bContext *C) @@ -2465,8 +2466,8 @@ static int vertex_group_mesh_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && - data && !data->lib && + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && + data && !ID_IS_LINKED_DATABLOCK(data) && ob->type == OB_MESH && ob->defbase.first); } @@ -2475,7 +2476,7 @@ static int UNUSED_FUNCTION(vertex_group_mesh_supported_poll)(bContext *C) { Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - return (ob && !ob->id.lib && ob->type == OB_MESH && data && !data->lib); + return (ob && !ID_IS_LINKED_DATABLOCK(ob) && ob->type == OB_MESH && data && !ID_IS_LINKED_DATABLOCK(data)); } @@ -2484,7 +2485,7 @@ static int UNUSED_FUNCTION(vertex_group_poll_edit) (bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ob->id.lib && data && !data->lib)) + if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data))) return 0; return BKE_object_is_in_editmode_vgroup(ob); @@ -2496,7 +2497,7 @@ static int vertex_group_vert_select_poll_ex(bContext *C, const short ob_type_fla Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ob->id.lib && data && !data->lib)) + if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data))) return false; if (ob_type_flag && (((1 << ob->type) & ob_type_flag)) == 0) { @@ -2536,7 +2537,7 @@ static int vertex_group_vert_select_unlocked_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ob->id.lib && data && !data->lib)) + if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data))) return 0; if (!(BKE_object_is_in_editmode_vgroup(ob) || @@ -2559,7 +2560,7 @@ static int vertex_group_vert_select_mesh_poll(bContext *C) Object *ob = ED_object_context(C); ID *data = (ob) ? ob->data : NULL; - if (!(ob && !ob->id.lib && data && !data->lib)) + if (!(ob && !ID_IS_LINKED_DATABLOCK(ob) && data && !ID_IS_LINKED_DATABLOCK(data))) return 0; /* only difference to #vertex_group_vert_select_poll */ @@ -2748,7 +2749,7 @@ static int vertex_group_select_exec(bContext *C, wmOperator *UNUSED(op)) { Object *ob = ED_object_context(C); - if (!ob || ob->id.lib) + if (!ob || ID_IS_LINKED_DATABLOCK(ob)) return OPERATOR_CANCELLED; vgroup_select_verts(ob, 1); @@ -3537,8 +3538,10 @@ static int vgroup_sort_name(const void *def_a_ptr, const void *def_b_ptr) return BLI_natstrcmp(def_a->name, def_b->name); } -/* Sorts the weight groups according to the bone hierarchy of the - associated armature (similar to how bones are ordered in the Outliner) */ +/** + * Sorts the weight groups according to the bone hierarchy of the + * associated armature (similar to how bones are ordered in the Outliner) + */ static void vgroup_sort_bone_hierarchy(Object *ob, ListBase *bonebase) { if (bonebase == NULL) { diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index 3da3a451d66..e22a145b3a6 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1173,7 +1173,7 @@ static void PE_update_selection(Scene *scene, Object *ob, int useflag) } } - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ @@ -1289,7 +1289,7 @@ void PE_update_object(Scene *scene, Object *ob, int useflag) PE_hide_keys_time(scene, edit, CFRA); /* regenerate path caches */ - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); /* disable update flag */ LOOP_POINTS { @@ -1634,7 +1634,7 @@ static int select_random_exec(bContext *C, wmOperator *op) int p; int k; - const float randfac = RNA_float_get (op->ptr, "percent") / 100.0f; + const float randfac = RNA_float_get(op->ptr, "percent") / 100.0f; const int seed = WM_operator_properties_select_random_seed_increment_get(op); const bool select = (RNA_enum_get(op->ptr, "action") == SEL_SELECT); RNG *rng; @@ -2288,7 +2288,7 @@ static int remove_tagged_particles(Object *ob, ParticleSystem *psys, int mirror) npoint= new_points= MEM_callocN(new_totpart * sizeof(PTCacheEditPoint), "PTCacheEditKey array"); if (ELEM(NULL, new_pars, new_points)) { - /* allocation error! */ + /* allocation error! */ if (new_pars) MEM_freeN(new_pars); if (new_points) @@ -4693,7 +4693,7 @@ static int particle_edit_toggle_poll(bContext *C) if (ob == NULL || ob->type != OB_MESH) return 0; - if (!ob->data || ((ID *)ob->data)->lib) + if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data)) return 0; if (CTX_data_edit_object(C)) return 0; diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 1297133e1a2..0dd00df6182 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -195,7 +195,7 @@ static int new_particle_settings_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy particle setting */ if (psys->part) - part= BKE_particlesettings_copy(psys->part); + part= BKE_particlesettings_copy(bmain, psys->part); else part= psys_new_settings("ParticleSettings", bmain); @@ -974,7 +974,7 @@ static void remove_particle_systems_from_object(Object *ob_to) if (ob_to->type != OB_MESH) return; - if (!ob_to->data || ((ID *)ob_to->data)->lib) + if (!ob_to->data || ID_IS_LINKED_DATABLOCK(ob_to->data)) return; for (md = ob_to->modifiers.first; md; md = md_next) { @@ -1004,7 +1004,7 @@ static bool copy_particle_systems_to_object(Scene *scene, Object *ob_from, Parti if (ob_to->type != OB_MESH) return false; - if (!ob_to->data || ((ID *)ob_to->data)->lib) + if (!ob_to->data || ID_IS_LINKED_DATABLOCK(ob_to->data)) return false; /* For remapping we need a valid DM. diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 1203889cf0e..8c5d25ad44d 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -1482,7 +1482,7 @@ static void render_view3d_do(RenderEngine *engine, const bContext *C) void render_view3d_update(RenderEngine *engine, const bContext *C) { /* this shouldn't be needed and causes too many database rebuilds, but we - * aren't actually tracking updates for all relevent datablocks so this is + * aren't actually tracking updates for all relevant datablocks so this is * a catch-all for updates */ engine->update_flag |= RE_ENGINE_UPDATE_DATABASE; diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index f4260a0cd33..76d0143e898 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -70,6 +70,7 @@ #include "BKE_icons.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" @@ -830,7 +831,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied material */ BLI_remlink(&pr_main->mat, sp->matcopy); - BKE_material_free_ex(sp->matcopy, false); + BKE_material_free(sp->matcopy); properties = IDP_GetProperties((ID *)sp->matcopy, false); if (properties) { @@ -862,7 +863,9 @@ static void shader_preview_free(void *customdata) /* get rid of copied world */ BLI_remlink(&pr_main->world, sp->worldcopy); - BKE_world_free_ex(sp->worldcopy, true); /* [#32865] - we need to unlink the texture copies, unlike for materials */ + /* T32865 - we need to unlink the texture copies, unlike for materials */ + BKE_libblock_relink_ex(pr_main, sp->worldcopy, NULL, NULL, true); + BKE_world_free(sp->worldcopy); properties = IDP_GetProperties((ID *)sp->worldcopy, false); if (properties) { @@ -878,6 +881,7 @@ static void shader_preview_free(void *customdata) /* get rid of copied lamp */ BLI_remlink(&pr_main->lamp, sp->lampcopy); + BKE_libblock_relink_ex(pr_main, sp->lampcopy, NULL, NULL, true); BKE_lamp_free(sp->lampcopy); properties = IDP_GetProperties((ID *)sp->lampcopy, false); diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 1d20ecf2d99..c3f83138707 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -464,7 +464,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy material */ if (ma) { - ma = BKE_material_copy(ma); + ma = BKE_material_copy(bmain, ma); } else { ma = BKE_material_add(bmain, DATA_("Material")); @@ -518,7 +518,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy texture */ if (tex) { - tex = BKE_texture_copy(tex); + tex = BKE_texture_copy(bmain, tex); } else { tex = BKE_texture_add(bmain, DATA_("Texture")); @@ -576,7 +576,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy world */ if (wo) { - wo = BKE_world_copy(wo); + wo = BKE_world_copy(bmain, wo); } else { wo = add_world(bmain, DATA_("World")); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index ab8b7d4e138..8d058ed2081 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -580,15 +580,20 @@ void ED_region_tag_refresh_ui(ARegion *ar) void ED_region_tag_redraw_partial(ARegion *ar, const rcti *rct) { if (ar && !(ar->do_draw & RGN_DRAWING)) { - if (!(ar->do_draw & RGN_DRAW)) { + if (!(ar->do_draw & (RGN_DRAW | RGN_DRAW_PARTIAL))) { /* no redraw set yet, set partial region */ ar->do_draw |= RGN_DRAW_PARTIAL; ar->drawrct = *rct; } else if (ar->drawrct.xmin != ar->drawrct.xmax) { + BLI_assert((ar->do_draw & RGN_DRAW_PARTIAL) != 0); /* partial redraw already set, expand region */ BLI_rcti_union(&ar->drawrct, rct); } + else { + BLI_assert((ar->do_draw & RGN_DRAW) != 0); + /* Else, full redraw is already requested, nothing to do here. */ + } } } diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index a93c8c83cbb..f0a6b56a7d2 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -45,6 +45,7 @@ #include "BKE_image.h" #include "BKE_global.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -1755,7 +1756,9 @@ bool ED_screen_delete_scene(bContext *C, Scene *scene) ED_screen_set_scene(C, CTX_wm_screen(C), newscene); - BKE_scene_unlink(bmain, scene, newscene); + BKE_libblock_remap(bmain, scene, newscene, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + + BKE_libblock_free(bmain, scene); return true; } diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index f340f716ccb..6dbb5db53d0 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -168,7 +168,7 @@ int ED_operator_screen_mainwinactive(bContext *C) int ED_operator_scene_editable(bContext *C) { Scene *scene = CTX_data_scene(C); - if (scene && scene->id.lib == NULL) + if (scene && !ID_IS_LINKED_DATABLOCK(scene)) return 1; return 0; } @@ -178,7 +178,7 @@ int ED_operator_objectmode(bContext *C) Scene *scene = CTX_data_scene(C); Object *obact = CTX_data_active_object(C); - if (scene == NULL || scene->id.lib) + if (scene == NULL || ID_IS_LINKED_DATABLOCK(scene)) return 0; if (CTX_data_edit_object(C)) return 0; @@ -279,7 +279,7 @@ int ED_operator_node_editable(bContext *C) { SpaceNode *snode = CTX_wm_space_node(C); - if (snode && snode->edittree && snode->edittree->id.lib == NULL) + if (snode && snode->edittree && !ID_IS_LINKED_DATABLOCK(snode->edittree)) return 1; return 0; @@ -341,20 +341,20 @@ int ED_operator_object_active(bContext *C) int ED_operator_object_active_editable(bContext *C) { Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob)); + return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob)); } int ED_operator_object_active_editable_mesh(bContext *C) { Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) && - (ob->type == OB_MESH) && !(((ID *)ob->data)->lib)); + return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) && + (ob->type == OB_MESH) && !ID_IS_LINKED_DATABLOCK(ob->data)); } int ED_operator_object_active_editable_font(bContext *C) { Object *ob = ED_object_active_context(C); - return ((ob != NULL) && !(ob->id.lib) && !ed_object_hidden(ob) && + return ((ob != NULL) && !ID_IS_LINKED_DATABLOCK(ob) && !ed_object_hidden(ob) && (ob->type == OB_FONT)); } @@ -2479,7 +2479,7 @@ static void SCREEN_OT_screen_full_area(wmOperatorType *ot) { PropertyRNA *prop; - ot->name = "Toggle Fullscreen Area"; + ot->name = "Toggle Maximize Area"; ot->description = "Toggle display selected area as fullscreen/maximized"; ot->idname = "SCREEN_OT_screen_full_area"; @@ -3955,7 +3955,7 @@ static int scene_new_exec(bContext *C, wmOperator *op) newscene = BKE_scene_add(bmain, DATA_("Scene")); } else { /* different kinds of copying */ - newscene = BKE_scene_copy(scene, type); + newscene = BKE_scene_copy(bmain, scene, type); /* these can't be handled in blenkernel currently, so do them here */ if (type == SCE_COPY_LINK_DATA) { diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index eba9448aa40..53c11e2a6a9 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -1016,7 +1016,7 @@ static void paint_draw_cursor(bContext *C, int x, int y, void *UNUSED(unused)) translation[1] = y; outline_alpha = 0.5; outline_col = brush->add_col; - final_radius = (BKE_brush_size_get(scene, brush) * zoomx) / U.pixelsize; + final_radius = (BKE_brush_size_get(scene, brush) * zoomx); /* don't calculate rake angles while a stroke is active because the rake variables are global and * we may get interference with the stroke itself. For line strokes, such interference is visible */ diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index 88b3bc5d8fd..bf344e1f721 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -401,7 +401,7 @@ static void image_undo_end(void) UndoImageTile *tmp_tile = tile->next; deallocsize += allocsize * ((tile->use_float) ? sizeof(float) : sizeof(char)); MEM_freeN(tile->rect.pt); - BLI_freelinkN (lb, tile); + BLI_freelinkN(lb, tile); tile = tmp_tile; } else { @@ -1342,7 +1342,7 @@ static int texture_paint_toggle_poll(bContext *C) Object *ob = CTX_data_active_object(C); if (ob == NULL || ob->type != OB_MESH) return 0; - if (!ob->data || ((ID *)ob->data)->lib) + if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data)) return 0; if (CTX_data_edit_object(C)) return 0; diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index e4c26064fec..d60c8e8dbd9 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -183,8 +183,8 @@ BLI_INLINE unsigned char f_to_char(const float val) /* to avoid locking in tile initialization */ #define TILE_PENDING SET_INT_IN_POINTER(-1) -/* This is mainly a convenience struct used so we can keep an array of images we use - * Thir imbufs, etc, in 1 array, When using threads this array is copied for each thread +/* This is mainly a convenience struct used so we can keep an array of images we use - + * their imbufs, etc, in 1 array, When using threads this array is copied for each thread * because 'partRedrawRect' and 'touch' values would not be thread safe */ typedef struct ProjPaintImage { Image *ima; @@ -202,7 +202,7 @@ typedef struct ProjPaintImage { */ typedef struct ProjStrokeHandle { /* Support for painting from multiple views at once, - * currently used to impliment symmetry painting, + * currently used to implement symmetry painting, * we can assume at least the first is set while painting. */ struct ProjPaintState *ps_views[8]; int ps_views_tot; @@ -2174,7 +2174,7 @@ static void project_bucket_clip_face( if ((*tot) < 3) { /* no intersections to speak of, but more probable is that all face is just outside the - * rectangle and culled due to float precision issues. Since above teste have failed, + * rectangle and culled due to float precision issues. Since above tests have failed, * just dump triangle as is for painting */ *tot = 0; copy_v2_v2(bucket_bounds_uv[*tot], uv1co); (*tot)++; @@ -3717,7 +3717,7 @@ static void project_paint_prepare_all_faces( } /* tfbase here should be non-null! */ - BLI_assert (mloopuv_base != NULL); + BLI_assert(mloopuv_base != NULL); if (is_face_sel && tpage) { ProjPaintFaceCoSS coSS; @@ -5858,7 +5858,9 @@ static int add_simple_uvs_exec(bContext *C, wmOperator *UNUSED(op)) Mesh *me = ob->data; bool synch_selection = (scene->toolsettings->uv_flag & UV_SYNC_SELECTION) != 0; - BMesh *bm = BM_mesh_create(&bm_mesh_allocsize_default); + BMesh *bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); /* turn synch selection off, since we are not in edit mode we need to ensure only the uv flags are tested */ scene->toolsettings->uv_flag &= ~UV_SYNC_SELECTION; diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index b6a7d671882..7e05ab929ae 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -101,6 +101,10 @@ bool ED_wpaint_fill(struct VPaint *wp, struct Object *ob, float paintweight); bool ED_vpaint_smooth(struct Object *ob); +typedef void (*VPaintTransform_Callback)(const float col[3], const void *user_data, float r_col[3]); + +bool ED_vpaint_color_transform(struct Object *ob, VPaintTransform_Callback vpaint_tx_fn, const void *user_data); + void PAINT_OT_weight_paint_toggle(struct wmOperatorType *ot); void PAINT_OT_weight_paint(struct wmOperatorType *ot); void PAINT_OT_weight_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index da7667c775e..f88b64129e7 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -69,7 +69,7 @@ static int brush_add_exec(bContext *C, wmOperator *UNUSED(op)) PaintMode mode = BKE_paintmode_get_active_from_context(C); if (br) - br = BKE_brush_copy(br); + br = BKE_brush_copy(bmain, br); else br = BKE_brush_add(bmain, "Brush", BKE_paint_object_mode_from_paint_mode(mode)); @@ -315,6 +315,241 @@ static void PAINT_OT_vertex_color_smooth(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/** \name Vertex Color Transformations + * \{ */ + +struct VPaintTx_BrightContrastData { + /* pre-calculated */ + float gain; + float offset; +}; + +static void vpaint_tx_brightness_contrast(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_BrightContrastData *data = user_data; + + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * col[i] + data->offset; + } +} + +static int vertex_color_brightness_contrast_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + float gain, offset; + { + float brightness = RNA_float_get(op->ptr, "brightness"); + float contrast = RNA_float_get(op->ptr, "contrast"); + brightness /= 100.0f; + float delta = contrast / 200.0f; + gain = 1.0f - delta * 2.0f; + /* + * The algorithm is by Werner D. Streidt + * (http://visca.com/ffactory/archives/5-99/msg00021.html) + * Extracted of OpenCV demhist.c + */ + if (contrast > 0) { + gain = 1.0f / ((gain != 0.0f) ? gain : FLT_EPSILON); + offset = gain * (brightness - delta); + } + else { + delta *= -1; + offset = gain * (brightness + delta); + } + } + + const struct VPaintTx_BrightContrastData user_data = { + .gain = gain, + .offset = offset, + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_brightness_contrast, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_brightness_contrast(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Vertex Paint Bright/Contrast"; + ot->idname = "PAINT_OT_vertex_color_brightness_contrast"; + ot->description = "Adjust vertex color brightness/contrast"; + + /* api callbacks */ + ot->exec = vertex_color_brightness_contrast_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + const float min = -100, max = +100; + prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max); + prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max); + RNA_def_property_ui_range(prop, min, max, 1, 1); +} + +struct VPaintTx_HueSatData { + float hue; + float sat; + float val; +}; + +static void vpaint_tx_hsv(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_HueSatData *data = user_data; + float hsv[3]; + rgb_to_hsv_v(col, hsv); + + hsv[0] += (data->hue - 0.5f); + if (hsv[0] > 1.0f) { + hsv[0] -= 1.0f; + } + else if (hsv[0] < 0.0f) { + hsv[0] += 1.0f; + } + hsv[1] *= data->sat; + hsv[2] *= data->val; + + hsv_to_rgb_v(hsv, r_col); +} + +static int vertex_color_hsv_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_HueSatData user_data = { + .hue = RNA_float_get(op->ptr, "h"), + .sat = RNA_float_get(op->ptr, "s"), + .val = RNA_float_get(op->ptr, "v"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_hsv, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_hsv(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Hue Saturation Value"; + ot->idname = "PAINT_OT_vertex_color_hsv"; + ot->description = "Adjust vertex color HSV values"; + + /* api callbacks */ + ot->exec = vertex_color_hsv_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f); + RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f); + RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f); +} + +static void vpaint_tx_invert(const float col[3], const void *UNUSED(user_data), float r_col[3]) +{ + for (int i = 0; i < 3; i++) { + r_col[i] = 1.0f - col[i]; + } +} + +static int vertex_color_invert_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *obact = CTX_data_active_object(C); + + if (ED_vpaint_color_transform(obact, vpaint_tx_invert, NULL)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_invert(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Invert"; + ot->idname = "PAINT_OT_vertex_color_invert"; + ot->description = "Invert RGB values"; + + /* api callbacks */ + ot->exec = vertex_color_invert_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + +struct VPaintTx_LevelsData { + float gain; + float offset; +}; + +static void vpaint_tx_levels(const float col[3], const void *user_data, float r_col[3]) +{ + const struct VPaintTx_LevelsData *data = user_data; + for (int i = 0; i < 3; i++) { + r_col[i] = data->gain * (col[i] + data->offset); + } +} + +static int vertex_color_levels_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + + const struct VPaintTx_LevelsData user_data = { + .gain = RNA_float_get(op->ptr, "gain"), + .offset = RNA_float_get(op->ptr, "offset"), + }; + + if (ED_vpaint_color_transform(obact, vpaint_tx_levels, &user_data)) { + ED_region_tag_redraw(CTX_wm_region(C)); + return OPERATOR_FINISHED; + } + else { + return OPERATOR_CANCELLED; + } +} + +static void PAINT_OT_vertex_color_levels(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Paint Levels"; + ot->idname = "PAINT_OT_vertex_color_levels"; + ot->description = "Adjust levels of vertex colors"; + + /* api callbacks */ + ot->exec = vertex_color_levels_exec; + ot->poll = vertex_paint_mode_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* params */ + RNA_def_float(ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f); + RNA_def_float(ot->srna, "gain", 1.0f, 0.0f, FLT_MAX, "Gain", "Value to multiply colors by", 0.0f, 10.0f); +} + +/** \} */ + + static int brush_reset_exec(bContext *C, wmOperator *UNUSED(op)) { Paint *paint = BKE_paint_get_active_from_context(C); @@ -1112,6 +1347,11 @@ void ED_operatortypes_paint(void) WM_operatortype_append(PAINT_OT_vertex_color_set); WM_operatortype_append(PAINT_OT_vertex_color_smooth); + WM_operatortype_append(PAINT_OT_vertex_color_brightness_contrast); + WM_operatortype_append(PAINT_OT_vertex_color_hsv); + WM_operatortype_append(PAINT_OT_vertex_color_invert); + WM_operatortype_append(PAINT_OT_vertex_color_levels); + /* face-select */ WM_operatortype_append(PAINT_OT_face_select_linked); WM_operatortype_append(PAINT_OT_face_select_linked_pick); diff --git a/source/blender/editors/sculpt_paint/paint_stroke.c b/source/blender/editors/sculpt_paint/paint_stroke.c index 67fbd000b64..1431958501d 100644 --- a/source/blender/editors/sculpt_paint/paint_stroke.c +++ b/source/blender/editors/sculpt_paint/paint_stroke.c @@ -491,31 +491,30 @@ static void paint_brush_stroke_add_step(bContext *C, wmOperator *op, const float } /* Returns zero if no sculpt changes should be made, non-zero otherwise */ -static int paint_smooth_stroke(PaintStroke *stroke, float output[2], float *outpressure, - const PaintSample *sample, PaintMode mode) +static bool paint_smooth_stroke( + PaintStroke *stroke, const PaintSample *sample, PaintMode mode, + float r_mouse[2], float *r_pressure) { if (paint_supports_smooth_stroke(stroke->brush, mode)) { float radius = stroke->brush->smooth_stroke_radius * stroke->zoom_2d; - float u = stroke->brush->smooth_stroke_factor, v = 1.0f - u; - float dx = stroke->last_mouse_position[0] - sample->mouse[0]; - float dy = stroke->last_mouse_position[1] - sample->mouse[1]; + float u = stroke->brush->smooth_stroke_factor; /* If the mouse is moving within the radius of the last move, * don't update the mouse position. This allows sharp turns. */ - if (dx * dx + dy * dy < radius * radius) - return 0; + if (len_squared_v2v2(stroke->last_mouse_position, sample->mouse) < SQUARE(radius)) { + return false; + } - output[0] = sample->mouse[0] * v + stroke->last_mouse_position[0] * u; - output[1] = sample->mouse[1] * v + stroke->last_mouse_position[1] * u; - *outpressure = sample->pressure * v + stroke->last_pressure * u; + interp_v2_v2v2(r_mouse, sample->mouse, stroke->last_mouse_position, u); + *r_pressure = interpf(sample->pressure, stroke->last_pressure, u); } else { - output[0] = sample->mouse[0]; - output[1] = sample->mouse[1]; - *outpressure = sample->pressure; + r_mouse[0] = sample->mouse[0]; + r_mouse[1] = sample->mouse[1]; + *r_pressure = sample->pressure; } - return 1; + return true; } static float paint_space_stroke_spacing(const Scene *scene, PaintStroke *stroke, float size_pressure, float spacing_pressure) @@ -1158,7 +1157,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) if (event->val == KM_RELEASE) { copy_v2_fl2(mouse, event->mval[0], event->mval[1]); paint_stroke_line_constrain(stroke, mouse); - paint_stroke_line_end (C, op, stroke, mouse); + paint_stroke_line_end(C, op, stroke, mouse); stroke_done(C, op); return OPERATOR_FINISHED; } @@ -1190,7 +1189,7 @@ int paint_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event) /* airbrush */ ((br->flag & BRUSH_AIRBRUSH) && event->type == TIMER && event->customdata == stroke->timer)) { - if (paint_smooth_stroke(stroke, mouse, &pressure, &sample_average, mode)) { + if (paint_smooth_stroke(stroke, &sample_average, mode, mouse, &pressure)) { if (stroke->stroke_started) { if (paint_space_stroke_enabled(br, mode)) { if (paint_space_stroke(C, op, mouse, pressure)) diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 2a1e7704b51..7b296473f31 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -247,7 +247,7 @@ static bool make_vertexcol(Object *ob) /* single ob */ { Mesh *me; - if ((ob->id.lib) || + if (ID_IS_LINKED_DATABLOCK(ob) || ((me = BKE_mesh_from_object(ob)) == NULL) || (me->totpoly == 0) || (me->edit_btmesh)) @@ -502,6 +502,51 @@ bool ED_vpaint_smooth(Object *ob) return true; } +/** + * Apply callback to each vertex of the active vertex color layer. + */ +bool ED_vpaint_color_transform( + struct Object *ob, + VPaintTransform_Callback vpaint_tx_fn, + const void *user_data) +{ + Mesh *me; + const MPoly *mp; + + if (((me = BKE_mesh_from_object(ob)) == NULL) || + (me->mloopcol == NULL && (make_vertexcol(ob) == false))) + { + return false; + } + + const bool do_face_sel = (me->editflag & ME_EDIT_PAINT_FACE_SEL) != 0; + mp = me->mpoly; + + for (int i = 0; i < me->totpoly; i++, mp++) { + MLoopCol *lcol = &me->mloopcol[mp->loopstart]; + + if (do_face_sel && !(mp->flag & ME_FACE_SEL)) { + continue; + } + + for (int j = 0; j < mp->totloop; j++, lcol++) { + float col[3]; + rgb_uchar_to_float(col, &lcol->r); + + vpaint_tx_fn(col, user_data, col); + + rgb_float_to_uchar(&lcol->r, col); + } + } + + /* remove stale me->mcol, will be added later */ + BKE_mesh_tessface_clear(me); + + DAG_id_tag_update(&me->id, 0); + + return true; +} + /* XXX: should be re-implemented as a vertex/weight paint 'color correct' operator */ #if 0 void vpaint_dogamma(Scene *scene) @@ -1796,7 +1841,7 @@ static int paint_poll_test(bContext *C) Object *ob = CTX_data_active_object(C); if (ob == NULL || ob->type != OB_MESH) return 0; - if (!ob->data || ((ID *)ob->data)->lib) + if (!ob->data || ID_IS_LINKED_DATABLOCK(ob->data)) return 0; if (CTX_data_edit_object(C)) return 0; @@ -2335,9 +2380,8 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P swap_m4m4(vc->rv3d->persmat, mat); /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); DAG_id_tag_update(ob->data, 0); ED_region_tag_redraw(vc->ar); @@ -2813,9 +2857,8 @@ static void vpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P } /* calculate pivot for rotation around seletion if needed */ - if (U.uiflag & USER_ORBIT_SELECTION) { - paint_last_stroke_update(scene, vc->ar, mval); - } + /* also needed for "View Selected" on last stroke */ + paint_last_stroke_update(scene, vc->ar, mval); ED_region_tag_redraw(vc->ar); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index c173156de3a..1305b76b5ad 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -1145,7 +1145,9 @@ static void calc_area_normal_and_center( /* Return modified brush strength. Includes the direction of the brush, positive * values pull vertices, negative values push. Uses tablet pressure and a * special multiplier found experimentally to scale the strength factor. */ -static float brush_strength(const Sculpt *sd, const StrokeCache *cache, const float feather, const UnifiedPaintSettings *ups) +static float brush_strength( + const Sculpt *sd, const StrokeCache *cache, + const float feather, const UnifiedPaintSettings *ups) { const Scene *scene = cache->vc->scene; const Brush *brush = BKE_paint_brush((Paint *)&sd->paint); @@ -3985,7 +3987,9 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) } /* Initialize the stroke cache invariants from operator properties */ -static void sculpt_update_cache_invariants(bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) +static void sculpt_update_cache_invariants( + bContext *C, Sculpt *sd, SculptSession *ss, + wmOperator *op, const float mouse[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); Scene *scene = CTX_data_scene(C); @@ -4448,7 +4452,9 @@ static void sculpt_raycast_detail_cb(PBVHNode *node, void *data_v, float *tmin) } } -static float sculpt_raycast_init(ViewContext *vc, const float mouse[2], float ray_start[3], float ray_end[3], float ray_normal[3], bool original) +static float sculpt_raycast_init( + ViewContext *vc, const float mouse[2], + float ray_start[3], float ray_end[3], float ray_normal[3], bool original) { float obimat[4][4]; float dist; @@ -4956,8 +4962,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->vdata, CD_PROP_INT, layer_id); } - ss->cd_vert_node_offset = CustomData_get_n_offset(&ss->bm->vdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); + ss->cd_vert_node_offset = CustomData_get_n_offset( + &ss->bm->vdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->vdata, CD_PROP_INT)); ss->bm->vdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; @@ -4967,8 +4974,9 @@ void sculpt_dyntopo_node_layers_add(SculptSession *ss) cd_node_layer_index = CustomData_get_named_layer_index(&ss->bm->pdata, CD_PROP_INT, layer_id); } - ss->cd_face_node_offset = CustomData_get_n_offset(&ss->bm->pdata, CD_PROP_INT, - cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); + ss->cd_face_node_offset = CustomData_get_n_offset( + &ss->bm->pdata, CD_PROP_INT, + cd_node_layer_index - CustomData_get_layer_index(&ss->bm->pdata, CD_PROP_INT)); ss->bm->pdata.layers[cd_node_layer_index].flag |= CD_FLAG_TEMPORARY; } @@ -5001,7 +5009,9 @@ void sculpt_dynamic_topology_enable(bContext *C) BKE_mesh_mselect_clear(me); /* Create triangles-only BMesh */ - ss->bm = BM_mesh_create(&allocsize); + ss->bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); BM_mesh_bm_from_me( ss->bm, me, (&(struct BMeshFromMeshParams){ @@ -5011,7 +5021,9 @@ void sculpt_dynamic_topology_enable(bContext *C) BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); sculpt_dyntopo_node_layers_add(ss); /* make sure the data for existing faces are initialized */ - BM_mesh_normals_update(ss->bm); + if (me->totpoly != ss->bm->totface) { + BM_mesh_normals_update(ss->bm); + } /* Enable dynamic topology */ me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; @@ -5088,6 +5100,8 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o Object *ob = CTX_data_active_object(C); SculptSession *ss = ob->sculpt; + WM_cursor_wait(1); + if (ss->bm) { sculpt_undo_push_begin("Dynamic topology disable"); sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_END); @@ -5100,16 +5114,24 @@ static int sculpt_dynamic_topology_toggle_exec(bContext *C, wmOperator *UNUSED(o } sculpt_undo_push_end(C); + WM_cursor_wait(0); + return OPERATOR_FINISHED; } +enum eDynTopoWarnFlag { + DYNTOPO_WARN_VDATA = (1 << 0), + DYNTOPO_WARN_EDATA = (1 << 1), + DYNTOPO_WARN_LDATA = (1 << 2), + DYNTOPO_WARN_MODIFIER = (1 << 3), +}; -static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bool modifiers) +static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, enum eDynTopoWarnFlag flag) { uiPopupMenu *pup = UI_popup_menu_begin(C, IFACE_("Warning!"), ICON_ERROR); uiLayout *layout = UI_popup_menu_layout(pup); - if (vdata) { + if (flag & (DYNTOPO_WARN_VDATA | DYNTOPO_WARN_EDATA | DYNTOPO_WARN_LDATA)) { const char *msg_error = TIP_("Vertex Data Detected!"); const char *msg = TIP_("Dyntopo will not preserve vertex colors, UVs, or other customdata"); uiItemL(layout, msg_error, ICON_INFO); @@ -5117,7 +5139,7 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo uiItemS(layout); } - if (modifiers) { + if (flag & DYNTOPO_WARN_MODIFIER) { const char *msg_error = TIP_("Generative Modifiers Detected!"); const char *msg = TIP_("Keeping the modifiers will increase polycount when returning to object mode"); @@ -5133,33 +5155,35 @@ static int dyntopo_warning_popup(bContext *C, wmOperatorType *ot, bool vdata, bo return OPERATOR_INTERFACE; } - -static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +static enum eDynTopoWarnFlag sculpt_dynamic_topology_check(bContext *C) { Object *ob = CTX_data_active_object(C); Mesh *me = ob->data; SculptSession *ss = ob->sculpt; - if (!ss->bm) { - Scene *scene = CTX_data_scene(C); - ModifierData *md; - VirtualModifierData virtualModifierData; - int i; - bool vdata = false; - bool modifiers = false; - - for (i = 0; i < CD_NUMTYPES; i++) { - if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX) && - (CustomData_has_layer(&me->vdata, i) || - CustomData_has_layer(&me->edata, i) || - CustomData_has_layer(&me->ldata, i))) - { - vdata = true; - break; + Scene *scene = CTX_data_scene(C); + enum eDynTopoWarnFlag flag = 0; + + BLI_assert(ss->bm == NULL); + UNUSED_VARS_NDEBUG(ss); + + for (int i = 0; i < CD_NUMTYPES; i++) { + if (!ELEM(i, CD_MVERT, CD_MEDGE, CD_MFACE, CD_MLOOP, CD_MPOLY, CD_PAINT_MASK, CD_ORIGINDEX)) { + if (CustomData_has_layer(&me->vdata, i)) { + flag |= DYNTOPO_WARN_VDATA; + } + if (CustomData_has_layer(&me->edata, i)) { + flag |= DYNTOPO_WARN_EDATA; + } + if (CustomData_has_layer(&me->ldata, i)) { + flag |= DYNTOPO_WARN_LDATA; } } + } - md = modifiers_getVirtualModifierList(ob, &virtualModifierData); + { + VirtualModifierData virtualModifierData; + ModifierData *md = modifiers_getVirtualModifierList(ob, &virtualModifierData); /* exception for shape keys because we can edit those */ for (; md; md = md->next) { @@ -5167,14 +5191,26 @@ static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, co if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) continue; if (mti->type == eModifierTypeType_Constructive) { - modifiers = true; + flag |= DYNTOPO_WARN_MODIFIER; break; } } + } - if (vdata || modifiers) { + return flag; +} + +static int sculpt_dynamic_topology_toggle_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (!ss->bm) { + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); + + if (flag) { /* The mesh has customdata that will be lost, let the user confirm this is OK */ - return dyntopo_warning_popup(C, op->type, vdata, modifiers); + return dyntopo_warning_popup(C, op->type, flag); } } @@ -5249,6 +5285,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); BM_log_before_all_removed(ss->bm, ss->bm_log); + BM_mesh_toolflags_set(ss->bm, true); + /* Symmetrize and re-triangulate */ BMO_op_callf(ss->bm, BMO_FLAG_DEFAULTS, "symmetrize input=%avef direction=%i dist=%f", @@ -5258,6 +5296,8 @@ static int sculpt_symmetrize_exec(bContext *C, wmOperator *UNUSED(op)) /* bisect operator flags edges (keep tags clean for edge queue) */ BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); + BM_mesh_toolflags_set(ss->bm, false); + /* Finish undo */ BM_log_all_added(ss->bm, ss->bm_log); sculpt_undo_push_end(C); @@ -5327,6 +5367,9 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) * mode to ensure the undo stack stays in a consistent * state */ sculpt_dynamic_topology_toggle_exec(C, NULL); + + /* store so we know to re-enable when entering sculpt mode */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; } /* Leave sculptmode */ @@ -5340,12 +5383,6 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) /* Enter sculptmode */ ob->mode |= mode_flag; - /* Remove dynamic-topology flag; this will be enabled if the - * file was saved with dynamic topology on, but we don't - * automatically re-enter dynamic-topology mode when loading a - * file. */ - me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; - if (flush_recalc) DAG_id_tag_update(&ob->id, OB_RECALC_DATA); @@ -5399,6 +5436,52 @@ static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) BKE_paint_init(scene, ePaintSculpt, PAINT_CURSOR_SCULPT); paint_cursor_start(C, sculpt_poll_view3d); + + /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, + * As long as no data was added that is not supported. */ + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + const char *message_unsupported = NULL; + if (me->totloop != me->totpoly * 3) { + message_unsupported = TIP_("non-triangle face"); + } + else if (mmd != NULL) { + message_unsupported = TIP_("multi-res modifier"); + } + else { + enum eDynTopoWarnFlag flag = sculpt_dynamic_topology_check(C); + if (flag == 0) { + /* pass */ + } + else if (flag & DYNTOPO_WARN_VDATA) { + message_unsupported = TIP_("vertex data"); + } + else if (flag & DYNTOPO_WARN_EDATA) { + message_unsupported = TIP_("edge data"); + } + else if (flag & DYNTOPO_WARN_LDATA) { + message_unsupported = TIP_("face data"); + } + else if (flag & DYNTOPO_WARN_MODIFIER) { + message_unsupported = TIP_("constructive modifier"); + } + else { + BLI_assert(0); + } + } + + if (message_unsupported == NULL) { + /* undo push is needed to prevent memory leak */ + sculpt_undo_push_begin("Dynamic topology enable"); + sculpt_dynamic_topology_enable(C); + sculpt_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + } + else { + BKE_reportf(op->reports, RPT_WARNING, + "Dynamic Topology found: %s, disabled", + message_unsupported); + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + } + } } if (ob->derivedFinal) /* VBO no longer valid */ @@ -5592,7 +5675,8 @@ static void SCULPT_OT_sample_detail_size(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); + RNA_def_int_array(ot->srna, "location", 2, NULL, 0, SHRT_MAX, + "Location", "Screen Coordinates of sampling", 0, SHRT_MAX); } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index ceefda99002..44bd872d107 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -366,7 +366,9 @@ static void sculpt_undo_bmesh_enable(Object *ob, sculpt_pbvh_clear(ob); /* Create empty BMesh and enable logging */ - ss->bm = BM_mesh_create(&bm_mesh_allocsize_default); + ss->bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); BM_data_layer_add(ss->bm, &ss->bm->vdata, CD_PAINT_MASK); sculpt_dyntopo_node_layers_add(ss); me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; diff --git a/source/blender/editors/sound/sound_ops.c b/source/blender/editors/sound/sound_ops.c index a4d9a920cbb..4931426d62e 100644 --- a/source/blender/editors/sound/sound_ops.c +++ b/source/blender/editors/sound/sound_ops.c @@ -116,7 +116,7 @@ static int sound_open_exec(bContext *C, wmOperator *op) info = AUD_getInfo(sound->playback_handle); if (info.specs.channels == AUD_CHANNELS_INVALID) { - BKE_sound_delete(bmain, sound); + BKE_libblock_free(bmain, sound); if (op->customdata) MEM_freeN(op->customdata); BKE_report(op->reports, RPT_ERROR, "Unsupported audio format"); return OPERATOR_CANCELLED; diff --git a/source/blender/editors/space_action/action_data.c b/source/blender/editors/space_action/action_data.c index a3be7791f9a..6755a6316cc 100644 --- a/source/blender/editors/space_action/action_data.c +++ b/source/blender/editors/space_action/action_data.c @@ -121,7 +121,7 @@ static bAction *action_create_new(bContext *C, bAction *oldact) */ if (oldact && GS(oldact->id.name) == ID_AC) { /* make a copy of the existing action */ - action = BKE_action_copy(oldact); + action = BKE_action_copy(CTX_data_main(C), oldact); } else { /* just make a new (empty) action */ diff --git a/source/blender/editors/space_action/action_draw.c b/source/blender/editors/space_action/action_draw.c index 10748c2fe15..9fc96e06299 100644 --- a/source/blender/editors/space_action/action_draw.c +++ b/source/blender/editors/space_action/action_draw.c @@ -81,7 +81,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); + height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); if (height > BLI_rcti_size_y(&v2d->mask)) { /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) @@ -95,11 +95,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; - y = (float)ACHANNEL_FIRST; + y = (float)ACHANNEL_FIRST(ac); for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -110,7 +110,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) } /* adjust y-position for next one */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); channel_index++; } } @@ -118,11 +118,11 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - y = (float)ACHANNEL_FIRST; + y = (float)ACHANNEL_FIRST(ac); for (ale = anim_data.first; ale; ale = ale->next) { - float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -133,7 +133,7 @@ void draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) } /* adjust y-position for next one */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); channel_index++; } @@ -195,19 +195,19 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); items = ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); - height = ((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT)); + height = ((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac))); /* don't use totrect set, as the width stays the same * (NOTE: this is ok here, the configuration is pretty straightforward) */ v2d->tot.ymin = (float)(-height); /* first backdrop strips */ - y = (float)(-ACHANNEL_HEIGHT); + y = (float)(-ACHANNEL_HEIGHT(ac)); glEnable(GL_BLEND); for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -260,39 +260,39 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) } /* draw region twice: firstly backdrop, then the current range */ - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); if (ac->datatype == ANIMCONT_ACTION) - glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF, act_end, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(act_start, (float)y - ACHANNEL_HEIGHT_HALF(ac), act_end, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_GPENCIL) { /* frames less than one get less saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } else if (ac->datatype == ANIMCONT_MASK) { /* TODO --- this is a copy of gpencil */ /* frames less than one get less saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x22); else glColor4ub(col2[0], col2[1], col2[2], 0x22); - glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(0.0f, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmin, (float)y + ACHANNEL_HEIGHT_HALF(ac)); /* frames one and higher get a saturated background */ if (sel) glColor4ub(col1[0], col1[1], col1[2], 0x44); else glColor4ub(col2[0], col2[1], col2[2], 0x44); - glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF, v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF); + glRectf(v2d->cur.xmin, (float)y - ACHANNEL_HEIGHT_HALF(ac), v2d->cur.xmax + EXTRA_SCROLL_PAD, (float)y + ACHANNEL_HEIGHT_HALF(ac)); } } } /* Increment the step */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); } glDisable(GL_BLEND); @@ -301,11 +301,11 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) * This is to try to optimize this for heavier data sets * 2) Keyframes which are out of view horizontally are disregarded */ - y = (float)(-ACHANNEL_HEIGHT); + y = (float)(-ACHANNEL_HEIGHT(ac)); for (ale = anim_data.first; ale; ale = ale->next) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -318,34 +318,34 @@ void draw_channel_strips(bAnimContext *ac, SpaceAction *saction, ARegion *ar) /* draw 'keyframes' for each specific datatype */ switch (ale->datatype) { case ALE_ALL: - draw_summary_channel(v2d, ale->data, y); + draw_summary_channel(v2d, ale->data, y, ac->yscale_fac); break; case ALE_SCE: - draw_scene_channel(v2d, ads, ale->key_data, y); + draw_scene_channel(v2d, ads, ale->key_data, y, ac->yscale_fac); break; case ALE_OB: - draw_object_channel(v2d, ads, ale->key_data, y); + draw_object_channel(v2d, ads, ale->key_data, y, ac->yscale_fac); break; case ALE_ACT: - draw_action_channel(v2d, adt, ale->key_data, y); + draw_action_channel(v2d, adt, ale->key_data, y, ac->yscale_fac); break; case ALE_GROUP: - draw_agroup_channel(v2d, adt, ale->data, y); + draw_agroup_channel(v2d, adt, ale->data, y, ac->yscale_fac); break; case ALE_FCURVE: - draw_fcurve_channel(v2d, adt, ale->key_data, y); + draw_fcurve_channel(v2d, adt, ale->key_data, y, ac->yscale_fac); break; case ALE_GPFRAME: - draw_gpl_channel(v2d, ads, ale->data, y); + draw_gpl_channel(v2d, ads, ale->data, y, ac->yscale_fac); break; case ALE_MASKLAY: - draw_masklay_channel(v2d, ads, ale->data, y); + draw_masklay_channel(v2d, ads, ale->data, y, ac->yscale_fac); break; } } } - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); } /* free tempolary channels used for drawing */ diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index 8261a211ed0..55b087c40e7 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -333,7 +333,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); /* loop through all channels, finding the first one that's selected */ - y = (float)ACHANNEL_FIRST; + y = (float)ACHANNEL_FIRST(ac); for (ale = anim_data.first; ale; ale = ale->next) { const bAnimChannelType *acf = ANIM_channel_get_typeinfo(ale); @@ -343,8 +343,8 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, ANIM_channel_setting_get(ac, ale, ACHANNEL_SETTING_SELECT)) { /* update best estimate */ - *min = (float)(y - ACHANNEL_HEIGHT_HALF); - *max = (float)(y + ACHANNEL_HEIGHT_HALF); + *min = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + *max = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* is this high enough priority yet? */ found = acf->channel_role; @@ -358,7 +358,7 @@ static bool actkeys_channels_get_selected_extents(bAnimContext *ac, float *min, } /* adjust y-position for next one */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); } /* free all temp data */ diff --git a/source/blender/editors/space_action/action_intern.h b/source/blender/editors/space_action/action_intern.h index 50e10e7e154..408eb38d386 100644 --- a/source/blender/editors/space_action/action_intern.h +++ b/source/blender/editors/space_action/action_intern.h @@ -59,6 +59,8 @@ void draw_channel_strips(struct bAnimContext *ac, struct SpaceAction *saction, s void ACTION_OT_select_all_toggle(struct wmOperatorType *ot); void ACTION_OT_select_border(struct wmOperatorType *ot); +void ACTION_OT_select_lasso(struct wmOperatorType *ot); +void ACTION_OT_select_circle(struct wmOperatorType *ot); void ACTION_OT_select_column(struct wmOperatorType *ot); void ACTION_OT_select_linked(struct wmOperatorType *ot); void ACTION_OT_select_more(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_action/action_ops.c b/source/blender/editors/space_action/action_ops.c index f69f9944f8a..a261202b690 100644 --- a/source/blender/editors/space_action/action_ops.c +++ b/source/blender/editors/space_action/action_ops.c @@ -59,6 +59,8 @@ void action_operatortypes(void) WM_operatortype_append(ACTION_OT_clickselect); WM_operatortype_append(ACTION_OT_select_all_toggle); WM_operatortype_append(ACTION_OT_select_border); + WM_operatortype_append(ACTION_OT_select_lasso); + WM_operatortype_append(ACTION_OT_select_circle); WM_operatortype_append(ACTION_OT_select_column); WM_operatortype_append(ACTION_OT_select_linked); WM_operatortype_append(ACTION_OT_select_more); @@ -178,6 +180,14 @@ static void action_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); + /* region select */ + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); + RNA_boolean_set(kmi->ptr, "deselect", false); + kmi = WM_keymap_add_item(keymap, "ACTION_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); + RNA_boolean_set(kmi->ptr, "deselect", true); + + WM_keymap_add_item(keymap, "ACTION_OT_select_circle", CKEY, KM_PRESS, 0, 0); + /* column select */ RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, 0, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_KEYS); RNA_enum_set(WM_keymap_add_item(keymap, "ACTION_OT_select_column", KKEY, KM_PRESS, KM_CTRL, 0)->ptr, "mode", ACTKEYS_COLUMNSEL_CFRA); diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c index f2813b2a8d3..553be0ad290 100644 --- a/source/blender/editors/space_action/action_select.c +++ b/source/blender/editors/space_action/action_select.c @@ -36,6 +36,7 @@ #include "BLI_blenlib.h" #include "BLI_dlrbTree.h" +#include "BLI_lasso.h" #include "BLI_utildefines.h" #include "DNA_anim_types.h" @@ -212,7 +213,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s KeyframeEditFunc ok_cb, select_cb; View2D *v2d = &ac->ar->v2d; rctf rectf; - float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF); + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ UI_view2d_region_to_view(v2d, rect.xmin, rect.ymin + 2, &rectf.xmin, &rectf.ymin); @@ -238,7 +239,7 @@ static void borderselect_action(bAnimContext *ac, const rcti rect, short mode, s AnimData *adt = ANIM_nla_mapping_get(ac, ale); /* get new vertical minimum extent of channel */ - ymin = ymax - ACHANNEL_STEP; + ymin = ymax - ACHANNEL_STEP(ac); /* set horizontal range (if applicable) */ if (ELEM(mode, ACTKEYS_BORDERSEL_FRAMERANGE, ACTKEYS_BORDERSEL_ALLKEYS)) { @@ -375,6 +376,264 @@ void ACTION_OT_select_border(wmOperatorType *ot) ot->prop = RNA_def_boolean(ot->srna, "axis_range", 0, "Axis Range", ""); } +/* ******************** Region Select Operators ***************************** */ +/* "Region Select" operators include the Lasso and Circle Select operators. + * These two ended up being lumped together, as it was easier in the + * original Graph Editor implementation of these to do it this way. + */ + +static void region_select_action_keys(bAnimContext *ac, const rctf *rectf_view, short mode, short selectmode, void *data) +{ + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + int filter; + + KeyframeEditData ked; + KeyframeEditFunc ok_cb, select_cb; + View2D *v2d = &ac->ar->v2d; + rctf rectf, scaled_rectf; + float ymin = 0, ymax = (float)(-ACHANNEL_HEIGHT_HALF(ac)); + + /* convert mouse coordinates to frame ranges and channel coordinates corrected for view pan/zoom */ + UI_view2d_region_to_view_rctf(v2d, rectf_view, &rectf); + + /* filter data */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS | ANIMFILTER_NODUPLIS); + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* get beztriple editing/validation funcs */ + select_cb = ANIM_editkeyframes_select(selectmode); + ok_cb = ANIM_editkeyframes_ok(mode); + + /* init editing data */ + memset(&ked, 0, sizeof(KeyframeEditData)); + if (mode == BEZT_OK_CHANNEL_LASSO) { + KeyframeEdit_LassoData *data_lasso = data; + data_lasso->rectf_scaled = &scaled_rectf; + ked.data = data_lasso; + } + else if (mode == BEZT_OK_CHANNEL_CIRCLE) { + KeyframeEdit_CircleData *data_circle = data; + data_circle->rectf_scaled = &scaled_rectf; + ked.data = data; + } + else { + ked.data = &scaled_rectf; + } + + /* loop over data, doing region select */ + for (ale = anim_data.first; ale; ale = ale->next) { + AnimData *adt = ANIM_nla_mapping_get(ac, ale); + + /* get new vertical minimum extent of channel */ + ymin = ymax - ACHANNEL_STEP(ac); + + /* compute midpoint of channel (used for testing if the key is in the region or not) */ + ked.channel_y = ymin + ACHANNEL_HEIGHT_HALF(ac); + + /* if channel is mapped in NLA, apply correction + * - Apply to the bounds being checked, not all the keyframe points, + * to avoid having scaling everything + * - Save result to the scaled_rect, which is all that these operators + * will read from + */ + if (adt) { + ked.iterflags &= ~(KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); + ked.f1 = BKE_nla_tweakedit_remap(adt, rectf.xmin, NLATIME_CONVERT_UNMAP); + ked.f2 = BKE_nla_tweakedit_remap(adt, rectf.xmax, NLATIME_CONVERT_UNMAP); + } + else { + ked.iterflags |= (KED_F1_NLA_UNMAP | KED_F2_NLA_UNMAP); /* for summary tracks */ + ked.f1 = rectf.xmin; + ked.f2 = rectf.xmax; + } + + /* Update values for scaled_rectf - which is used to compute the mapping in the callbacks + * NOTE: Since summary tracks need late-binding remapping, the callbacks may overwrite these + * with the properly remapped ked.f1/f2 values, when needed + */ + scaled_rectf.xmin = ked.f1; + scaled_rectf.xmax = ked.f2; + scaled_rectf.ymin = ymin; + scaled_rectf.ymax = ymax; + + /* perform vertical suitability check (if applicable) */ + if ((mode == ACTKEYS_BORDERSEL_FRAMERANGE) || + !((ymax < rectf.ymin) || (ymin > rectf.ymax))) + { + /* loop over data selecting */ + switch (ale->type) { + case ANIMTYPE_GPDATABLOCK: + { + bGPdata *gpd = ale->data; + bGPDlayer *gpl; + for (gpl = gpd->layers.first; gpl; gpl = gpl->next) { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + } + break; + } + case ANIMTYPE_GPLAYER: + { + ED_gplayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + case ANIMTYPE_MASKDATABLOCK: + { + Mask *mask = ale->data; + MaskLayer *masklay; + for (masklay = mask->masklayers.first; masklay; masklay = masklay->next) { + ED_masklayer_frames_select_region(&ked, masklay, mode, selectmode); + } + break; + } + case ANIMTYPE_MASKLAYER: + { + ED_masklayer_frames_select_region(&ked, ale->data, mode, selectmode); + break; + } + default: + ANIM_animchannel_keyframes_loop(&ked, ac->ads, ale, ok_cb, select_cb, NULL); + break; + } + } + + /* set minimum extent to be the maximum of the next channel */ + ymax = ymin; + } + + /* cleanup */ + ANIM_animdata_freelist(&anim_data); +} + +/* ----------------------------------- */ + +static int actkeys_lassoselect_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + KeyframeEdit_LassoData data_lasso; + rcti rect; + rctf rect_fl; + + short selectmode; + bool extend; + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data_lasso.rectf_view = &rect_fl; + data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); + if (data_lasso.mcords == NULL) + return OPERATOR_CANCELLED; + + /* clear all selection if not extending selection */ + extend = RNA_boolean_get(op->ptr, "extend"); + if (!extend) + deselect_action_keys(&ac, 1, SELECT_SUBTRACT); + + if (!RNA_boolean_get(op->ptr, "deselect")) + selectmode = SELECT_ADD; + else + selectmode = SELECT_SUBTRACT; + + /* get settings from operator */ + BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); + BLI_rctf_rcti_copy(&rect_fl, &rect); + + /* apply borderselect action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_LASSO, selectmode, &data_lasso); + + MEM_freeN((void *)data_lasso.mcords); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_lasso(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Lasso Select"; + ot->description = "Select keyframe points using lasso selection"; + ot->idname = "ACTION_OT_select_lasso"; + + /* api callbacks */ + ot->invoke = WM_gesture_lasso_invoke; + ot->modal = WM_gesture_lasso_modal; + ot->exec = actkeys_lassoselect_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_lasso_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); + RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); + RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); +} + +/* ------------------- */ + +static int action_circle_select_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + + KeyframeEdit_CircleData data = {0}; + rctf rect_fl; + + float x = RNA_int_get(op->ptr, "x"); + float y = RNA_int_get(op->ptr, "y"); + float radius = RNA_int_get(op->ptr, "radius"); + + /* get editor data */ + if (ANIM_animdata_get_context(C, &ac) == 0) + return OPERATOR_CANCELLED; + + data.mval[0] = x; + data.mval[1] = y; + data.radius_squared = radius * radius; + data.rectf_view = &rect_fl; + + rect_fl.xmin = x - radius; + rect_fl.xmax = x + radius; + rect_fl.ymin = y - radius; + rect_fl.ymax = y + radius; + + /* apply region select action */ + region_select_action_keys(&ac, &rect_fl, BEZT_OK_CHANNEL_CIRCLE, selectmode, &data); + + /* send notifier that keyframe selection has changed */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); + + return OPERATOR_FINISHED; +} + +void ACTION_OT_select_circle(wmOperatorType *ot) +{ + ot->name = "Circle Select"; + ot->description = "Select keyframe points using circle selection"; + ot->idname = "ACTION_OT_select_circle"; + + ot->invoke = WM_gesture_circle_invoke; + ot->modal = WM_gesture_circle_modal; + ot->exec = action_circle_select_exec; + ot->poll = ED_operator_action_active; + ot->cancel = WM_gesture_circle_cancel; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + RNA_def_int(ot->srna, "x", 0, INT_MIN, INT_MAX, "X", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "y", 0, INT_MIN, INT_MAX, "Y", "", INT_MIN, INT_MAX); + RNA_def_int(ot->srna, "radius", 1, 1, INT_MAX, "Radius", "", 1, INT_MAX); + RNA_def_int(ot->srna, "gesture_mode", 0, INT_MIN, INT_MAX, "Event Type", "", INT_MIN, INT_MAX); +} + /* ******************** Column Select Operator **************************** */ /* This operator works in one of four ways: * - 1) select all keyframes in the same frame as a selected one (KKEY) @@ -1092,6 +1351,7 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ bool found = false; float frame = 0.0f; /* frame of keyframe under mouse - NLA corrections not applied/included */ float selx = 0.0f; /* frame of keyframe under mouse */ + float key_hsize; float x, y; rctf rectf; @@ -1101,11 +1361,16 @@ static void mouse_action_keys(bAnimContext *ac, const int mval[2], short select_ /* use View2D to determine the index of the channel (i.e a row in the list) where keyframe was */ UI_view2d_region_to_view(v2d, mval[0], mval[1], &x, &y); - UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP, 0, (float)ACHANNEL_HEIGHT_HALF, x, y, NULL, &channel_index); + UI_view2d_listview_view_to_cell(v2d, 0, ACHANNEL_STEP(ac), 0, (float)ACHANNEL_HEIGHT_HALF(ac), x, y, NULL, &channel_index); + + /* x-range to check is +/- 7px for standard keyframe under standard dpi/y-scale (in screen/region-space), + * on either side of mouse click (size of keyframe icon) + */ + key_hsize = ACHANNEL_HEIGHT(ac) * 0.8f; /* standard channel height (to allow for some slop) */ + key_hsize = roundf(key_hsize / 2.0f); /* half-size (for either side), but rounded up to nearest int (for easier targetting) */ - /* x-range to check is +/- 7 (in screen/region-space) on either side of mouse click (size of keyframe icon) */ - UI_view2d_region_to_view(v2d, mval[0] - 7, mval[1], &rectf.xmin, &rectf.ymin); - UI_view2d_region_to_view(v2d, mval[0] + 7, mval[1], &rectf.xmax, &rectf.ymax); + UI_view2d_region_to_view(v2d, mval[0] - (int)key_hsize, mval[1], &rectf.xmin, &rectf.ymin); + UI_view2d_region_to_view(v2d, mval[0] + (int)key_hsize, mval[1], &rectf.xmax, &rectf.ymax); /* filter data */ filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_LIST_VISIBLE | ANIMFILTER_LIST_CHANNELS); diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 60240109432..671d6bb083e 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_action_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -614,6 +615,19 @@ static void action_refresh(const bContext *C, ScrArea *sa) // XXX re-sizing y-extents of tot should go here? } +static void action_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceAction *sact = (SpaceAction *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sact->ads.filter_grp == old_id) { + sact->ads.filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_action(void) { @@ -631,7 +645,8 @@ void ED_spacetype_action(void) st->keymap = action_keymap; st->listener = action_listener; st->refresh = action_refresh; - + st->id_remap = action_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype action region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 42e2d6b90f0..5b03bdd7761 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -1180,33 +1180,3 @@ ID *buttons_context_id_path(const bContext *C) return NULL; } - -void ED_buttons_id_unref(SpaceButs *sbuts, const ID *id) -{ - if (sbuts->pinid == id) { - sbuts->pinid = NULL; - sbuts->flag &= ~SB_PIN_CONTEXT; - } - - if (sbuts->path) { - ButsContextPath *path = sbuts->path; - int i; - - for (i = 0; i < path->len; i++) { - if (path->ptr[i].id.data == id) { - break; - } - } - - if (i == path->len) { - /* pass */ - } - else if (i == 0) { - MEM_SAFE_FREE(sbuts->path); - } - else { - memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); - path->len = i; - } - } -} diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 126a27c36cb..e4c23ad74f8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -45,6 +45,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" + #include "buttons_intern.h" /* own include */ /* ******************** default callbacks for buttons space ***************** */ @@ -389,6 +391,59 @@ static void buttons_area_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier * ED_area_tag_redraw(sa); } +static void buttons_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceButs *sbuts = (SpaceButs *)slink; + + if (sbuts->pinid == old_id) { + sbuts->pinid = new_id; + if (new_id == NULL) { + sbuts->flag &= ~SB_PIN_CONTEXT; + } + } + + if (sbuts->path) { + ButsContextPath *path = sbuts->path; + int i; + + for (i = 0; i < path->len; i++) { + if (path->ptr[i].id.data == old_id) { + break; + } + } + + if (i == path->len) { + /* pass */ + } + else if (new_id == NULL) { + if (i == 0) { + MEM_SAFE_FREE(sbuts->path); + } + else { + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + else { + RNA_id_pointer_create(new_id, &path->ptr[i]); + /* There is no easy way to check/make path downwards valid, just nullify it. + * Next redraw will rebuild this anyway. */ + i++; + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + } + + if (sbuts->texuser) { + ButsContextTexture *ct = sbuts->texuser; + if ((ID *)ct->texture == old_id) { + ct->texture = (Tex *)new_id; + } + BLI_freelistN(&ct->users); + ct->user = NULL; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_buttons(void) { @@ -406,7 +461,8 @@ void ED_spacetype_buttons(void) st->keymap = buttons_keymap; st->listener = buttons_area_listener; st->context = buttons_context; - + st->id_remap = buttons_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype buttons region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 1ff656243d6..14d0f909d23 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -634,7 +634,7 @@ typedef struct PrefetchQueue { short render_size, render_flag; /* If true prefecthing goes forward in time, - * othwewise it goes backwards in time (starting from current frame). + * otherwise it goes backwards in time (starting from current frame). */ bool forward; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index e1d4e4fabc5..415839ab761 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -45,6 +45,7 @@ #include "BKE_context.h" #include "BKE_screen.h" +#include "BKE_library.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -1512,6 +1513,25 @@ static void clip_properties_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED /********************* registration ********************/ +static void clip_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceClip *sclip = (SpaceClip *)slink; + + if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) { + return; + } + + if ((ID *)sclip->clip == old_id) { + sclip->clip = (MovieClip *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)sclip->mask_info.mask == old_id) { + sclip->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_clip(void) { @@ -1531,6 +1551,7 @@ void ED_spacetype_clip(void) st->context = clip_context; st->dropboxes = clip_dropboxes; st->refresh = clip_refresh; + st->id_remap = clip_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype clip region"); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 71e38f72a7a..a55b18a2212 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -128,6 +128,7 @@ void file_panels_register(struct ARegionType *art); /* file_utils.c */ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, rcti *r_bounds); +bool file_is_dir(struct SpaceFile *sfile, const char *path); #endif /* __FILE_INTERN_H__ */ diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index d83a7d5ea62..c42ff120102 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -208,7 +208,7 @@ static FileSelect file_select_do(bContext *C, int selected_idx, bool do_diropen) BLI_add_slash(params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); retval = FILE_SELECT_DIR; } } @@ -826,7 +826,7 @@ static int bookmark_select_exec(bContext *C, wmOperator *op) RNA_property_string_get(op->ptr, prop, entry); BLI_strncpy(params->dir, entry, sizeof(params->dir)); BLI_cleanup_dir(G.main->name, params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); } @@ -1379,7 +1379,7 @@ int file_exec(bContext *C, wmOperator *exec_op) BLI_add_slash(sfile->params->dir); } - ED_file_change_dir(C, false); + ED_file_change_dir(C); } /* opening file - sends events now, so things get handled on windowqueue level */ else if (sfile->op) { @@ -1447,19 +1447,7 @@ int file_parent_exec(bContext *C, wmOperator *UNUSED(unused)) if (sfile->params) { if (BLI_parent_dir(sfile->params->dir)) { BLI_cleanup_dir(G.main->name, sfile->params->dir); - /* if not browsing in .blend file, we still want to check whether the path is a directory */ - if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, NULL)) { - ED_file_change_dir(C, false); - } - else { - ED_file_change_dir(C, true); - } - } - else { - ED_file_change_dir(C, true); - } + ED_file_change_dir(C); if (sfile->params->recursion_level > 1) { /* Disable 'dirtree' recursion when going up in tree. */ sfile->params->recursion_level = 0; @@ -1529,7 +1517,7 @@ int file_previous_exec(bContext *C, wmOperator *UNUSED(unused)) folderlist_popdir(sfile->folders_prev, sfile->params->dir); folderlist_pushdir(sfile->folders_next, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1561,7 +1549,7 @@ int file_next_exec(bContext *C, wmOperator *UNUSED(unused)) // update folders_prev so we can check for it in folderlist_clear_next() folderlist_pushdir(sfile->folders_prev, sfile->params->dir); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1809,7 +1797,7 @@ int file_directory_new_exec(bContext *C, wmOperator *op) if (RNA_boolean_get(op->ptr, "open")) { BLI_strncpy(sfile->params->dir, path, sizeof(sfile->params->dir)); - ED_file_change_dir(C, true); + ED_file_change_dir(C); } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1906,17 +1894,35 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN file_expand_directory(C); /* special case, user may have pasted a filepath into the directory */ - if (BLI_is_file(sfile->params->dir)) { - char path[sizeof(sfile->params->dir)]; - BLI_strncpy(path, sfile->params->dir, sizeof(path)); - BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, sizeof(sfile->params->dir), sizeof(sfile->params->file)); + if (!file_is_dir(sfile, sfile->params->dir)) { + char tdir[FILE_MAX_LIBEXTRA]; + char *group, *name; + + if (BLI_is_file(sfile->params->dir)) { + char path[sizeof(sfile->params->dir)]; + BLI_strncpy(path, sfile->params->dir, sizeof(path)); + BLI_split_dirfile(path, sfile->params->dir, sfile->params->file, + sizeof(sfile->params->dir), sizeof(sfile->params->file)); + } + else if (BLO_library_path_explode(sfile->params->dir, tdir, &group, &name)) { + if (group) { + BLI_path_append(tdir, sizeof(tdir), group); + } + BLI_strncpy(sfile->params->dir, tdir, sizeof(sfile->params->dir)); + if (name) { + BLI_strncpy(sfile->params->file, name, sizeof(sfile->params->file)); + } + else { + sfile->params->file[0] = '\0'; + } + } } BLI_cleanup_dir(G.main->name, sfile->params->dir); - if (BLI_exists(sfile->params->dir)) { + if (file_is_dir(sfile, sfile->params->dir)) { /* if directory exists, enter it immediately */ - ED_file_change_dir(C, true); + ED_file_change_dir(C); /* don't do for now because it selects entire text instead of * placing cursor at the end */ @@ -1931,20 +1937,26 @@ void file_directory_enter_handle(bContext *C, void *UNUSED(arg_unused), void *UN #endif else { const char *lastdir = folderlist_peeklastdir(sfile->folders_prev); + char tdir[FILE_MAX_LIBEXTRA]; - /* if not, ask to create it and enter if confirmed */ - wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); - PointerRNA ptr; - WM_operator_properties_create_ptr(&ptr, ot); - RNA_string_set(&ptr, "directory", sfile->params->dir); - RNA_boolean_set(&ptr, "open", true); - - if (lastdir) + /* If we are 'inside' a blend library, we cannot do anything... */ + if (lastdir && BLO_library_path_explode(lastdir, tdir, NULL, NULL)) { BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); - - - WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); - WM_operator_properties_free(&ptr); + } + else { + /* if not, ask to create it and enter if confirmed */ + wmOperatorType *ot = WM_operatortype_find("FILE_OT_directory_new", false); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_string_set(&ptr, "directory", sfile->params->dir); + RNA_boolean_set(&ptr, "open", true); + + if (lastdir) + BLI_strncpy(sfile->params->dir, lastdir, sizeof(sfile->params->dir)); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); + } } WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); @@ -1971,8 +1983,6 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg BLI_filename_make_safe(sfile->params->file); if (matches) { - /* int i, numfiles = filelist_numfiles(sfile->files); */ /* XXX UNUSED */ - sfile->params->file[0] = '\0'; /* replace the pattern (or filename that the user typed in, with the first selected file of the match */ BLI_strncpy(sfile->params->file, matched_file, sizeof(sfile->params->file)); @@ -1980,30 +1990,17 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg } if (matches == 1) { - BLI_join_dirfile(filepath, sizeof(sfile->params->dir), sfile->params->dir, sfile->params->file); /* if directory, open it and empty filename field */ - if (BLI_is_dir(filepath)) { + if (file_is_dir(sfile, filepath)) { BLI_cleanup_dir(G.main->name, filepath); BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); sfile->params->file[0] = '\0'; - ED_file_change_dir(C, true); + ED_file_change_dir(C); UI_textbutton_activate_but(C, but); WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_PARAMS, NULL); } - else if (sfile->params->type == FILE_LOADLIB) { - char tdir[FILE_MAX]; - BLI_add_slash(filepath); - if (BLO_library_path_explode(filepath, tdir, NULL, NULL)) { - BLI_cleanup_dir(G.main->name, filepath); - BLI_strncpy(sfile->params->dir, filepath, sizeof(sfile->params->dir)); - sfile->params->file[0] = '\0'; - ED_file_change_dir(C, false); - UI_textbutton_activate_but(C, but); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); - } - } } else if (matches > 1) { file_draw_check(C); diff --git a/source/blender/editors/space_file/file_utils.c b/source/blender/editors/space_file/file_utils.c index 3c007f25da3..f19e301064d 100644 --- a/source/blender/editors/space_file/file_utils.c +++ b/source/blender/editors/space_file/file_utils.c @@ -25,6 +25,9 @@ */ #include "BLI_rect.h" +#include "BLI_fileops.h" + +#include "BLO_readfile.h" #include "BKE_context.h" @@ -45,3 +48,17 @@ void file_tile_boundbox(const ARegion *ar, FileLayout *layout, const int file, r BLI_rcti_init(r_bounds, xmin, xmin + layout->tile_w + layout->tile_border_x, ymax - layout->tile_h - layout->tile_border_y, ymax); } + +/* Cannot directly use BLI_is_dir in libloading context... */ +bool file_is_dir(struct SpaceFile *sfile, const char *path) +{ + if (sfile->params->type == FILE_LOADLIB) { + char tdir[FILE_MAX_LIBEXTRA]; + char *name; + if (BLO_library_path_explode(sfile->params->dir, tdir, NULL, &name) && BLI_is_file(tdir)) { + /* .blend file itself and group are considered as directories, not final datablock names. */ + return name ? false : true; + } + } + return BLI_is_dir(path); +} diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index fc3341bfb92..5e9eb1f9207 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -624,7 +624,7 @@ static bool is_filtered_file(FileListInternEntry *file, const char *UNUSED(root) static bool is_filtered_lib(FileListInternEntry *file, const char *root, FileListFilter *filter) { bool is_filtered; - char path[FILE_MAX_LIBEXTRA], dir[FILE_MAXDIR], *group, *name; + char path[FILE_MAX_LIBEXTRA], dir[FILE_MAX_LIBEXTRA], *group, *name; BLI_join_dirfile(path, sizeof(path), root, file->relpath); @@ -697,7 +697,7 @@ void filelist_filter(FileList *filelist) if (filelist->max_recursion) { /* Never show lib ID 'categories' directories when we are in 'flat' mode, unless * root path is a blend file. */ - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!filelist_islibrary(filelist, dir, NULL)) { filelist->filter_data.flags |= FLF_HIDE_LIB_DIR; } @@ -947,7 +947,7 @@ static void filelist_checkdir_dir(struct FileList *UNUSED(filelist), char *r_dir static void filelist_checkdir_lib(struct FileList *UNUSED(filelist), char *r_dir) { - char dir[FILE_MAXDIR]; + char dir[FILE_MAX_LIBEXTRA]; if (!BLO_library_path_explode(r_dir, dir, NULL, NULL)) { /* if not a valid library, we need it to be a valid directory! */ BLI_make_exist(r_dir); @@ -2113,6 +2113,7 @@ unsigned int filelist_entry_select_index_get(FileList *filelist, const int index return 0; } +/* WARNING! dir must be FILE_MAX_LIBEXTRA long! */ bool filelist_islibrary(struct FileList *filelist, char *dir, char **group) { return BLO_library_path_explode(filelist->filelist.root, dir, group, NULL); @@ -2208,7 +2209,7 @@ static int filelist_readjob_list_lib(const char *root, ListBase *entries, const FileListInternEntry *entry; LinkNode *ln, *names; int i, nnames, idcode = 0, nbr_entries = 0; - char dir[FILE_MAX], *group; + char dir[FILE_MAX_LIBEXTRA], *group; bool ok; struct BlendHandle *libfiledata = NULL; diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index bf90a4ea170..ab33d452d3c 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -576,7 +576,7 @@ FileLayout *ED_fileselect_get_layout(struct SpaceFile *sfile, ARegion *ar) return sfile->layout; } -void ED_file_change_dir(bContext *C, const bool checkdir) +void ED_file_change_dir(bContext *C) { wmWindowManager *wm = CTX_wm_manager(C); SpaceFile *sfile = CTX_wm_space_file(C); @@ -590,7 +590,7 @@ void ED_file_change_dir(bContext *C, const bool checkdir) sfile->params->filter_search[0] = '\0'; sfile->params->active_file = -1; - if (checkdir && !BLI_is_dir(sfile->params->dir)) { + if (!file_is_dir(sfile, sfile->params->dir)) { BLI_strncpy(sfile->params->dir, filelist_dir(sfile->files), sizeof(sfile->params->dir)); /* could return but just refresh the current dir */ } @@ -618,7 +618,7 @@ int file_select_match(struct SpaceFile *sfile, const char *pattern, char *matche */ for (i = 0; i < n; i++) { file = filelist_file(sfile->files, i); - /* Do not check wether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */ + /* Do not check whether file is a file or dir here! Causes T44243 (we do accept dirs at this stage). */ if (fnmatch(pattern, file->relpath, 0) == 0) { filelist_entry_select_set(sfile->files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); if (!match) { diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 3ac90200aea..ae91a466495 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -826,7 +826,7 @@ static void graph_draw_driver_debug(bAnimContext *ac, ID *id, FCurve *fcu) //if ((driver->flag & DRIVER_FLAG_SHOWDEBUG) == 0) // return; - /* No curve to modify/visualise the result? + /* No curve to modify/visualize the result? * => We still want to show the 1-1 default... */ if ((fcu->totvert == 0) && BLI_listbase_is_empty(&fcu->modifiers)) { @@ -1130,18 +1130,18 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) * - offset of ACHANNEL_HEIGHT*2 is added to the height of the channels, as first is for * start of list offset, and the second is as a correction for the scrollers. */ - height = (float)((items * ACHANNEL_STEP) + (ACHANNEL_HEIGHT * 2)); + height = (float)((items * ACHANNEL_STEP(ac)) + (ACHANNEL_HEIGHT(ac) * 2)); UI_view2d_totRect_set(v2d, ar->winx, height); /* loop through channels, and set up drawing depending on their type */ { /* first pass: just the standard GL-drawing for backdrop + text */ size_t channel_index = 0; - y = (float)ACHANNEL_FIRST; + y = (float)ACHANNEL_FIRST(ac); for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -1152,7 +1152,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) } /* adjust y-position for next one */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); channel_index++; } } @@ -1160,15 +1160,15 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) uiBlock *block = UI_block_begin(C, ar, __func__, UI_EMBOSS); size_t channel_index = 0; - y = (float)ACHANNEL_FIRST; + y = (float)ACHANNEL_FIRST(ac); /* set blending again, as may not be set in previous step */ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF); - const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF); + const float yminc = (float)(y - ACHANNEL_HEIGHT_HALF(ac)); + const float ymaxc = (float)(y + ACHANNEL_HEIGHT_HALF(ac)); /* check if visible */ if (IN_RANGE(yminc, v2d->cur.ymin, v2d->cur.ymax) || @@ -1179,7 +1179,7 @@ void graph_draw_channel_names(bContext *C, bAnimContext *ac, ARegion *ar) } /* adjust y-position for next one */ - y -= ACHANNEL_STEP; + y -= ACHANNEL_STEP(ac); channel_index++; } diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index 6b860990c10..478dbd3d9c0 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -555,19 +555,20 @@ static void graphedit_keymap_keyframes(wmKeyConfig *keyconf, wmKeyMap *keymap) kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", false); - + kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "axis_range", false); RNA_boolean_set(kmi->ptr, "include_handles", true); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_border", BKEY, KM_PRESS, KM_CTRL | KM_ALT, 0); RNA_boolean_set(kmi->ptr, "axis_range", true); RNA_boolean_set(kmi->ptr, "include_handles", true); - + + /* region select */ kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL, 0); RNA_boolean_set(kmi->ptr, "deselect", false); kmi = WM_keymap_add_item(keymap, "GRAPH_OT_select_lasso", EVT_TWEAK_A, KM_ANY, KM_CTRL | KM_SHIFT, 0); RNA_boolean_set(kmi->ptr, "deselect", true); - + WM_keymap_add_item(keymap, "GRAPH_OT_select_circle", CKEY, KM_PRESS, 0, 0); /* column select */ diff --git a/source/blender/editors/space_graph/graph_select.c b/source/blender/editors/space_graph/graph_select.c index eb786d872ec..67b960bfa53 100644 --- a/source/blender/editors/space_graph/graph_select.c +++ b/source/blender/editors/space_graph/graph_select.c @@ -210,6 +210,8 @@ void GRAPH_OT_select_all_toggle(wmOperatorType *ot) * -> 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) * -> 3) y-axis, so select all frames within channels that region included (validation with BEZT_OK_VALUERANGE) + * + * The selection backend is also reused for the Lasso and Circle select operators. */ /* Borderselect only selects keyframes now, as overshooting handles often get caught too, @@ -245,12 +247,12 @@ static void borderselect_graphkeys( /* init editing data */ memset(&ked, 0, sizeof(KeyframeEditData)); if (mode == BEZT_OK_REGION_LASSO) { - struct KeyframeEdit_LassoData *data_lasso = data; + KeyframeEdit_LassoData *data_lasso = data; data_lasso->rectf_scaled = &scaled_rectf; ked.data = data_lasso; } else if (mode == BEZT_OK_REGION_CIRCLE) { - struct KeyframeEdit_CircleData *data_circle = data; + KeyframeEdit_CircleData *data_circle = data; data_circle->rectf_scaled = &scaled_rectf; ked.data = data; } @@ -265,27 +267,27 @@ static void borderselect_graphkeys( } else mapping_flag = ANIM_UNITCONV_ONLYKEYS; - + mapping_flag |= ANIM_get_normalization_flags(ac); - + /* loop over data, doing border select */ for (ale = anim_data.first; ale; ale = ale->next) { AnimData *adt = ANIM_nla_mapping_get(ac, ale); FCurve *fcu = (FCurve *)ale->key_data; float offset; float unit_scale = ANIM_unit_mapping_get_factor(ac->scene, ale->id, fcu, mapping_flag, &offset); - + /* apply NLA mapping to all the keyframes, since it's easier than trying to * guess when a callback might use something different */ if (adt) ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, 0, incl_handles == 0); - + scaled_rectf.xmin = rectf.xmin; scaled_rectf.xmax = rectf.xmax; scaled_rectf.ymin = rectf.ymin / unit_scale - offset; scaled_rectf.ymax = rectf.ymax / unit_scale - offset; - + /* set horizontal range (if applicable) * NOTE: these values are only used for x-range and y-range but not region * (which uses ked.data, i.e. rectf) @@ -406,37 +408,41 @@ void GRAPH_OT_select_border(wmOperatorType *ot) RNA_def_boolean(ot->srna, "include_handles", 0, "Include Handles", "Are handles tested individually against the selection criteria"); } + +/* ------------------- */ + static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) { bAnimContext ac; + + KeyframeEdit_LassoData data_lasso = {0}; rcti rect; rctf rect_fl; + short selectmode; bool incl_handles; bool extend; - - struct KeyframeEdit_LassoData data_lasso; - + /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data_lasso.rectf_view = &rect_fl; data_lasso.mcords = WM_gesture_lasso_path_to_array(C, op, &data_lasso.mcords_tot); if (data_lasso.mcords == NULL) return OPERATOR_CANCELLED; - + /* clear all selection if not extending selection */ extend = RNA_boolean_get(op->ptr, "extend"); if (!extend) deselect_graph_keys(&ac, 1, SELECT_SUBTRACT, true); - + if (!RNA_boolean_get(op->ptr, "deselect")) selectmode = SELECT_ADD; else selectmode = SELECT_SUBTRACT; - - if (ac.spacetype == SPACE_IPO) { + + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -446,60 +452,57 @@ static int graphkeys_lassoselect_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - - + /* get settings from operator */ BLI_lasso_boundbox(&rect, data_lasso.mcords, data_lasso.mcords_tot); - BLI_rctf_rcti_copy(&rect_fl, &rect); - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_LASSO, selectmode, incl_handles, &data_lasso); - + MEM_freeN((void *)data_lasso.mcords); - - + /* send notifier that keyframe selection has changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_SELECTED, NULL); - + return OPERATOR_FINISHED; } - void GRAPH_OT_select_lasso(wmOperatorType *ot) { /* identifiers */ ot->name = "Lasso Select"; ot->description = "Select keyframe points using lasso selection"; ot->idname = "GRAPH_OT_select_lasso"; - + /* api callbacks */ ot->invoke = WM_gesture_lasso_invoke; ot->modal = WM_gesture_lasso_modal; ot->exec = graphkeys_lassoselect_exec; ot->poll = graphop_visible_keyframes_poll; ot->cancel = WM_gesture_lasso_cancel; - + /* flags */ ot->flag = OPTYPE_UNDO; - + /* properties */ RNA_def_collection_runtime(ot->srna, "path", &RNA_OperatorMousePath, "Path", ""); RNA_def_boolean(ot->srna, "deselect", false, "Deselect", "Deselect rather than select items"); RNA_def_boolean(ot->srna, "extend", true, "Extend", "Extend selection instead of deselecting everything first"); } +/* ------------------- */ + static int graph_circle_select_exec(bContext *C, wmOperator *op) { bAnimContext ac; const int gesture_mode = RNA_int_get(op->ptr, "gesture_mode"); - short selectmode; - bool incl_handles; + const short selectmode = (gesture_mode == GESTURE_MODAL_SELECT) ? SELECT_ADD : SELECT_SUBTRACT; + bool incl_handles = false; + + KeyframeEdit_CircleData data = {0}; rctf rect_fl; - struct KeyframeEdit_CircleData data; + float x = RNA_int_get(op->ptr, "x"); float y = RNA_int_get(op->ptr, "y"); float radius = RNA_int_get(op->ptr, "radius"); @@ -507,23 +510,18 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) /* get editor data */ if (ANIM_animdata_get_context(C, &ac) == 0) return OPERATOR_CANCELLED; - + data.mval[0] = x; data.mval[1] = y; data.radius_squared = radius * radius; data.rectf_view = &rect_fl; - if (gesture_mode == GESTURE_MODAL_SELECT) - selectmode = SELECT_ADD; - else - selectmode = SELECT_SUBTRACT; - rect_fl.xmin = x - radius; rect_fl.xmax = x + radius; rect_fl.ymin = y - radius; rect_fl.ymax = y + radius; - if (ac.spacetype == SPACE_IPO) { + { SpaceIpo *sipo = (SpaceIpo *)ac.sl; if (selectmode == SELECT_ADD) { incl_handles = ((sipo->flag & SIPO_SELVHANDLESONLY) || @@ -533,10 +531,7 @@ static int graph_circle_select_exec(bContext *C, wmOperator *op) incl_handles = (sipo->flag & SIPO_NOHANDLES) == 0; } } - else { - incl_handles = false; - } - + /* apply borderselect action */ borderselect_graphkeys(&ac, &rect_fl, BEZT_OK_REGION_CIRCLE, selectmode, incl_handles, &data); diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index c6a8a9753d1..2582ba4be8d 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -524,12 +525,130 @@ static void graph_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } } - +/* Update F-Curve colors */ +static void graph_refresh_fcurve_colors(const bContext *C) +{ + bAnimContext ac; + + ListBase anim_data = {NULL, NULL}; + bAnimListElem *ale; + size_t items; + int filter; + int i; + + if (ANIM_animdata_get_context(C, &ac) == false) + return; + + UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW); + + /* build list of F-Curves which will be visible as channels in channel-region + * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a + * mismatch between channel-colors and the drawn curves + */ + filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS); + items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); + + /* loop over F-Curves, assigning colors */ + for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { + FCurve *fcu = (FCurve *)ale->data; + + /* set color of curve here */ + switch (fcu->color_mode) { + case FCURVE_COLOR_CUSTOM: + { + /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors), + * which should be left alone... Nothing needs to be done here. + */ + break; + } + case FCURVE_COLOR_AUTO_RGB: + { + /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors. + * TODO: find a way to module the hue so that not all curves have same color... + */ + float *col = fcu->color; + + switch (fcu->array_index) { + case 0: + UI_GetThemeColor3fv(TH_AXIS_X, col); + break; + case 1: + UI_GetThemeColor3fv(TH_AXIS_Y, col); + break; + case 2: + UI_GetThemeColor3fv(TH_AXIS_Z, col); + break; + default: + /* 'unknown' color - bluish so as to not conflict with handles */ + col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; + break; + } + break; + } + case FCURVE_COLOR_AUTO_YRGB: + { + /* Like FCURVE_COLOR_AUTO_RGB, except this is for quaternions... */ + float *col = fcu->color; + + switch (fcu->array_index) { + case 1: + UI_GetThemeColor3fv(TH_AXIS_X, col); + break; + case 2: + UI_GetThemeColor3fv(TH_AXIS_Y, col); + break; + case 3: + UI_GetThemeColor3fv(TH_AXIS_Z, col); + break; + + case 0: + { + /* Special Case: "W" channel should be yellowish, so blend X and Y channel colors... */ + float c1[3], c2[3]; + float h1[3], h2[3]; + float hresult[3]; + + /* - get colors (rgb) */ + UI_GetThemeColor3fv(TH_AXIS_X, c1); + UI_GetThemeColor3fv(TH_AXIS_Y, c2); + + /* - perform blending in HSV space (to keep brightness similar) */ + rgb_to_hsv_v(c1, h1); + rgb_to_hsv_v(c2, h2); + + interp_v3_v3v3(hresult, h1, h2, 0.5f); + + /* - convert back to RGB for display */ + hsv_to_rgb_v(hresult, col); + break; + } + + default: + /* 'unknown' color - bluish so as to not conflict with handles */ + col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; + break; + } + break; + } + case FCURVE_COLOR_AUTO_RAINBOW: + default: + { + /* determine color 'automatically' using 'magic function' which uses the given args + * of current item index + total items to determine some RGB color + */ + getcolor_fcurve_rainbow(i, items, fcu->color); + break; + } + } + } + + /* free temp list */ + ANIM_animdata_freelist(&anim_data); +} static void graph_refresh(const bContext *C, ScrArea *sa) { SpaceIpo *sipo = (SpaceIpo *)sa->spacedata.first; - bAnimContext ac; /* updates to data needed depends on Graph Editor mode... */ switch (sipo->mode) { @@ -557,73 +676,19 @@ static void graph_refresh(const bContext *C, ScrArea *sa) } /* init/adjust F-Curve colors */ - if (ANIM_animdata_get_context(C, &ac)) { - ListBase anim_data = {NULL, NULL}; - bAnimListElem *ale; - size_t items; - int filter; - int i; - - UI_SetTheme(SPACE_IPO, RGN_TYPE_WINDOW); - - /* build list of F-Curves which will be visible as channels in channel-region - * - we don't include ANIMFILTER_CURVEVISIBLE filter, as that will result in a - * mismatch between channel-colors and the drawn curves - */ - filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_NODUPLIS); - items = ANIM_animdata_filter(&ac, &anim_data, filter, ac.data, ac.datatype); - - /* loop over F-Curves, assigning colors */ - for (ale = anim_data.first, i = 0; ale; ale = ale->next, i++) { - FCurve *fcu = (FCurve *)ale->data; - - /* set color of curve here */ - switch (fcu->color_mode) { - case FCURVE_COLOR_CUSTOM: - { - /* User has defined a custom color for this curve already (we assume it's not going to cause clashes with text colors), - * which should be left alone... Nothing needs to be done here. - */ - break; - } - case FCURVE_COLOR_AUTO_RGB: - { - /* F-Curve's array index is automatically mapped to RGB values. This works best of 3-value vectors. - * TODO: find a way to module the hue so that not all curves have same color... - */ - float *col = fcu->color; - - switch (fcu->array_index) { - case 0: - UI_GetThemeColor3fv(TH_AXIS_X, col); - break; - case 1: - UI_GetThemeColor3fv(TH_AXIS_Y, col); - break; - case 2: - UI_GetThemeColor3fv(TH_AXIS_Z, col); - break; - default: - /* 'unknown' color - bluish so as to not conflict with handles */ - col[0] = 0.3f; col[1] = 0.8f; col[2] = 1.0f; - break; - } - break; - } - case FCURVE_COLOR_AUTO_RAINBOW: - default: - { - /* determine color 'automatically' using 'magic function' which uses the given args - * of current item index + total items to determine some RGB color - */ - getcolor_fcurve_rainbow(i, items, fcu->color); - break; - } - } - } - - /* free temp list */ - ANIM_animdata_freelist(&anim_data); + graph_refresh_fcurve_colors(C); +} + +static void graph_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceIpo *sgraph = (SpaceIpo *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)sgraph->ads->filter_grp == old_id) { + sgraph->ads->filter_grp = (Group *)new_id; } } @@ -644,7 +709,8 @@ void ED_spacetype_ipo(void) st->keymap = graphedit_keymap; st->listener = graph_listener; st->refresh = graph_refresh; - + st->id_remap = graph_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype graphedit region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_image/image_buttons.c b/source/blender/editors/space_image/image_buttons.c index a2db6827b0e..38a54ade367 100644 --- a/source/blender/editors/space_image/image_buttons.c +++ b/source/blender/editors/space_image/image_buttons.c @@ -345,6 +345,13 @@ struct ImageUI_Data { int rpass_index; }; +static struct ImageUI_Data *ui_imageuser_data_copy(const struct ImageUI_Data *rnd_pt_src) +{ + struct ImageUI_Data *rnd_pt_dst = MEM_mallocN(sizeof(*rnd_pt_src), __func__); + memcpy(rnd_pt_dst, rnd_pt_src, sizeof(*rnd_pt_src)); + return rnd_pt_dst; +} + static void ui_imageuser_layer_menu(bContext *UNUSED(C), uiLayout *layout, void *rnd_pt) { struct ImageUI_Data *rnd_data = rnd_pt; @@ -532,9 +539,10 @@ static void ui_imageuser_view_menu_multiview(bContext *UNUSED(C), uiLayout *layo } /* 5 layer button callbacks... */ -static void image_multi_cb(bContext *C, void *rr_v, void *iuser_v) +static void image_multi_cb(bContext *C, void *rnd_pt, void *rr_v) { - ImageUser *iuser = iuser_v; + struct ImageUI_Data *rnd_data = rnd_pt; + ImageUser *iuser = rnd_data->iuser; BKE_image_multilayer_index(rr_v, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -575,6 +583,8 @@ static bool ui_imageuser_layer_menu_step(bContext *C, int direction, void *rnd_p BLI_assert(0); } + BKE_image_release_renderresult(scene, image); + if (changed) { BKE_image_multilayer_index(rr, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -662,10 +672,11 @@ static bool ui_imageuser_pass_menu_step(bContext *C, int direction, void *rnd_pt } /* 5 view button callbacks... */ -static void image_multiview_cb(bContext *C, void *ima_v, void *iuser_v) +static void image_multiview_cb(bContext *C, void *rnd_pt, void *UNUSED(arg_v)) { - Image *ima = ima_v; - ImageUser *iuser = iuser_v; + struct ImageUI_Data *rnd_data = rnd_pt; + Image *ima = rnd_data->image; + ImageUser *iuser = rnd_data->iuser; BKE_image_multiview_index(ima, iuser); WM_event_add_notifier(C, NC_IMAGE | ND_DRAW, NULL); @@ -692,7 +703,7 @@ static void uiblock_layer_pass_buttons( uiLayout *layout, Image *image, RenderResult *rr, ImageUser *iuser, int w, short *render_slot) { - static struct ImageUI_Data rnd_pt; /* XXX, workaround */ + struct ImageUI_Data rnd_pt_local, *rnd_pt = NULL; uiBlock *block = uiLayoutGetBlock(layout); uiBut *but; RenderLayer *rl = NULL; @@ -708,10 +719,10 @@ static void uiblock_layer_pass_buttons( wmenu2 = (3 * w) / 5; wmenu3 = (3 * w) / 6; wmenu4 = (3 * w) / 6; - - rnd_pt.image = image; - rnd_pt.iuser = iuser; - rnd_pt.rpass_index = 0; + + rnd_pt_local.image = image; + rnd_pt_local.iuser = iuser; + rnd_pt_local.rpass_index = 0; /* menu buts */ if (render_slot) { @@ -723,10 +734,12 @@ static void uiblock_layer_pass_buttons( BLI_snprintf(str, sizeof(str), IFACE_("Slot %d"), *render_slot + 1); } + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); but = uiDefMenuBut(block, ui_imageuser_slot_menu, image, str, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select Slot")); UI_but_func_menu_step_set(but, ui_imageuser_slot_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } if (rr) { @@ -738,15 +751,18 @@ static void uiblock_layer_pass_buttons( fake_name = ui_imageuser_layer_fake_name(rr); rpass_index = iuser->layer - (fake_name ? 1 : 0); rl = BLI_findlink(&rr->layers, rpass_index); - rnd_pt.rpass_index = rpass_index; + rnd_pt_local.rpass_index = rpass_index; if (RE_layers_have_name(rr)) { display_name = rl ? rl->name : (fake_name ? fake_name : ""); - but = uiDefMenuBut(block, ui_imageuser_layer_menu, &rnd_pt, display_name, - 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer")); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_layer_menu, rnd_pt, display_name, + 0, 0, wmenu2, UI_UNIT_Y, TIP_("Select Layer")); UI_but_func_menu_step_set(but, ui_imageuser_layer_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } /* pass */ @@ -754,11 +770,14 @@ static void uiblock_layer_pass_buttons( rpass = (rl ? BLI_findlink(&rl->passes, iuser->pass - (fake_name ? 1 : 0)) : NULL); display_name = rpass ? rpass->internal_name : (fake_name ? fake_name : ""); - but = uiDefMenuBut(block, ui_imageuser_pass_menu, &rnd_pt, IFACE_(display_name), - 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_pass_menu, rnd_pt, IFACE_(display_name), + 0, 0, wmenu3, UI_UNIT_Y, TIP_("Select Pass")); UI_but_func_menu_step_set(but, ui_imageuser_pass_menu_step); - UI_but_func_set(but, image_multi_cb, rr, iuser); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; /* view */ if (BLI_listbase_count_ex(&rr->views, 2) > 1 && @@ -767,9 +786,13 @@ static void uiblock_layer_pass_buttons( rview = BLI_findlink(&rr->views, iuser->view); display_name = rview ? rview->name : ""; - but = uiDefMenuBut(block, ui_imageuser_view_menu_rr, &rnd_pt, display_name, 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View")); - UI_but_func_set(but, image_multi_cb, rr, iuser); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_view_menu_rr, rnd_pt, display_name, + 0, 0, wmenu4, UI_UNIT_Y, TIP_("Select View")); + UI_but_funcN_set(but, image_multi_cb, rnd_pt, rr); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } } @@ -787,9 +810,13 @@ static void uiblock_layer_pass_buttons( } } - but = uiDefMenuBut(block, ui_imageuser_view_menu_multiview, &rnd_pt, display_name, 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View")); - UI_but_func_set(but, image_multiview_cb, image, iuser); + rnd_pt = ui_imageuser_data_copy(&rnd_pt_local); + but = uiDefMenuBut( + block, ui_imageuser_view_menu_multiview, rnd_pt, display_name, + 0, 0, wmenu1, UI_UNIT_Y, TIP_("Select View")); + UI_but_funcN_set(but, image_multiview_cb, rnd_pt, NULL); UI_but_type_set_menu_from_pulldown(but); + rnd_pt = NULL; } } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 8db5a8f9bd3..1538842b139 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1061,6 +1061,12 @@ typedef struct ImageOpenData { ImageFormatData im_format; } ImageOpenData; +typedef struct ImageFrameRange { + struct ImageFrameRange *next, *prev; + ListBase frames; + char filepath[FILE_MAX]; +} ImageFrameRange; + typedef struct ImageFrame { struct ImageFrame *next, *prev; int framenr; @@ -1086,10 +1092,10 @@ static void image_open_cancel(bContext *UNUSED(C), wmOperator *op) * \param frames [out] the list of frame numbers found in the files matching the first one by name * \param path [out] the full path of the first file in the list of image files */ -static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *path, const size_t maxlen) +static void image_sequence_get_frame_ranges(PointerRNA *ptr, ListBase *frames_all) { char dir[FILE_MAXDIR]; - bool is_first_entry = true; + ImageFrameRange *frame_range = NULL; RNA_string_get(ptr, "directory", dir); RNA_BEGIN (ptr, itemptr, "files") @@ -1101,29 +1107,26 @@ static void image_sequence_get_frames(PointerRNA *ptr, ListBase *frames, char *p ImageFrame *frame = MEM_callocN(sizeof(ImageFrame), "image_frame"); /* use the first file in the list as base filename */ - if (is_first_entry) { - BLI_join_dirfile(path, maxlen, dir, filename); - frame->framenr = BLI_stringdec(filename, base_head, base_tail, &digits); - BLI_addtail(frames, frame); - is_first_entry = false; + frame->framenr = BLI_stringdec(filename, head, tail, &digits); + + /* still in the same sequence */ + if ((frame_range != NULL) && + (STREQLEN(base_head, head, FILE_MAX)) && + (STREQLEN(base_tail, tail, FILE_MAX))) + { + /* pass */ } else { - frame->framenr = BLI_stringdec(filename, head, tail, &digits); + /* start a new frame range */ + frame_range = MEM_callocN(sizeof(*frame_range), __func__); + BLI_join_dirfile(frame_range->filepath, sizeof(frame_range->filepath), dir, filename); + BLI_addtail(frames_all, frame_range); - /* still in the same sequence */ - if ((STREQLEN(base_head, head, FILE_MAX)) && - (STREQLEN(base_tail, tail, FILE_MAX))) - { - BLI_addtail(frames, frame); - } - else { - /* different file base name found, is ignored */ - MEM_freeN(filename); - MEM_freeN(frame); - break; - } + BLI_strncpy(base_head, head, sizeof(base_head)); + BLI_strncpy(base_tail, tail, sizeof(base_tail)); } + BLI_addtail(&frame_range->frames, frame); MEM_freeN(filename); } RNA_END @@ -1164,6 +1167,52 @@ static int image_sequence_get_len(ListBase *frames, int *ofs) return 0; } +static Image *image_open_single( + wmOperator *op, const char *filepath, const char *relbase, + bool is_relative_path, bool use_multiview, int frame_seq_len) +{ + bool exists = false; + Image *ima = NULL; + + errno = 0; + ima = BKE_image_load_exists_ex(filepath, &exists); + + if (!ima) { + if (op->customdata) MEM_freeN(op->customdata); + BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", + filepath, errno ? strerror(errno) : TIP_("unsupported image format")); + return NULL; + } + + if (!exists) { + /* only image path after save, never ibuf */ + if (is_relative_path) { + BLI_path_rel(ima->name, relbase); + } + + /* handle multiview images */ + if (use_multiview) { + ImageOpenData *iod = op->customdata; + ImageFormatData *imf = &iod->im_format; + + ima->flag |= IMA_USE_VIEWS; + ima->views_format = imf->views_format; + *ima->stereo3d_format = imf->stereo3d_format; + } + else { + ima->flag &= ~IMA_USE_VIEWS; + BKE_image_free_views(ima); + } + + if ((frame_seq_len > 1) && (ima->source == IMA_SRC_FILE)) { + ima->source = IMA_SRC_SEQUENCE; + } + } + + return ima; +} + + static int image_open_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -1174,70 +1223,60 @@ static int image_open_exec(bContext *C, wmOperator *op) ImageOpenData *iod = op->customdata; PointerRNA idptr; Image *ima = NULL; - char path[FILE_MAX]; + char filepath[FILE_MAX]; int frame_seq_len = 0; int frame_ofs = 1; - bool exists = false; const bool is_relative_path = RNA_boolean_get(op->ptr, "relative_path"); + const bool use_multiview = RNA_boolean_get(op->ptr, "use_multiview"); - RNA_string_get(op->ptr, "filepath", path); + if (!op->customdata) + image_open_init(C, op); + + RNA_string_get(op->ptr, "filepath", filepath); if (RNA_struct_property_is_set(op->ptr, "directory") && RNA_struct_property_is_set(op->ptr, "files")) { - /* only to pass to imbuf */ - char path_full[FILE_MAX]; - BLI_strncpy(path_full, path, sizeof(path_full)); - BLI_path_abs(path_full, G.main->name); + bool was_relative = BLI_path_is_rel(filepath); + ListBase frame_ranges_all; - if (!IMB_isanim(path_full)) { - bool was_relative = BLI_path_is_rel(path); - ListBase frames; + BLI_listbase_clear(&frame_ranges_all); + image_sequence_get_frame_ranges(op->ptr, &frame_ranges_all); + for (ImageFrameRange *frame_range = frame_ranges_all.first; frame_range; frame_range = frame_range->next) { + int frame_range_ofs; + int frame_range_seq_len = image_sequence_get_len(&frame_range->frames, &frame_range_ofs); + BLI_freelistN(&frame_range->frames); - BLI_listbase_clear(&frames); - image_sequence_get_frames(op->ptr, &frames, path, sizeof(path)); - frame_seq_len = image_sequence_get_len(&frames, &frame_ofs); - BLI_freelistN(&frames); + char filepath_range[FILE_MAX]; + BLI_strncpy(filepath_range, frame_range->filepath, sizeof(filepath_range)); if (was_relative) { - BLI_path_rel(path, G.main->name); + BLI_path_rel(filepath_range, bmain->name); } - } - } - - errno = 0; - ima = BKE_image_load_exists_ex(path, &exists); + Image *ima_range = image_open_single( + op, filepath_range, bmain->name, + is_relative_path, use_multiview, frame_range_seq_len); - if (!ima) { - if (op->customdata) MEM_freeN(op->customdata); - BKE_reportf(op->reports, RPT_ERROR, "Cannot read '%s': %s", - path, errno ? strerror(errno) : TIP_("unsupported image format")); - return OPERATOR_CANCELLED; - } - - if (!op->customdata) - image_open_init(C, op); - - /* handle multiview images */ - if (RNA_boolean_get(op->ptr, "use_multiview")) { - ImageFormatData *imf = &iod->im_format; - - ima->flag |= IMA_USE_VIEWS; - ima->views_format = imf->views_format; - *ima->stereo3d_format = imf->stereo3d_format; + /* take the first image */ + if ((ima == NULL) && ima_range) { + ima = ima_range; + frame_seq_len = frame_range_seq_len; + frame_ofs = frame_range_ofs; + } + } + BLI_freelistN(&frame_ranges_all); } else { - ima->flag &= ~IMA_USE_VIEWS; - BKE_image_free_views(ima); + /* for drag & drop etc. */ + ima = image_open_single( + op, filepath, bmain->name, + is_relative_path, use_multiview, 1); } - /* only image path after save, never ibuf */ - if (is_relative_path) { - if (!exists) { - BLI_path_rel(ima->name, bmain->name); - } + if (ima == NULL) { + return OPERATOR_CANCELLED; } /* hook into UI */ @@ -1245,11 +1284,8 @@ static int image_open_exec(bContext *C, wmOperator *op) if (iod->pprop.prop) { /* when creating new ID blocks, use is already 1, but RNA - * pointer se also increases user, so this compensates it */ + * pointer also increases user, so this compensates it */ id_us_min(&ima->id); - if ((frame_seq_len > 1) && ima->source == IMA_SRC_FILE) { - ima->source = IMA_SRC_SEQUENCE; - } RNA_id_pointer_create(&ima->id, &idptr); RNA_property_pointer_set(&iod->pprop.ptr, iod->pprop.prop, idptr); RNA_property_update(C, &iod->pprop.ptr, iod->pprop.prop); @@ -2979,7 +3015,7 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event if (ibuf->zbuf) { info->z = ibuf->zbuf[y * ibuf->x + x]; info->zp = &info->z; - if (ibuf->zbuf == (int*)ibuf->rect) { + if (ibuf->zbuf == (int *)ibuf->rect) { info->colp = NULL; } } diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index 168f9c0dfdf..35a658eac23 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -28,6 +28,7 @@ * \ingroup spimage */ +#include "DNA_gpencil_types.h" #include "DNA_mesh_types.h" #include "DNA_mask_types.h" #include "DNA_meshdata_types.h" @@ -44,6 +45,7 @@ #include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_image.h" +#include "BKE_library.h" #include "BKE_scene.h" #include "BKE_screen.h" @@ -981,6 +983,31 @@ static void image_header_region_listener(bScreen *UNUSED(sc), ScrArea *UNUSED(sa } } +static void image_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceImage *simg = (SpaceImage *)slink; + + if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) { + return; + } + + if ((ID *)simg->image == old_id) { + simg->image = (Image *)new_id; + id_us_ensure_real(new_id); + } + + if ((ID *)simg->gpd == old_id) { + simg->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + + if ((ID *)simg->mask_info.mask == old_id) { + simg->mask_info.mask = (Mask *)new_id; + id_us_ensure_real(new_id); + } +} + /**************************** spacetype *****************************/ /* only called once, from space/spacetypes.c */ @@ -1002,7 +1029,8 @@ void ED_spacetype_image(void) st->refresh = image_refresh; st->listener = image_listener; st->context = image_context; - + st->id_remap = image_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype image region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_logic/logic_ops.c b/source/blender/editors/space_logic/logic_ops.c index 51f4a61047d..074368a82c5 100644 --- a/source/blender/editors/space_logic/logic_ops.c +++ b/source/blender/editors/space_logic/logic_ops.c @@ -65,7 +65,7 @@ static int edit_sensor_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "sensor", &RNA_Sensor); - if (ptr.data && ((ID *)ptr.id.data)->lib) return 0; + if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0; return 1; } @@ -73,7 +73,7 @@ static int edit_controller_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "controller", &RNA_Controller); - if (ptr.data && ((ID *)ptr.id.data)->lib) return 0; + if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0; return 1; } @@ -81,7 +81,7 @@ static int edit_actuator_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "actuator", &RNA_Actuator); - if (ptr.data && ((ID *)ptr.id.data)->lib) return 0; + if (ptr.data && ID_IS_LINKED_DATABLOCK(ptr.id.data)) return 0; return 1; } diff --git a/source/blender/editors/space_logic/space_logic.c b/source/blender/editors/space_logic/space_logic.c index 243a522011b..69966e9bf34 100644 --- a/source/blender/editors/space_logic/space_logic.c +++ b/source/blender/editors/space_logic/space_logic.c @@ -38,7 +38,10 @@ #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "DNA_gpencil_types.h" + #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "ED_space_api.h" @@ -300,6 +303,21 @@ static void logic_header_region_draw(const bContext *C, ARegion *ar) /**************************** spacetype *****************************/ +static void logic_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceLogic *slog = (SpaceLogic *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)slog->gpd == old_id) { + slog->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_logic(void) { @@ -317,7 +335,8 @@ void ED_spacetype_logic(void) st->keymap = logic_keymap; st->refresh = logic_refresh; st->context = logic_context; - + st->id_remap = logic_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype logic region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index b0adabe4d1d..5b3c062e16d 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -62,7 +62,7 @@ #include "UI_resources.h" #include "UI_view2d.h" - +#include "nla_private.h" #include "nla_intern.h" /* own include */ @@ -145,6 +145,62 @@ static void nla_action_draw_keyframes(AnimData *adt, bAction *act, View2D *v2d, BLI_dlrbTree_free(&keys); } +/* Strip Markers ------------------------ */ + +/* Markers inside an action strip */ +static void nla_actionclip_draw_markers(NlaStrip *strip, float yminc, float ymaxc) +{ + bAction *act = strip->act; + TimeMarker *marker; + + if (ELEM(NULL, strip->act, strip->act->markers.first)) + return; + + for (marker = act->markers.first; marker; marker = marker->next) { + if ((marker->frame > strip->actstart) && (marker->frame < strip->actend)) { + float frame = nlastrip_get_frame(strip, marker->frame, NLATIME_CONVERT_MAP); + + /* just a simple line for now */ + // XXX: draw a triangle instead... + fdrawline(frame, yminc + 1, frame, ymaxc - 1); + } + } +} + +/* Markers inside a NLA-Strip */ +static void nla_strip_draw_markers(NlaStrip *strip, float yminc, float ymaxc) +{ + glLineWidth(2.0); + + if (strip->type == NLASTRIP_TYPE_CLIP) { + /* try not to be too conspicuous, while being visible enough when transforming */ + if (strip->flag & NLASTRIP_FLAG_SELECT) + UI_ThemeColorShade(TH_STRIP_SELECT, -60); + else + UI_ThemeColorShade(TH_STRIP_SELECT, -40); + + setlinestyle(3); + + /* just draw the markers in this clip */ + nla_actionclip_draw_markers(strip, yminc, ymaxc); + + setlinestyle(0); + } + else if (strip->flag & NLASTRIP_FLAG_TEMP_META) { + /* just a solid color, so that it is very easy to spot */ + UI_ThemeColorShade(TH_STRIP_SELECT, 20); + + /* draw the markers in the first level of strips only (if they are actions) */ + for (NlaStrip *nls = strip->strips.first; nls; nls = nls->next) { + if (nls->type == NLASTRIP_TYPE_CLIP) { + nla_actionclip_draw_markers(nls, yminc, ymaxc); + } + } + } + + glLineWidth(1.0); +} + /* Strips (Proper) ---------------------- */ /* get colors for drawing NLA-Strips */ @@ -361,6 +417,10 @@ static void nla_draw_strip(SpaceNla *snla, AnimData *adt, NlaTrack *nlt, NlaStri nla_draw_strip_curves(strip, yminc, ymaxc); + /* draw markings indicating locations of local markers (useful for lining up different actions) */ + if ((snla->flag & SNLA_NOLOCALMARKERS) == 0) + nla_strip_draw_markers(strip, yminc, ymaxc); + /* draw strip outline * - color used here is to indicate active vs non-active */ diff --git a/source/blender/editors/space_nla/nla_edit.c b/source/blender/editors/space_nla/nla_edit.c index a2159696394..3e7e8ccc3f4 100644 --- a/source/blender/editors/space_nla/nla_edit.c +++ b/source/blender/editors/space_nla/nla_edit.c @@ -1856,6 +1856,7 @@ void NLA_OT_action_sync_length(wmOperatorType *ot) static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); bAnimContext ac; ListBase anim_data = {NULL, NULL}; @@ -1887,7 +1888,7 @@ static int nlaedit_make_single_user_exec(bContext *C, wmOperator *UNUSED(op)) /* multi-user? */ if (ID_REAL_USERS(strip->act) > 1) { /* make a new copy of the action for us to use (it will have 1 user already) */ - bAction *new_action = BKE_action_copy(strip->act); + bAction *new_action = BKE_action_copy(bmain, strip->act); /* decrement user count of our existing action */ id_us_min(&strip->act->id); @@ -1945,6 +1946,7 @@ static short bezt_apply_nlamapping(KeyframeEditData *ked, BezTriple *bezt) static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); bAnimContext ac; ListBase anim_data = {NULL, NULL}; @@ -1974,7 +1976,7 @@ static int nlaedit_apply_scale_exec(bContext *C, wmOperator *UNUSED(op)) continue; if (strip->act->id.us > 1) { /* make a copy of the Action to work on */ - bAction *act = BKE_action_copy(strip->act); + bAction *act = BKE_action_copy(bmain, strip->act); /* set this as the new referenced action, decrementing the users of the old one */ id_us_min(&strip->act->id); diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index e2b36c5b5ae..3b5604087b9 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -33,6 +33,7 @@ #include <stdio.h> #include "DNA_anim_types.h" +#include "DNA_group_types.h" #include "DNA_scene_types.h" #include "MEM_guardedalloc.h" @@ -501,6 +502,19 @@ static void nla_listener(bScreen *UNUSED(sc), ScrArea *sa, wmNotifier *wmn) } } +static void nla_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNla *snla = (SpaceNla *)slink; + + if (!ELEM(GS(old_id->name), ID_GR)) { + return; + } + + if ((ID *)snla->ads->filter_grp == old_id) { + snla->ads->filter_grp = (Group *)new_id; + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_nla(void) { @@ -517,7 +531,8 @@ void ED_spacetype_nla(void) st->operatortypes = nla_operatortypes; st->listener = nla_listener; st->keymap = nla_keymap; - + st->id_remap = nla_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype nla region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c index 1c20a883c7a..e1d6eb688d4 100644 --- a/source/blender/editors/space_node/node_edit.c +++ b/source/blender/editors/space_node/node_edit.c @@ -734,34 +734,6 @@ void ED_node_set_active(Main *bmain, bNodeTree *ntree, bNode *node) } } -void ED_node_id_unref(SpaceNode *snode, const ID *id) -{ - if (GS(id->name) == ID_SCE) { - if (snode->id == id) { - /* nasty DNA logic for SpaceNode: - * ideally should be handled by editor code, but would be bad level call - */ - bNodeTreePath *path, *path_next; - for (path = snode->treepath.first; path; path = path_next) { - path_next = path->next; - MEM_freeN(path); - } - BLI_listbase_clear(&snode->treepath); - - snode->id = NULL; - snode->from = NULL; - snode->nodetree = NULL; - snode->edittree = NULL; - } - } - else if (GS(id->name) == ID_OB) { - if (snode->from == id) { - snode->flag &= ~SNODE_PIN; - snode->from = NULL; - } - } -} - void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree)) { /* XXX This does not work due to layout functions relying on node->block, diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c index 5c58e9b720c..cf6e2ac226e 100644 --- a/source/blender/editors/space_node/node_group.c +++ b/source/blender/editors/space_node/node_group.c @@ -255,7 +255,7 @@ static int node_group_ungroup(bNodeTree *ntree, bNode *gnode) bAction *waction; /* firstly, wgroup needs to temporary dummy action that can be destroyed, as it shares copies */ - waction = wgroup->adt->action = BKE_action_copy(wgroup->adt->action); + waction = wgroup->adt->action = BKE_action_copy(G.main, wgroup->adt->action); /* now perform the moving */ BKE_animdata_separate_by_basepath(&wgroup->id, &ntree->id, &anim_basepaths); diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index df484724fc5..4ef703c8994 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -28,6 +28,7 @@ * \ingroup spnode */ +#include "DNA_gpencil_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -821,6 +822,41 @@ static int node_context(const bContext *C, const char *member, bContextDataResul return 0; } +static void node_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceNode *snode = (SpaceNode *)slink; + + if (GS(old_id->name) == ID_SCE) { + if (snode->id == old_id) { + /* nasty DNA logic for SpaceNode: + * ideally should be handled by editor code, but would be bad level call + */ + BLI_freelistN(&snode->treepath); + + /* XXX Untested in case new_id != NULL... */ + snode->id = new_id; + snode->from = NULL; + snode->nodetree = NULL; + snode->edittree = NULL; + } + } + else if (GS(old_id->name) == ID_OB) { + if (snode->from == old_id) { + if (new_id == NULL) { + snode->flag &= ~SNODE_PIN; + } + snode->from = new_id; + } + } + else if (GS(old_id->name) == ID_GD) { + if ((ID *)snode->gpd == old_id) { + snode->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } +} + /* only called once, from space/spacetypes.c */ void ED_spacetype_node(void) { @@ -840,6 +876,7 @@ void ED_spacetype_node(void) st->refresh = node_area_refresh; st->context = node_context; st->dropboxes = node_dropboxes; + st->id_remap = node_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype node region"); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 554009da8be..ae34a118992 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -402,7 +402,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) if (group_restrict_flag(gr, flag)) { for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->id.lib) + if (ID_IS_LINKED_DATABLOCK(gob->ob)) continue; gob->ob->restrictflag &= ~flag; @@ -414,7 +414,7 @@ void restrictbutton_gr_restrict_flag(void *poin, void *poin2, int flag) } else { for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->id.lib) + if (ID_IS_LINKED_DATABLOCK(gob->ob)) continue; /* not in editmode */ @@ -502,6 +502,11 @@ static void namebutton_cb(bContext *C, void *tsep, char *oldname) BKE_reportf(CTX_wm_reports(C), RPT_ERROR, "Library path '%s' does not exist, correct this before saving", expanded); } + else if (lib->id.tag & LIB_TAG_MISSING) { + BKE_reportf(CTX_wm_reports(C), RPT_INFO, + "Library path '%s' is now valid, please reload the library", expanded); + lib->id.tag &= ~LIB_TAG_MISSING; + } } } else { @@ -650,7 +655,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar int but_flag = UI_BUT_DRAG_LOCK; gr = (Group *)tselem->id; - if (gr->id.lib) + if (ID_IS_LINKED_DATABLOCK(gr)) but_flag |= UI_BUT_DISABLED; UI_block_emboss_set(block, UI_EMBOSS_NONE); @@ -823,7 +828,7 @@ static void outliner_draw_userbuts(uiBlock *block, ARegion *ar, SpaceOops *soops char buf[16] = ""; int but_flag = UI_BUT_DRAG_LOCK; - if (id->lib) + if (ID_IS_LINKED_DATABLOCK(id)) but_flag |= UI_BUT_DISABLED; UI_block_emboss_set(block, UI_EMBOSS_NONE); @@ -988,7 +993,8 @@ static void tselem_draw_icon_uibut(struct DrawIconArg *arg, int icon) } else { uiBut *but = uiDefIconBut(arg->block, UI_BTYPE_LABEL, 0, icon, arg->xb, arg->yb, UI_UNIT_X, UI_UNIT_Y, NULL, - 0.0, 0.0, 1.0, arg->alpha, (arg->id && arg->id->lib) ? arg->id->lib->name : ""); + 0.0, 0.0, 1.0, arg->alpha, + (arg->id && ID_IS_LINKED_DATABLOCK(arg->id)) ? arg->id->lib->name : ""); if (arg->id) UI_but_drag_set_id(but, arg->id); @@ -1234,106 +1240,106 @@ static void tselem_draw_icon(uiBlock *block, int xmax, float x, float y, TreeSto UI_icon_draw(x, y, ICON_DOT); break; } } - else if (GS(tselem->id->name) == ID_OB) { - Object *ob = (Object *)tselem->id; - switch (ob->type) { - case OB_LAMP: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break; - case OB_MESH: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break; - case OB_CAMERA: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break; - case OB_CURVE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break; - case OB_MBALL: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break; - case OB_LATTICE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break; - case OB_ARMATURE: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break; - case OB_FONT: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break; - case OB_SURF: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break; - case OB_SPEAKER: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break; - case OB_EMPTY: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break; - + else if (tselem->id) { + if (GS(tselem->id->name) == ID_OB) { + Object *ob = (Object *)tselem->id; + switch (ob->type) { + case OB_LAMP: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LAMP); break; + case OB_MESH: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_MESH); break; + case OB_CAMERA: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CAMERA); break; + case OB_CURVE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_CURVE); break; + case OB_MBALL: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_META); break; + case OB_LATTICE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_LATTICE); break; + case OB_ARMATURE: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_ARMATURE); break; + case OB_FONT: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_FONT); break; + case OB_SURF: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SURFACE); break; + case OB_SPEAKER: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_SPEAKER); break; + case OB_EMPTY: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_OB_EMPTY); break; + } } - } - else { - switch (GS(tselem->id->name)) { - case ID_SCE: - tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; - case ID_ME: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break; - case ID_CU: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break; - case ID_MB: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break; - case ID_LT: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break; - case ID_LA: - { - Lamp *la = (Lamp *)tselem->id; - - switch (la->type) { - case LA_LOCAL: - tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break; - case LA_SUN: - tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break; - case LA_SPOT: - tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break; - case LA_HEMI: - tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break; - case LA_AREA: - tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break; - default: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break; + else { + switch (GS(tselem->id->name)) { + case ID_SCE: + tselem_draw_icon_uibut(&arg, ICON_SCENE_DATA); break; + case ID_ME: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_MESH); break; + case ID_CU: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CURVE); break; + case ID_MB: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_META); break; + case ID_LT: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LATTICE); break; + case ID_LA: + { + Lamp *la = (Lamp *)tselem->id; + switch (la->type) { + case LA_LOCAL: + tselem_draw_icon_uibut(&arg, ICON_LAMP_POINT); break; + case LA_SUN: + tselem_draw_icon_uibut(&arg, ICON_LAMP_SUN); break; + case LA_SPOT: + tselem_draw_icon_uibut(&arg, ICON_LAMP_SPOT); break; + case LA_HEMI: + tselem_draw_icon_uibut(&arg, ICON_LAMP_HEMI); break; + case LA_AREA: + tselem_draw_icon_uibut(&arg, ICON_LAMP_AREA); break; + default: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_LAMP); break; + } + break; } - break; + case ID_MA: + tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break; + case ID_TE: + tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break; + case ID_IM: + tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break; + case ID_SPK: + case ID_SO: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break; + case ID_AR: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break; + case ID_CA: + tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break; + case ID_KE: + tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break; + case ID_WO: + tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break; + case ID_AC: + tselem_draw_icon_uibut(&arg, ICON_ACTION); break; + case ID_NLA: + tselem_draw_icon_uibut(&arg, ICON_NLA); break; + case ID_TXT: + tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break; + case ID_GR: + tselem_draw_icon_uibut(&arg, ICON_GROUP); break; + case ID_LI: + if (tselem->id->tag & LIB_TAG_MISSING) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); + } + else if (((Library *)tselem->id)->parent) { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); + } + else { + tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); + } + break; + case ID_LS: + tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; + case ID_GD: + tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; } - case ID_MA: - tselem_draw_icon_uibut(&arg, ICON_MATERIAL_DATA); break; - case ID_TE: - tselem_draw_icon_uibut(&arg, ICON_TEXTURE_DATA); break; - case ID_IM: - tselem_draw_icon_uibut(&arg, ICON_IMAGE_DATA); break; - case ID_SPK: - case ID_SO: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_SPEAKER); break; - case ID_AR: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_ARMATURE); break; - case ID_CA: - tselem_draw_icon_uibut(&arg, ICON_OUTLINER_DATA_CAMERA); break; - case ID_KE: - tselem_draw_icon_uibut(&arg, ICON_SHAPEKEY_DATA); break; - case ID_WO: - tselem_draw_icon_uibut(&arg, ICON_WORLD_DATA); break; - case ID_AC: - tselem_draw_icon_uibut(&arg, ICON_ACTION); break; - case ID_NLA: - tselem_draw_icon_uibut(&arg, ICON_NLA); break; - case ID_TXT: - tselem_draw_icon_uibut(&arg, ICON_SCRIPT); break; - case ID_GR: - tselem_draw_icon_uibut(&arg, ICON_GROUP); break; - case ID_LI: - if (tselem->id->tag & LIB_TAG_MISSING) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_BROKEN); - } - else if (((Library *)tselem->id)->parent) { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_INDIRECT); - } - else { - tselem_draw_icon_uibut(&arg, ICON_LIBRARY_DATA_DIRECT); - } - break; - case ID_LS: - tselem_draw_icon_uibut(&arg, ICON_LINE_DATA); break; - case ID_GD: - tselem_draw_icon_uibut(&arg, ICON_GREASEPENCIL); break; } } } @@ -1562,7 +1568,7 @@ static void outliner_draw_tree_element( else offsx += 2 * ufac; - if (tselem->type == 0 && tselem->id->lib) { + if (tselem->type == 0 && ID_IS_LINKED_DATABLOCK(tselem->id)) { glPixelTransferf(GL_ALPHA_SCALE, 0.5f); if (tselem->id->tag & LIB_TAG_MISSING) { UI_icon_draw((float)startx + offsx, (float)*starty + 2 * ufac, ICON_LIBRARY_DATA_BROKEN); diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 2627b978b40..b0cd3aabbfd 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -29,17 +29,23 @@ * \ingroup spoutliner */ +#include <string.h> + #include "MEM_guardedalloc.h" #include "DNA_anim_types.h" #include "DNA_group_types.h" +#include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_object_types.h" #include "DNA_material_types.h" #include "BLI_blenlib.h" #include "BLI_utildefines.h" +#include "BLI_path_util.h" #include "BLI_mempool.h" +#include "BLI_stack.h" +#include "BLI_string.h" #include "BLT_translation.h" @@ -47,7 +53,10 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_global.h" +#include "BKE_idcode.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_outliner_treehash.h" #include "BKE_report.h" @@ -55,6 +64,8 @@ #include "BKE_material.h" #include "BKE_group.h" +#include "../blenloader/BLO_readfile.h" + #include "ED_object.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -70,6 +81,9 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "GPU_material.h" #include "outliner_intern.h" @@ -218,7 +232,7 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, else if (ELEM(tselem->type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } - else if (tselem->id->lib) { + else if (ID_IS_LINKED_DATABLOCK(tselem->id)) { BKE_report(reports, RPT_WARNING, "Cannot edit external libdata"); } else if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { @@ -230,8 +244,9 @@ static void do_item_rename(ARegion *ar, TreeElement *te, TreeStoreElem *tselem, } } -void item_rename_cb(bContext *C, Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void item_rename_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ARegion *ar = CTX_wm_region(C); ReportList *reports = CTX_wm_reports(C); // XXX @@ -291,64 +306,315 @@ void OUTLINER_OT_item_rename(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; } -/* Library delete --------------------------------------------------- */ +/* ID delete --------------------------------------------------- */ -static void lib_delete(bContext *C, TreeElement *te, TreeStoreElem *tselem, ReportList *reports) +static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeStoreElem *tselem) { - Library *lib = (Library *)tselem->id; - ListBase *lbarray[MAX_LIBARRAY]; - int a; + Main *bmain = CTX_data_main(C); + ID *id = tselem->id; - BLI_assert(te->idcode == ID_LI && lib != NULL); + BLI_assert(te->idcode != 0 && id != NULL); + BLI_assert(te->idcode != ID_LI || ((Library *)id)->parent == NULL); UNUSED_VARS_NDEBUG(te); - /* We simply set all ID from given lib (including lib itself) to zero user count. - * It is not possible to do a proper cleanup without a save/reload in current master. */ - a = set_listbasepointers(CTX_data_main(C), lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - ID *id; - - for (id = lb->first; id; id = id->next) { - if (id->lib == lib) { - id_fake_user_clear(id); - id->us = 0; + if (id->tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked id '%s'", id->name); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, id) && ID_REAL_USERS(id) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete id '%s', indirectly used datablocks need at least one user", + id->name); + return; + } + + + BKE_libblock_delete(bmain, id); + + WM_event_add_notifier(C, NC_WINDOW, NULL); +} + +void id_delete_cb( + bContext *C, ReportList *reports, Scene *UNUSED(scene), + TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + id_delete(C, reports, te, tselem); +} + +static int outliner_id_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +{ + if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (te->idcode != 0 && tselem->id) { + if (te->idcode == ID_LI && ((Library *)tselem->id)->parent) { + BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, + "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + return OPERATOR_CANCELLED; + } + id_delete(C, reports, te, tselem); + return OPERATOR_FINISHED; + } + } + else { + for (te = te->subtree.first; te; te = te->next) { + int ret; + if ((ret = outliner_id_delete_invoke_do(C, reports, te, mval))) { + return ret; + } + } + } + + return 0; +} + +static int outliner_id_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_id_delete_invoke_do(C, op->reports, te, fmval))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_id_delete(wmOperatorType *ot) +{ + ot->name = "Delete Datablock"; + ot->idname = "OUTLINER_OT_id_delete"; + ot->description = "Delete the ID under cursor"; + + ot->invoke = outliner_id_delete_invoke; + ot->poll = ED_operator_outliner_active; +} + +/* ID remap --------------------------------------------------- */ + +static int outliner_id_remap_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + + const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); + ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id")); + ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id")); + + /* check for invalid states */ + if (soops == NULL) { + return OPERATOR_CANCELLED; + } + + if (!(old_id && (old_id != new_id) && (GS(old_id->name) == GS(new_id->name)))) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, "Invalid old/new ID pair ('%s' / '%s')", + old_id->name, new_id->name); + return OPERATOR_CANCELLED; + } + + if (ID_IS_LINKED_DATABLOCK(old_id)) { + BKE_reportf(op->reports, RPT_WARNING, + "Old ID '%s' is linked from a library, indirect usages of this datablock will not be remapped", + old_id->name); + } + + BKE_libblock_remap(bmain, old_id, new_id, + ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + + BKE_main_lib_objects_recalc_all(bmain); + + /* recreate dependency graph to include new objects */ + DAG_scene_relations_rebuild(bmain, scene); + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; +} + +static bool outliner_id_remap_find_tree_element(bContext *C, wmOperator *op, ListBase *tree, const float y) +{ + TreeElement *te; + + for (te = tree->first; te; te = te->next) { + if (y > te->ys && y < te->ys + UI_UNIT_Y) { + TreeStoreElem *tselem = TREESTORE(te); + + if (tselem->type == 0 && tselem->id) { + printf("found id %s (%p)!\n", tselem->id->name, tselem->id); + + RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); + RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); + return true; } } + if (outliner_id_remap_find_tree_element(C, op, &te->subtree, y)) { + return true; + } + } + return false; +} + +static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + SpaceOops *soops = CTX_wm_space_outliner(C); + ARegion *ar = CTX_wm_region(C); + float fmval[2]; + + if (!RNA_property_is_set(op->ptr, RNA_struct_find_property(op->ptr, "id_type"))) { + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + outliner_id_remap_find_tree_element(C, op, &soops->tree, fmval[1]); } - BKE_reportf(reports, RPT_WARNING, - "Please save and reload .blend file to complete deletion of '%s' library", - ((Library *)tselem->id)->filepath); + return WM_operator_props_dialog_popup(C, op, 200, 100); +} + +static EnumPropertyItem *outliner_id_itemf(bContext *C, PointerRNA *ptr, PropertyRNA *UNUSED(prop), bool *r_free) +{ + EnumPropertyItem item_tmp = {0}, *item = NULL; + int totitem = 0; + int i = 0; + + short id_type = (short)RNA_enum_get(ptr, "id_type"); + ID *id = which_libbase(CTX_data_main(C), id_type)->first; + + for (; id; id = id->next) { + item_tmp.identifier = item_tmp.name = id->name + 2; + item_tmp.value = i++; + RNA_enum_item_add(&item, &totitem, &item_tmp); + } + + RNA_enum_item_end(&item, &totitem); + *r_free = true; + + return item; +} + +void OUTLINER_OT_id_remap(wmOperatorType *ot) +{ + PropertyRNA *prop; + + /* identifiers */ + ot->name = "Outliner ID data Remap"; + ot->idname = "OUTLINER_OT_id_remap"; + ot->description = ""; + + /* callbacks */ + ot->invoke = outliner_id_remap_invoke; + ot->exec = outliner_id_remap_exec; + ot->poll = ED_operator_outliner_active; + + ot->flag = 0; + + RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); + + prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); + RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN); + + ot->prop = RNA_def_enum(ot->srna, "new_id", DummyRNA_NULL_items, 0, + "New ID", "New ID to remap all selected IDs' users to"); + RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE); } -void lib_delete_cb( - bContext *C, Scene *UNUSED(scene), TreeElement *te, +void id_remap_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - lib_delete(C, te, tselem, CTX_wm_reports(C)); + wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false); + PointerRNA op_props; + + BLI_assert(tselem->id != NULL); + + WM_operator_properties_create_ptr(&op_props, ot); + + RNA_enum_set(&op_props, "id_type", GS(tselem->id->name)); + RNA_enum_set_identifier(C, &op_props, "old_id", tselem->id->name + 2); + + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + + WM_operator_properties_free(&op_props); +} + +/* Library relocate/reload --------------------------------------------------- */ + +static int lib_relocate( + bContext *C, TreeElement *te, TreeStoreElem *tselem, wmOperatorType *ot, const bool reload) +{ + PointerRNA op_props; + int ret = 0; + + BLI_assert(te->idcode == ID_LI && tselem->id != NULL); + UNUSED_VARS_NDEBUG(te); + + WM_operator_properties_create_ptr(&op_props, ot); + + RNA_string_set(&op_props, "library", tselem->id->name + 2); + + if (reload) { + Library *lib = (Library *)tselem->id; + char dir[FILE_MAXDIR], filename[FILE_MAX]; + + BLI_split_dirfile(lib->filepath, dir, filename, sizeof(dir), sizeof(filename)); + + printf("%s, %s\n", tselem->id->name, lib->filepath); + + /* We assume if both paths in lib are not the same then lib->name was relative... */ + RNA_boolean_set(&op_props, "relative_path", BLI_path_cmp(lib->filepath, lib->name) != 0); + + RNA_string_set(&op_props, "directory", dir); + RNA_string_set(&op_props, "filename", filename); + + ret = WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &op_props); + } + else { + ret = WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &op_props); + } + + WM_operator_properties_free(&op_props); + + return ret; } -static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeElement *te, const float mval[2]) +static int outliner_lib_relocate_invoke_do( + bContext *C, ReportList *reports, TreeElement *te, const float mval[2], const bool reload) { if (mval[1] > te->ys && mval[1] < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); if (te->idcode == ID_LI && tselem->id) { - if (((Library *)tselem->id)->parent) { + if (((Library *)tselem->id)->parent && !reload) { BKE_reportf(reports, RPT_ERROR_INVALID_INPUT, - "Cannot delete indirectly linked library '%s'", ((Library *)tselem->id)->filepath); + "Cannot relocate indirectly linked library '%s'", ((Library *)tselem->id)->filepath); return OPERATOR_CANCELLED; } + else { + wmOperatorType *ot = WM_operatortype_find(reload ? "WM_OT_lib_reload" : "WM_OT_lib_relocate", false); - lib_delete(C, te, tselem, reports); - return OPERATOR_FINISHED; + return lib_relocate(C, te, tselem, ot, reload); + } } } else { for (te = te->subtree.first; te; te = te->next) { int ret; - if ((ret = outliner_lib_delete_invoke_do(C, reports, te, mval))) { + if ((ret = outliner_lib_relocate_invoke_do(C, reports, te, mval, reload))) { return ret; } } @@ -357,7 +623,51 @@ static int outliner_lib_delete_invoke_do(bContext *C, ReportList *reports, TreeE return 0; } -static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent *event) +static int outliner_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + ARegion *ar = CTX_wm_region(C); + SpaceOops *soops = CTX_wm_space_outliner(C); + TreeElement *te; + float fmval[2]; + + BLI_assert(ar && soops); + + UI_view2d_region_to_view(&ar->v2d, event->mval[0], event->mval[1], &fmval[0], &fmval[1]); + + for (te = soops->tree.first; te; te = te->next) { + int ret; + + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, false))) { + return ret; + } + } + + return OPERATOR_CANCELLED; +} + +void OUTLINER_OT_lib_relocate(wmOperatorType *ot) +{ + ot->name = "Relocate Library"; + ot->idname = "OUTLINER_OT_lib_relocate"; + ot->description = "Relocate the library under cursor"; + + ot->invoke = outliner_lib_relocate_invoke; + ot->poll = ED_operator_outliner_active; +} + +/* XXX This does not work with several items + * (it is only called once in the end, due to the 'deferred' filebrowser invocation through event system...). */ +void lib_relocate_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_relocate", false); + + lib_relocate(C, te, tselem, ot, false); +} + + +static int outliner_lib_reload_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); @@ -371,7 +681,7 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent for (te = soops->tree.first; te; te = te->next) { int ret; - if ((ret = outliner_lib_delete_invoke_do(C, op->reports, te, fmval))) { + if ((ret = outliner_lib_relocate_invoke_do(C, op->reports, te, fmval, true))) { return ret; } } @@ -379,16 +689,25 @@ static int outliner_lib_delete_invoke(bContext *C, wmOperator *op, const wmEvent return OPERATOR_CANCELLED; } -void OUTLINER_OT_lib_delete(wmOperatorType *ot) +void OUTLINER_OT_lib_reload(wmOperatorType *ot) { - ot->name = "Delete Library"; - ot->idname = "OUTLINER_OT_lib_delete"; - ot->description = "Delete the library under cursor (needs a save/reload)"; + ot->name = "Reload Library"; + ot->idname = "OUTLINER_OT_lib_reload"; + ot->description = "Reload the library under cursor"; - ot->invoke = outliner_lib_delete_invoke; + ot->invoke = outliner_lib_reload_invoke; ot->poll = ED_operator_outliner_active; } +void lib_reload_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +{ + wmOperatorType *ot = WM_operatortype_find("WM_OT_lib_reload", false); + + lib_relocate(C, te, tselem, ot, true); +} + /* ************************************************************** */ /* Setting Toggling Operators */ @@ -468,8 +787,9 @@ int common_restrict_check(bContext *C, Object *ob) /* Toggle Visibility ---------------------------------------- */ -void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_visibility_cb( + bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; Object *ob = (Object *)tselem->id; @@ -484,21 +804,22 @@ void object_toggle_visibility_cb(bContext *C, Scene *scene, TreeElement *te, } } -void group_toggle_visibility_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_visibility_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_VIEW); } -static int outliner_toggle_visibility_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_visibility_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); DAG_id_type_tag(bmain, ID_OB); WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); @@ -523,8 +844,9 @@ void OUTLINER_OT_visibility_toggle(wmOperatorType *ot) /* Toggle Selectability ---------------------------------------- */ -void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_selectability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -534,20 +856,21 @@ void object_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme } } -void group_toggle_selectability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_selectability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_SELECT); } -static int outliner_toggle_selectability_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_selectability_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); ED_region_tag_redraw(ar); @@ -571,8 +894,9 @@ void OUTLINER_OT_selectability_toggle(wmOperatorType *ot) /* Toggle Renderability ---------------------------------------- */ -void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void object_toggle_renderability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -582,20 +906,21 @@ void object_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeEleme } } -void group_toggle_renderability_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +void group_toggle_renderability_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; restrictbutton_gr_restrict_flag(scene, group, OB_RESTRICT_RENDER); } -static int outliner_toggle_renderability_exec(bContext *C, wmOperator *UNUSED(op)) +static int outliner_toggle_renderability_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); SpaceOops *soops = CTX_wm_space_outliner(C); Scene *scene = CTX_data_scene(C); - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); DAG_id_type_tag(bmain, ID_OB); WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); @@ -1657,7 +1982,7 @@ static int parent_drop_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "child", childname); ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); return OPERATOR_CANCELLED; } @@ -1705,7 +2030,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (ob == par) { return OPERATOR_CANCELLED; } - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { BKE_report(op->reports, RPT_INFO, "Can't edit library linked object"); return OPERATOR_CANCELLED; } @@ -1914,7 +2239,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_string_get(op->ptr, "object", obname); ob = (Object *)BKE_libblock_find_name(ID_OB, obname); - if (ELEM(NULL, ob, scene) || scene->id.lib != NULL) { + if (ELEM(NULL, ob, scene) || ID_IS_LINKED_DATABLOCK(scene)) { return OPERATOR_CANCELLED; } @@ -2079,36 +2404,3 @@ void OUTLINER_OT_group_link(wmOperatorType *ot) /* properties */ RNA_def_string(ot->srna, "object", "Object", MAX_ID_NAME, "Object", "Target Object"); } - -/******** Utils to clear any ref to freed ID... **********/ - -void ED_outliner_id_unref(SpaceOops *so, const ID *id) -{ - /* Some early out checks. */ - if (!TREESTORE_ID_TYPE(id)) { - return; /* ID type is not used by outilner... */ - } - - if (so->search_tse.id == id) { - so->search_tse.id = NULL; - } - - if (so->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - bool changed = false; - - BLI_mempool_iternew(so->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == id) { - tselem->id = NULL; - changed = true; - } - } - if (so->treehash && changed) { - /* rebuild hash table, because it depends on ids too */ - /* postpone a full rebuild because this can be called many times on-free */ - so->storeflag |= SO_TREESTORE_REBUILD; - } - } -} diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index dc81be7a8e0..d2666cd0b6d 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -153,35 +153,58 @@ eOLDrawState tree_element_active(struct bContext *C, struct Scene *scene, SpaceO int outliner_item_do_activate(struct bContext *C, int x, int y, bool extend, bool recursive); /* outliner_edit.c ---------------------------------------------- */ +typedef void (*outliner_operation_cb)( + struct bContext *C, struct ReportList *, struct Scene *scene, + struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *); void outliner_do_object_operation_ex( - struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, - void (*operation_cb)(struct bContext *C, struct Scene *scene, - struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *), - bool recurse_selected); + struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + outliner_operation_cb operation_cb, bool recurse_selected); void outliner_do_object_operation( - struct bContext *C, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, - void (*operation_cb)(struct bContext *C, struct Scene *scene, - struct TreeElement *, struct TreeStoreElem *, TreeStoreElem *, void *)); + struct bContext *C, ReportList *reports, struct Scene *scene, struct SpaceOops *soops, struct ListBase *lb, + outliner_operation_cb operation_cb); int common_restrict_check(struct bContext *C, struct Object *ob); int outliner_has_one_flag(struct SpaceOops *soops, ListBase *lb, short flag, const int curlevel); void outliner_set_flag(struct SpaceOops *soops, ListBase *lb, short flag, short set); -void object_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void object_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void object_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - - -void group_toggle_visibility_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_selectability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void group_toggle_renderability_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); - -void item_rename_cb(struct bContext *C, struct Scene *scene, TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_visibility_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_selectability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void object_toggle_renderability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); + + +void group_toggle_visibility_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void group_toggle_selectability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void group_toggle_renderability_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); + +void item_rename_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, + TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void lib_relocate_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void lib_reload_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); -void lib_delete_cb( - struct bContext *C, struct Scene *scene, struct TreeElement *te, +void id_delete_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, + struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); +void id_remap_cb( + struct bContext *C, struct ReportList *reports, struct Scene *scene, struct TreeElement *te, struct TreeStoreElem *tsep, struct TreeStoreElem *tselem, void *user_data); TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float fmval[2], const bool children); @@ -190,8 +213,10 @@ TreeElement *outliner_dropzone_find(const struct SpaceOops *soops, const float f void OUTLINER_OT_item_activate(struct wmOperatorType *ot); void OUTLINER_OT_item_openclose(struct wmOperatorType *ot); void OUTLINER_OT_item_rename(struct wmOperatorType *ot); +void OUTLINER_OT_lib_relocate(struct wmOperatorType *ot); +void OUTLINER_OT_lib_reload(struct wmOperatorType *ot); -void OUTLINER_OT_lib_delete(struct wmOperatorType *ot); +void OUTLINER_OT_id_delete(struct wmOperatorType *ot); void OUTLINER_OT_show_one_level(struct wmOperatorType *ot); void OUTLINER_OT_show_active(struct wmOperatorType *ot); @@ -230,6 +255,7 @@ void OUTLINER_OT_object_operation(struct wmOperatorType *ot); void OUTLINER_OT_group_operation(struct wmOperatorType *ot); void OUTLINER_OT_lib_operation(struct wmOperatorType *ot); void OUTLINER_OT_id_operation(struct wmOperatorType *ot); +void OUTLINER_OT_id_remap(struct wmOperatorType *ot); void OUTLINER_OT_data_operation(struct wmOperatorType *ot); void OUTLINER_OT_animdata_operation(struct wmOperatorType *ot); void OUTLINER_OT_action_set(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index 720cfe12567..776717c8443 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -47,13 +47,15 @@ void outliner_operatortypes(void) WM_operatortype_append(OUTLINER_OT_select_border); WM_operatortype_append(OUTLINER_OT_item_openclose); WM_operatortype_append(OUTLINER_OT_item_rename); - WM_operatortype_append(OUTLINER_OT_lib_delete); WM_operatortype_append(OUTLINER_OT_operation); WM_operatortype_append(OUTLINER_OT_scene_operation); WM_operatortype_append(OUTLINER_OT_object_operation); WM_operatortype_append(OUTLINER_OT_group_operation); WM_operatortype_append(OUTLINER_OT_lib_operation); + WM_operatortype_append(OUTLINER_OT_lib_relocate); WM_operatortype_append(OUTLINER_OT_id_operation); + WM_operatortype_append(OUTLINER_OT_id_delete); + WM_operatortype_append(OUTLINER_OT_id_remap); WM_operatortype_append(OUTLINER_OT_data_operation); WM_operatortype_append(OUTLINER_OT_animdata_operation); WM_operatortype_append(OUTLINER_OT_action_set); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 83677b6bd86..111e60e5159 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -57,6 +57,8 @@ #include "BKE_fcurve.h" #include "BKE_group.h" #include "BKE_library.h" +#include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_report.h" #include "BKE_scene.h" @@ -133,15 +135,17 @@ static void set_operation_types(SpaceOops *soops, ListBase *lb, } } -static void unlink_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_action_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* just set action to NULL */ BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); } -static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_material_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { Material **matar = NULL; int a, totcol = 0; @@ -180,8 +184,9 @@ static void unlink_material_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEl } } -static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *te, - TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void unlink_texture_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *te, + TreeStoreElem *tsep, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { MTex **mtex = NULL; int a; @@ -217,7 +222,7 @@ static void unlink_texture_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEle } static void unlink_group_cb( - bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; @@ -230,12 +235,14 @@ static void unlink_group_cb( } else { Main *bmain = CTX_data_main(C); - BKE_group_unlink(bmain, group); + BKE_libblock_unlink(bmain, group, false, false); + BKE_libblock_free(bmain, group); } } -static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void unlink_world_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { Scene *parscene = (Scene *)tsep->id; World *wo = (World *)tselem->id; @@ -246,8 +253,8 @@ static void unlink_world_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeEleme } static void outliner_do_libdata_operation( - bContext *C, Scene *scene, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *), + bContext *C, ReportList *reports, Scene *scene, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb, void *user_data) { TreeElement *te; @@ -258,11 +265,11 @@ static void outliner_do_libdata_operation( if (tselem->flag & TSE_SELECTED) { if (tselem->type == 0) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; - operation_cb(C, scene, te, tsep, tselem, user_data); + operation_cb(C, reports, scene, te, tsep, tselem, user_data); } } if (TSELEM_OPEN(tselem, soops)) { - outliner_do_libdata_operation(C, scene, soops, &te->subtree, operation_cb, user_data); + outliner_do_libdata_operation(C, reports, scene, soops, &te->subtree, operation_cb, user_data); } } } @@ -352,8 +359,9 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) } /* ******************************************** */ -static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_select_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -364,8 +372,9 @@ static void object_select_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, } } -static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) +static void object_select_hierarchy_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { /* From where do i get the x,y coordinate of the mouse event ? */ wmWindow *win = CTX_wm_window(C); @@ -375,8 +384,9 @@ static void object_select_hierarchy_cb(bContext *C, Scene *UNUSED(scene), TreeEl } -static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_deselect_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; @@ -387,14 +397,27 @@ static void object_deselect_cb(bContext *UNUSED(C), Scene *scene, TreeElement *t } } -static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void object_delete_cb( + bContext *C, ReportList *reports, Scene *scene, TreeElement *te, + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; if (base == NULL) base = BKE_scene_base_find(scene, (Object *)tselem->id); if (base) { + Main *bmain = CTX_data_main(C); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + return; + } + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + return; + } + // check also library later if (scene->obedit == base->object) ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); @@ -408,45 +431,50 @@ static void object_delete_cb(bContext *C, Scene *scene, TreeElement *te, } } -static void id_local_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_local_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { - if (tselem->id->lib && (tselem->id->tag & LIB_TAG_EXTERN)) { + if (ID_IS_LINKED_DATABLOCK(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) { + Main *bmain = CTX_data_main(C); /* if the ID type has no special local function, * just clear the lib */ - if (id_make_local(tselem->id, false) == false) { - Main *bmain = CTX_data_main(C); + if (id_make_local(bmain, tselem->id, false, false) == false) { id_clear_lib_data(bmain, tselem->id); } } } -static void id_fake_user_set_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_set_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; id_fake_user_set(id); } -static void id_fake_user_clear_cb(bContext *UNUSED(C), Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_fake_user_clear_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; id_fake_user_clear(id); } -static void id_select_linked_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void id_select_linked_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; ED_object_select_linked_by_id(C, id); } -static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_action_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; @@ -462,8 +490,9 @@ static void singleuser_action_cb(bContext *C, Scene *UNUSED(scene), TreeElement } } -static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement *UNUSED(te), - TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) +static void singleuser_world_cb( + bContext *C, ReportList *UNUSED(reports), Scene *UNUSED(scene), TreeElement *UNUSED(te), + TreeStoreElem *tsep, TreeStoreElem *tselem, void *UNUSED(user_data)) { ID *id = tselem->id; @@ -480,34 +509,29 @@ static void singleuser_world_cb(bContext *C, Scene *UNUSED(scene), TreeElement * } } -static void group_linkobs2scene_cb(bContext *UNUSED(C), Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void group_linkobs2scene_cb( + bContext *UNUSED(C), ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; GroupObject *gob; Base *base; - + for (gob = group->gobject.first; gob; gob = gob->next) { base = BKE_scene_base_find(scene, gob->ob); - if (base) { - base->object->flag |= SELECT; - base->flag |= SELECT; - } - else { + if (!base) { /* link to scene */ - base = MEM_callocN(sizeof(Base), "add_base"); - BLI_addhead(&scene->base, base); - base->lay = gob->ob->lay; - gob->ob->flag |= SELECT; - base->flag = gob->ob->flag; - base->object = gob->ob; + base = BKE_scene_base_add(scene, gob->ob); id_lib_extern((ID *)gob->ob); /* in case these are from a linked group */ } + base->object->flag |= SELECT; + base->flag |= SELECT; } } -static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te), - TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) +static void group_instance_cb( + bContext *C, ReportList *UNUSED(reports), Scene *scene, TreeElement *UNUSED(te), + TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Group *group = (Group *)tselem->id; @@ -521,10 +545,8 @@ static void group_instance_cb(bContext *C, Scene *scene, TreeElement *UNUSED(te) * \param select_recurse: Set to false for operations which are already recursively operating on their children. */ void outliner_do_object_operation_ex( - bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *C, Scene *scene, TreeElement *, - TreeStoreElem *, TreeStoreElem *, void *), - bool select_recurse) + bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb, bool select_recurse) { TreeElement *te; @@ -541,23 +563,24 @@ void outliner_do_object_operation_ex( /* important to use 'scene_owner' not scene_act else deleting objects can crash. * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the * outliner isn't showing scenes: Visible Layer draw mode for eg. */ - operation_cb(C, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL); + operation_cb(C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, NULL); select_handled = true; } } if (TSELEM_OPEN(tselem, soops)) { if ((select_handled == false) || select_recurse) { - outliner_do_object_operation_ex(C, scene_act, soops, &te->subtree, operation_cb, select_recurse); + outliner_do_object_operation_ex( + C, reports, scene_act, soops, &te->subtree, operation_cb, select_recurse); } } } } void outliner_do_object_operation( - bContext *C, Scene *scene_act, SpaceOops *soops, ListBase *lb, - void (*operation_cb)(bContext *, Scene *, TreeElement *, TreeStoreElem *, TreeStoreElem *, void *)) + bContext *C, ReportList *reports, Scene *scene_act, SpaceOops *soops, ListBase *lb, + outliner_operation_cb operation_cb) { - outliner_do_object_operation_ex(C, scene_act, soops, lb, operation_cb, true); + outliner_do_object_operation_ex(C, reports, scene_act, soops, lb, operation_cb, true); } /* ******************************************** */ @@ -565,7 +588,7 @@ void outliner_do_object_operation( static void clear_animdata_cb(int UNUSED(event), TreeElement *UNUSED(te), TreeStoreElem *tselem, void *UNUSED(arg)) { - BKE_animdata_free(tselem->id); + BKE_animdata_free(tselem->id, true); } @@ -792,7 +815,7 @@ static void outliner_do_data_operation(SpaceOops *soops, int type, int event, Li } } -static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base) +static Base *outline_delete_hierarchy(bContext *C, ReportList *reports, Scene *scene, Base *base) { Base *child_base, *base_next; Object *parent; @@ -805,17 +828,30 @@ static Base *outline_delete_hierarchy(bContext *C, Scene *scene, Base *base) base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != base->object); parent = parent->parent); if (parent) { - base_next = outline_delete_hierarchy(C, scene, child_base); + base_next = outline_delete_hierarchy(C, reports, scene, child_base); } } base_next = base->next; + + Main *bmain = CTX_data_main(C); + if (base->object->id.tag & LIB_TAG_INDIRECT) { + BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked object '%s'", base->object->id.name + 2); + return base_next; + } + else if (BKE_library_ID_is_indirectly_used(bmain, base->object) && ID_REAL_USERS(base->object) <= 1) { + BKE_reportf(reports, RPT_WARNING, + "Cannot delete object '%s' from scene '%s', indirectly used objects need at least one user", + base->object->id.name + 2, scene->id.name + 2); + return base_next; + } ED_base_object_free_and_unlink(CTX_data_main(C), scene, base); return base_next; } static void object_delete_hierarchy_cb( - bContext *C, Scene *scene, TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) + bContext *C, ReportList *reports, Scene *scene, + TreeElement *te, TreeStoreElem *UNUSED(tsep), TreeStoreElem *tselem, void *UNUSED(user_data)) { Base *base = (Base *)te->directdata; Object *obedit = scene->obedit; @@ -830,7 +866,7 @@ static void object_delete_hierarchy_cb( ED_object_editmode_exit(C, EM_FREEDATA | EM_FREEUNDO | EM_WAITCURSOR | EM_DO_UNDO); } - outline_delete_hierarchy(C, scene, base); + outline_delete_hierarchy(C, reports, scene, base); /* leave for ED_outliner_id_unref to handle */ #if 0 te->directdata = NULL; @@ -849,6 +885,7 @@ enum { OL_OP_SELECT_HIERARCHY, OL_OP_DELETE, OL_OP_DELETE_HIERARCHY, + OL_OP_REMAP, OL_OP_LOCALIZED, /* disabled, see below */ OL_OP_TOGVIS, OL_OP_TOGSEL, @@ -862,6 +899,8 @@ static EnumPropertyItem prop_object_op_types[] = { {OL_OP_SELECT_HIERARCHY, "SELECT_HIERARCHY", 0, "Select Hierarchy", ""}, {OL_OP_DELETE, "DELETE", 0, "Delete", ""}, {OL_OP_DELETE_HIERARCHY, "DELETE_HIERARCHY", 0, "Delete Hierarchy", ""}, + {OL_OP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead a new chosen one"}, {OL_OP_TOGVIS, "TOGVIS", 0, "Toggle Visible", ""}, {OL_OP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, {OL_OP_TOGREN, "TOGREN", 0, "Toggle Renderable", ""}, @@ -885,7 +924,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) if (event == OL_OP_SELECT) { Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation(C, scene, soops, &soops->tree, object_select_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_select_cb); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } @@ -895,7 +934,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) } else if (event == OL_OP_SELECT_HIERARCHY) { Scene *sce = scene; // to be able to delete, scenes are set... - outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_select_hierarchy_cb, false); + outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_select_hierarchy_cb, false); if (scene != sce) { ED_screen_set_scene(C, CTX_wm_screen(C), sce); } @@ -903,12 +942,12 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DESELECT) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_deselect_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_deselect_cb); str = "Deselect Objects"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_DELETE) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_delete_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_delete_cb); /* XXX: tree management normally happens from draw_outliner(), but when * you're clicking to fast on Delete object from context menu in @@ -922,7 +961,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } else if (event == OL_OP_DELETE_HIERARCHY) { - outliner_do_object_operation_ex(C, scene, soops, &soops->tree, object_delete_hierarchy_cb, false); + outliner_do_object_operation_ex(C, op->reports, scene, soops, &soops->tree, object_delete_hierarchy_cb, false); /* XXX: See OL_OP_DELETE comment above. */ outliner_cleanup_tree(soops); @@ -931,27 +970,31 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) str = "Delete Object Hierarchy"; WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, scene); } + else if (event == OL_OP_REMAP) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + str = "Remap ID"; + } else if (event == OL_OP_LOCALIZED) { /* disabled, see above enum (ton) */ - outliner_do_object_operation(C, scene, soops, &soops->tree, id_local_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb); str = "Localized Objects"; } else if (event == OL_OP_TOGVIS) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_visibility_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_visibility_cb); str = "Toggle Visibility"; WM_event_add_notifier(C, NC_SCENE | ND_OB_VISIBLE, scene); } else if (event == OL_OP_TOGSEL) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_selectability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_selectability_cb); str = "Toggle Selectability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); } else if (event == OL_OP_TOGREN) { - outliner_do_object_operation(C, scene, soops, &soops->tree, object_toggle_renderability_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, object_toggle_renderability_cb); str = "Toggle Renderability"; WM_event_add_notifier(C, NC_SCENE | ND_OB_RENDER, scene); } else if (event == OL_OP_RENAME) { - outliner_do_object_operation(C, scene, soops, &soops->tree, item_rename_cb); + outliner_do_object_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb); str = "Rename Object"; } else { @@ -988,6 +1031,8 @@ typedef enum eOutliner_PropGroupOps { OL_GROUPOP_UNLINK = 1, OL_GROUPOP_LOCAL, OL_GROUPOP_LINK, + OL_GROUPOP_DELETE, + OL_GROUPOP_REMAP, OL_GROUPOP_INSTANCE, OL_GROUPOP_TOGVIS, OL_GROUPOP_TOGSEL, @@ -999,6 +1044,9 @@ static EnumPropertyItem prop_group_op_types[] = { {OL_GROUPOP_UNLINK, "UNLINK", 0, "Unlink Group", ""}, {OL_GROUPOP_LOCAL, "LOCAL", 0, "Make Local Group", ""}, {OL_GROUPOP_LINK, "LINK", 0, "Link Group Objects to Scene", ""}, + {OL_GROUPOP_DELETE, "DELETE", 0, "Delete Group", "WARNING: no undo"}, + {OL_GROUPOP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead current (clicked) one"}, {OL_GROUPOP_INSTANCE, "INSTANCE", 0, "Instance Groups in Scene", ""}, {OL_GROUPOP_TOGVIS, "TOGVIS", 0, "Toggle Visible Group", ""}, {OL_GROUPOP_TOGSEL, "TOGSEL", 0, "Toggle Selectable", ""}, @@ -1021,38 +1069,41 @@ static int outliner_group_operation_exec(bContext *C, wmOperator *op) switch (event) { case OL_GROUPOP_UNLINK: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_group_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_group_cb, NULL); break; case OL_GROUPOP_LOCAL: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); break; case OL_GROUPOP_LINK: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_linkobs2scene_cb, NULL); break; case OL_GROUPOP_INSTANCE: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_instance_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_instance_cb, NULL); + /* works without this except if you try render right after, see: 22027 */ + DAG_relations_tag_update(CTX_data_main(C)); + break; + case OL_GROUPOP_DELETE: + WM_operator_name_call(C, "OUTLINER_OT_id_delete", WM_OP_INVOKE_REGION_WIN, NULL); + break; + case OL_GROUPOP_REMAP: + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); break; case OL_GROUPOP_TOGVIS: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_visibility_cb, NULL); break; case OL_GROUPOP_TOGSEL: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_selectability_cb, NULL); break; case OL_GROUPOP_TOGREN: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, group_toggle_renderability_cb, NULL); break; case OL_GROUPOP_RENAME: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); break; default: BLI_assert(0); } - if (event == 3) { /* instance */ - /* works without this except if you try render right after, see: 22027 */ - DAG_relations_tag_update(CTX_data_main(C)); - } - ED_undo_push(C, prop_group_op_types[event - 1].name); WM_event_add_notifier(C, NC_GROUP, NULL); @@ -1085,6 +1136,8 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_UNLINK, OUTLINER_IDOP_LOCAL, OUTLINER_IDOP_SINGLE, + OUTLINER_IDOP_DELETE, + OUTLINER_IDOP_REMAP, OUTLINER_IDOP_FAKE_ADD, OUTLINER_IDOP_FAKE_CLEAR, @@ -1098,6 +1151,9 @@ static EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_UNLINK, "UNLINK", 0, "Unlink", ""}, {OUTLINER_IDOP_LOCAL, "LOCAL", 0, "Make Local", ""}, {OUTLINER_IDOP_SINGLE, "SINGLE", 0, "Make Single User", ""}, + {OUTLINER_IDOP_DELETE, "DELETE", 0, "Delete", "WARNING: no undo"}, + {OUTLINER_IDOP_REMAP, "REMAP", 0, "Remap Users", + "Make all users of selected datablocks to use instead current (clicked) one"}, {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, "Add Fake User", "Ensure datablock gets saved even if it isn't in use (e.g. for motion and material libraries)"}, {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, @@ -1127,25 +1183,25 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) /* unlink datablock from its parent */ switch (idlevel) { case ID_AC: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_action_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_action_cb, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); ED_undo_push(C, "Unlink action"); break; case ID_MA: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_material_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_material_cb, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); ED_undo_push(C, "Unlink material"); break; case ID_TE: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_texture_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_texture_cb, NULL); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); ED_undo_push(C, "Unlink texture"); break; case ID_WO: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, unlink_world_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, unlink_world_cb, NULL); WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Unlink world"); @@ -1159,7 +1215,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_LOCAL: { /* make local */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_local_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_local_cb, NULL); ED_undo_push(C, "Localized Data"); break; } @@ -1168,14 +1224,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) /* make single user */ switch (idlevel) { case ID_AC: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_action_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_action_cb, NULL); WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); ED_undo_push(C, "Single-User Action"); break; case ID_WO: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, singleuser_world_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, singleuser_world_cb, NULL); WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); ED_undo_push(C, "Single-User World"); @@ -1187,10 +1243,24 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } break; } + case OUTLINER_IDOP_DELETE: + { + if (idlevel > 0) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + } + break; + } + case OUTLINER_IDOP_REMAP: + { + if (idlevel > 0) { + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_remap_cb, NULL); + } + break; + } case OUTLINER_IDOP_FAKE_ADD: { /* set fake user */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_set_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Add Fake User"); @@ -1199,7 +1269,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_FAKE_CLEAR: { /* clear fake user */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_fake_user_clear_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Clear Fake User"); @@ -1208,14 +1278,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_RENAME: { /* rename */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Rename"); break; } case OUTLINER_IDOP_SELECT_LINKED: - outliner_do_libdata_operation(C, scene, soops, &soops->tree, id_select_linked_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_select_linked_cb, NULL); ED_undo_push(C, "Select"); break; @@ -1258,13 +1328,16 @@ typedef enum eOutlinerLibOpTypes { OL_LIB_RENAME, OL_LIB_DELETE, + OL_LIB_RELOCATE, + OL_LIB_RELOAD, } eOutlinerLibOpTypes; static EnumPropertyItem outliner_lib_op_type_items[] = { {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, - {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender (needs a save/reload)"}, + {OL_LIB_DELETE, "DELETE", 0, "Delete", "Delete this library and all its item from Blender - WARNING: no undo"}, + {OL_LIB_RELOCATE, "RELOCATE", 0, "Relocate", "Select a new path for this library, and reload all its data"}, + {OL_LIB_RELOAD, "RELOAD", 0, "Reload", "Reload all data from this library"}, {0, NULL, 0, NULL, NULL} - }; static int outliner_lib_operation_exec(bContext *C, wmOperator *op) @@ -1286,7 +1359,7 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) case OL_LIB_RENAME: { /* rename */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, item_rename_cb, NULL); + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, item_rename_cb, NULL); WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); ED_undo_push(C, "Rename"); @@ -1294,13 +1367,19 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) } case OL_LIB_DELETE: { - /* delete */ - outliner_do_libdata_operation(C, scene, soops, &soops->tree, lib_delete_cb, NULL); - - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); - /* Note: no undo possible here really, not 100% sure why... - * Probably because of library optimizations in undo/redo process? */ - /* ED_undo_push(C, "Rename"); */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, id_delete_cb, NULL); + break; + } + case OL_LIB_RELOCATE: + { + /* rename */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_relocate_cb, NULL); + break; + } + case OL_LIB_RELOAD: + { + /* rename */ + outliner_do_libdata_operation(C, op->reports, scene, soops, &soops->tree, lib_reload_cb, NULL); break; } default: diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index a687f61d69f..b22e6595caf 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -490,7 +490,7 @@ static void outliner_add_object_contents(SpaceOops *soops, TreeElement *te, Tree outliner_add_element(soops, &te->subtree, ob->poselib, te, 0, 0); // XXX FIXME.. add a special type for this - if (ob->proxy && ob->id.lib == NULL) + if (ob->proxy && !ID_IS_LINKED_DATABLOCK(ob)) outliner_add_element(soops, &te->subtree, ob->proxy, te, TSE_PROXY, 0); outliner_add_element(soops, &te->subtree, ob->gpd, te, 0, 0); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index 1dd66366e5d..76bf9c701ed 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -486,6 +486,39 @@ static SpaceLink *outliner_duplicate(SpaceLink *sl) return (SpaceLink *)soutlinern; } +static void outliner_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceOops *so = (SpaceOops *)slink; + + /* Some early out checks. */ + if (!TREESTORE_ID_TYPE(old_id)) { + return; /* ID type is not used by outilner... */ + } + + if (so->search_tse.id == old_id) { + so->search_tse.id = new_id; + } + + if (so->treestore) { + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + + BLI_mempool_iternew(so->treestore, &iter); + while ((tselem = BLI_mempool_iterstep(&iter))) { + if (tselem->id == old_id) { + tselem->id = new_id; + changed = true; + } + } + if (so->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + /* postpone a full rebuild because this can be called many times on-free */ + so->storeflag |= SO_TREESTORE_REBUILD; + } + } +} + /* only called once, from space_api/spacetypes.c */ void ED_spacetype_outliner(void) { @@ -502,7 +535,8 @@ void ED_spacetype_outliner(void) st->operatortypes = outliner_operatortypes; st->keymap = outliner_keymap; st->dropboxes = outliner_dropboxes; - + st->id_remap = outliner_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index c11a4d2e5a3..ede6b7ce469 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -1071,7 +1071,7 @@ static int sequencer_add_effect_strip_invoke(bContext *C, wmOperator *op, const { bool is_type_set = RNA_struct_property_is_set(op->ptr, "type"); int type = -1; - int prop_flag = SEQPROP_ENDFRAME; + int prop_flag = SEQPROP_ENDFRAME | SEQPROP_NOPATHS; if (is_type_set) { type = RNA_enum_get(op->ptr, "type"); @@ -1106,9 +1106,6 @@ void SEQUENCER_OT_effect_strip_add(struct wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - WM_operator_properties_filesel( - ot, 0, FILE_SPECIAL, FILE_OPENFILE, - WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); sequencer_generic_props__internal(ot, SEQPROP_STARTFRAME | SEQPROP_ENDFRAME); RNA_def_enum(ot->srna, "type", sequencer_prop_effect_types, SEQ_TYPE_CROSS, "Type", "Sequencer effect type"); RNA_def_float_vector(ot->srna, "color", 3, NULL, 0.0f, 1.0f, "Color", diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index fce40f8ca59..a2a80297041 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -32,6 +32,7 @@ #include <string.h> #include <stdio.h> +#include "DNA_gpencil_types.h" #include "DNA_scene_types.h" #include "DNA_mask_types.h" @@ -41,6 +42,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_sequencer.h" #include "BKE_global.h" @@ -687,6 +689,22 @@ static void sequencer_buttons_region_listener(bScreen *UNUSED(sc), ScrArea *UNUS break; } } + +static void sequencer_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceSeq *sseq = (SpaceSeq *)slink; + + if (!ELEM(GS(old_id->name), ID_GD)) { + return; + } + + if ((ID *)sseq->gpd == old_id) { + sseq->gpd = (bGPdata *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } +} + /* ************************************* */ /* only called once, from space/spacetypes.c */ @@ -708,6 +726,7 @@ void ED_spacetype_sequencer(void) st->dropboxes = sequencer_dropboxes; st->refresh = sequencer_refresh; st->listener = sequencer_listener; + st->id_remap = sequencer_id_remap; /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype sequencer region"); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index 0a6a9a81e63..686a10fc785 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -38,6 +38,7 @@ #include "BLI_blenlib.h" #include "BKE_context.h" +#include "BKE_library.h" #include "BKE_screen.h" #include "BKE_text.h" @@ -562,6 +563,20 @@ static void text_properties_region_draw(const bContext *C, ARegion *ar) } } +static void text_id_remap(ScrArea *UNUSED(sa), SpaceLink *slink, ID *old_id, ID *new_id) +{ + SpaceText *stext = (SpaceText *)slink; + + if (!ELEM(GS(old_id->name), ID_TXT)) { + return; + } + + if ((ID *)stext->text == old_id) { + stext->text = (Text *)new_id; + id_us_ensure_real(new_id); + } +} + /********************* registration ********************/ /* only called once, from space/spacetypes.c */ @@ -582,7 +597,8 @@ void ED_spacetype_text(void) st->listener = text_listener; st->context = text_context; st->dropboxes = text_dropboxes; - + st->id_remap = text_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype text region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index d404e7aaf15..e7428fd79d9 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -92,7 +92,7 @@ static int text_edit_poll(bContext *C) if (!text) return 0; - if (text->id.lib) { + if (ID_IS_LINKED_DATABLOCK(text)) { // BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); return 0; } @@ -108,7 +108,7 @@ int text_space_edit_poll(bContext *C) if (!st || !text) return 0; - if (text->id.lib) { + if (ID_IS_LINKED_DATABLOCK(text)) { // BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); return 0; } @@ -128,7 +128,7 @@ static int text_region_edit_poll(bContext *C) if (!ar || ar->regiontype != RGN_TYPE_WINDOW) return 0; - if (text->id.lib) { + if (ID_IS_LINKED_DATABLOCK(text)) { // BKE_report(op->reports, RPT_ERROR, "Cannot edit external libdata"); return 0; } @@ -384,8 +384,7 @@ static int text_unlink_exec(bContext *C, wmOperator *UNUSED(op)) } } - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); + BKE_libblock_delete(bmain, text); text_drawcache_tag_update(st, 1); WM_event_add_notifier(C, NC_TEXT | NA_REMOVED, NULL); diff --git a/source/blender/editors/space_view3d/drawmesh.c b/source/blender/editors/space_view3d/drawmesh.c index ee82a4c5072..791ece14cb9 100644 --- a/source/blender/editors/space_view3d/drawmesh.c +++ b/source/blender/editors/space_view3d/drawmesh.c @@ -979,10 +979,17 @@ static void draw_mesh_textured_old(Scene *scene, View3D *v3d, RegionView3D *rv3d if (ob == OBACT) { if (ob->mode & OB_MODE_WEIGHT_PAINT) { dm_draw_flag |= DM_DRAW_USE_COLORS | DM_DRAW_ALWAYS_SMOOTH | DM_DRAW_SKIP_HIDDEN; - } else if (ob->mode & OB_MODE_SCULPT) { - dm_draw_flag |= DM_DRAW_SKIP_HIDDEN; + dm_draw_flag |= DM_DRAW_SKIP_HIDDEN | DM_DRAW_USE_COLORS; + } + else if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { + dm_draw_flag |= DM_DRAW_USE_COLORS; + } + } + else { + if ((ob->mode & OB_MODE_TEXTURE_PAINT) == 0) { + dm_draw_flag |= DM_DRAW_USE_COLORS; } } diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 07e8325756f..4320699b8d7 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -1401,8 +1401,8 @@ static void drawlamp(View3D *v3d, RegionView3D *rv3d, Base *base, float blend = z_abs * (1.0f - pow2f(la->spotblend)); /* hide line if it is zero size or overlaps with outer border, - * previously it adjusted to always to show it but that seems - * confusing because it doesn't show the actual blend size */ + * previously it adjusted to always to show it but that seems + * confusing because it doesn't show the actual blend size */ if (blend != 0.0f && blend != z_abs) { circ(0.0f, 0.0f, blend); } @@ -3744,7 +3744,7 @@ static void draw_em_fancy(Scene *scene, ARegion *ar, View3D *v3d, } if ((dt > OB_WIRE) && (v3d->flag2 & V3D_RENDER_SHADOW)) { - /* pass */ + /* pass */ } else { /* annoying but active faces is stored differently */ @@ -4250,12 +4250,15 @@ static bool draw_mesh_object(Scene *scene, ARegion *ar, View3D *v3d, RegionView3 if (ob == obedit || drawlinked) { DerivedMesh *finalDM, *cageDM; - if (obedit != ob) - finalDM = cageDM = editbmesh_get_derived_base(ob, em); - else + if (obedit != ob) { + finalDM = cageDM = editbmesh_get_derived_base( + ob, em, scene->customdata_mask); + } + else { cageDM = editbmesh_get_derived_cage_and_final( scene, ob, em, scene->customdata_mask, &finalDM); + } const bool use_material = ((me->drawflag & ME_DRAWEIGHT) == 0); @@ -5015,7 +5018,7 @@ static void draw_new_particle_system(Scene *scene, View3D *v3d, RegionView3D *rv unsigned char tcol[4] = {0, 0, 0, 255}; /* 1. */ - if (part == NULL || !psys_check_enabled(ob, psys)) + if (part == NULL || !psys_check_enabled(ob, psys, G.is_rendering)) return; if (pars == NULL) return; @@ -5723,7 +5726,7 @@ static void draw_update_ptcache_edit(Scene *scene, Object *ob, PTCacheEdit *edit /* create path and child path cache if it doesn't exist already */ if (edit->pathcache == NULL) - psys_cache_edit_paths(scene, ob, edit, CFRA); + psys_cache_edit_paths(scene, ob, edit, CFRA, G.is_rendering); } static void draw_ptcache_edit(Scene *scene, View3D *v3d, PTCacheEdit *edit) @@ -7331,7 +7334,7 @@ static void draw_object_wire_color(Scene *scene, Base *base, unsigned char r_ob_ } else { /* Sets the 'colindex' */ - if (ob->id.lib) { + if (ID_IS_LINKED_DATABLOCK(ob)) { colindex = (base->flag & (SELECT + BA_WAS_SEL)) ? 2 : 1; } /* Sets the 'theme_id' or fallback to wire */ @@ -8087,7 +8090,7 @@ void draw_object(Scene *scene, ARegion *ar, View3D *v3d, Base *base, const short !(G.f & G_RENDER_OGL)) { /* check > 0 otherwise grease pencil can draw into the circle select which is annoying. */ - drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ob->id.lib || ob->id.us > 1); + drawcentercircle(v3d, rv3d, ob->obmat[3], do_draw_center, ID_IS_LINKED_DATABLOCK(ob) || ob->id.us > 1); } } } @@ -8216,7 +8219,7 @@ static void bbs_obmode_mesh_verts__mapFunc(void *userData, int index, const floa MVert *mv = &data->mvert[index]; if (!(mv->flag & ME_HIDE)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8241,7 +8244,7 @@ static void bbs_mesh_verts__mapFunc(void *userData, int index, const float co[3] BMVert *eve = BM_vert_at_index(data->bm, index); if (!BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); glVertex3fv(co); } } @@ -8260,7 +8263,7 @@ static DMDrawOption bbs_mesh_wire__setDrawOptions(void *userData, int index) BMEdge *eed = BM_edge_at_index(data->bm, index); if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(data->offset + index); + GPU_select_index_set(data->offset + index); return DM_DRAW_OPTION_NORMAL; } else { @@ -8274,7 +8277,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) } /** - * dont set #WM_framebuffer_index_set. just use to mask other + * dont set #GPU_framebuffer_index_set. just use to mask other */ static DMDrawOption bbs_mesh_mask__setSolidDrawOptions(void *userData, int index) { @@ -8293,7 +8296,7 @@ static DMDrawOption bbs_mesh_solid__setSolidDrawOptions(void *userData, int inde BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8306,7 +8309,7 @@ static void bbs_mesh_solid__drawCenter(void *userData, int index, const float ce BMFace *efa = BM_face_at_index(userData, index); if (!BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); glVertex3fv(cent); } @@ -8337,7 +8340,7 @@ static void bbs_mesh_solid_EM(BMEditMesh *em, Scene *scene, View3D *v3d, static DMDrawOption bbs_mesh_solid__setDrawOpts(void *UNUSED(userData), int index) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } @@ -8346,7 +8349,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) Mesh *me = userData; if (!(me->mpoly[index].flag & ME_HIDE)) { - WM_framebuffer_index_set(index + 1); + GPU_select_index_set(index + 1); return DM_DRAW_OPTION_NORMAL; } else { @@ -8354,7 +8357,7 @@ static DMDrawOption bbs_mesh_solid_hide__setDrawOpts(void *userData, int index) } } -/* must have called WM_framebuffer_index_set beforehand */ +/* must have called GPU_framebuffer_index_set beforehand */ static DMDrawOption bbs_mesh_solid_hide2__setDrawOpts(void *userData, int index) { Mesh *me = userData; @@ -8480,7 +8483,7 @@ static void draw_object_mesh_instance(Scene *scene, View3D *v3d, RegionView3D *r DerivedMesh *dm = NULL, *edm = NULL; if (ob->mode & OB_MODE_EDIT) { - edm = editbmesh_get_derived_base(ob, me->edit_btmesh); + edm = editbmesh_get_derived_base(ob, me->edit_btmesh, CD_MASK_BAREMESH); DM_update_materials(edm, ob); } else { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index fa14ca96fe2..96dda65b81d 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1400,6 +1400,66 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes return -1; /* found but not available */ } +static void view3d_id_remap(ScrArea *sa, SpaceLink *slink, ID *old_id, ID *new_id) +{ + View3D *v3d; + ARegion *ar; + bool is_local = false; + + if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) { + return; + } + + for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) { + if ((ID *)v3d->camera == old_id) { + v3d->camera = (Object *)new_id; + if (!new_id) { + for (ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = is_local ? ((RegionView3D *)ar->regiondata)->localvd : ar->regiondata; + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + rv3d->persp = RV3D_PERSP; + } + } + } + } + } + if ((ID *)v3d->ob_centre == old_id) { + v3d->ob_centre = (Object *)new_id; + if (new_id == NULL) { /* Otherwise, bonename may remain valid... We could be smart and check this, too? */ + v3d->ob_centre_bone[0] = '\0'; + } + } + + if ((ID *)v3d->defmaterial == old_id) { + v3d->defmaterial = (Material *)new_id; + } +#if 0 /* XXX Deprecated? */ + if ((ID *)v3d->gpd == old_id) { + v3d->gpd = (bGPData *)new_id; + } +#endif + + if (ELEM(GS(old_id->name), ID_IM, ID_MC)) { + for (BGpic *bgpic = v3d->bgpicbase.first; bgpic; bgpic = bgpic->next) { + if ((ID *)bgpic->ima == old_id) { + bgpic->ima = (Image *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + if ((ID *)bgpic->clip == old_id) { + bgpic->clip = (MovieClip *)new_id; + id_us_min(old_id); + id_us_plus(new_id); + } + } + } + + if (is_local) { + break; + } + } +} /* only called once, from space/spacetypes.c */ void ED_spacetype_view3d(void) @@ -1419,7 +1479,8 @@ void ED_spacetype_view3d(void) st->keymap = view3d_keymap; st->dropboxes = view3d_dropboxes; st->context = view3d_context; - + st->id_remap = view3d_id_remap; + /* regions: main window */ art = MEM_callocN(sizeof(ARegionType), "spacetype view3d main region"); art->regionid = RGN_TYPE_WINDOW; diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 9fb990b35a0..1de06af0478 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1488,7 +1488,7 @@ unsigned int ED_view3d_backbuf_sample(ViewContext *vc, int x, int y) BLI_endian_switch_uint32(&col); } - return WM_framebuffer_to_index(col); + return GPU_select_to_index(col); } /* reads full rect, converts indices */ @@ -1521,7 +1521,7 @@ ImBuf *ED_view3d_backbuf_read(ViewContext *vc, int xmin, int ymin, int xmax, int IMB_convert_rgba_to_abgr(ibuf_clip); } - WM_framebuffer_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); + GPU_select_to_index_array(ibuf_clip->rect, size_clip[0] * size_clip[1]); if ((clip.xmin == xmin) && (clip.xmax == xmax) && @@ -2599,6 +2599,7 @@ static void gpu_update_lamps_shadows_world(Scene *scene, View3D *v3d) GPU_mist_update_values(world->mistype, world->miststa, world->mistdist, world->misi, &world->horr); GPU_horizon_update_color(&world->horr); GPU_ambient_update_color(&world->ambr); + GPU_zenith_update_color(&world->zenr); } } diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index c25ea33109d..b117a5e68d8 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -110,7 +110,7 @@ static bool view3d_operator_offset_lock_check(bContext *C, wmOperator *op) bool ED_view3d_camera_lock_check(const View3D *v3d, const RegionView3D *rv3d) { return ((v3d->camera) && - (v3d->camera->id.lib == NULL) && + (!ID_IS_LINKED_DATABLOCK(v3d->camera)) && (v3d->flag2 & V3D_LOCK_CAMERA) && (rv3d->persp == RV3D_CAMOB)); } @@ -3079,7 +3079,9 @@ static int viewselected_exec(bContext *C, wmOperator *op) else if (ob && (ob->mode & OB_MODE_PARTICLE_EDIT)) { ok = PE_minmax(scene, min, max); } - else if (ob && (ob->mode & (OB_MODE_SCULPT | OB_MODE_TEXTURE_PAINT))) { + else if (ob && + (ob->mode & (OB_MODE_SCULPT | OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT))) + { BKE_paint_stroke_get_average(scene, ob, min); copy_v3_v3(max, min); ok = true; @@ -3434,12 +3436,8 @@ static int render_border_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); } - /* drawing a border surrounding the entire camera view switches off border rendering - * or the border covers no pixels */ - if ((border.xmin <= 0.0f && border.xmax >= 1.0f && - border.ymin <= 0.0f && border.ymax >= 1.0f) || - (border.xmin == border.xmax || border.ymin == border.ymax)) - { + /* drawing a border outside the camera view switches off border rendering */ + if ((border.xmin == border.xmax || border.ymin == border.ymax)) { if (rv3d->persp == RV3D_CAMOB) scene->r.mode &= ~R_BORDER; else @@ -3620,7 +3618,7 @@ static int view3d_zoom_border_exec(bContext *C, wmOperator *op) dist_range[0] = v3d->near * 1.5f; } else { /* othographic */ - /* find the current window width and height */ + /* find the current window width and height */ vb[0] = ar->winx; vb[1] = ar->winy; diff --git a/source/blender/editors/space_view3d/view3d_fly.c b/source/blender/editors/space_view3d/view3d_fly.c index 8418cf0980c..31377d0fce8 100644 --- a/source/blender/editors/space_view3d/view3d_fly.c +++ b/source/blender/editors/space_view3d/view3d_fly.c @@ -346,7 +346,7 @@ static bool initFlyInfo(bContext *C, FlyInfo *fly, wmOperator *op, const wmEvent fly->rv3d->persp = RV3D_PERSP; } - if (fly->rv3d->persp == RV3D_CAMOB && fly->v3d->camera->id.lib) { + if (fly->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(fly->v3d->camera)) { BKE_report(op->reports, RPT_ERROR, "Cannot fly a camera from an external library"); return false; } diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 6d831c667a8..bdd2702a6ce 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -274,6 +274,7 @@ bool ED_view3d_minmax_verts(struct Object *obedit, float min[3], float max[3]); void VIEW3D_OT_snap_selected_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_selected_to_cursor(struct wmOperatorType *ot); +void VIEW3D_OT_snap_selected_to_active(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_grid(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_center(struct wmOperatorType *ot); void VIEW3D_OT_snap_cursor_to_selected(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 1c84ce3c985..b273f46fca3 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -214,6 +214,7 @@ void view3d_operatortypes(void) WM_operatortype_append(VIEW3D_OT_snap_selected_to_grid); WM_operatortype_append(VIEW3D_OT_snap_selected_to_cursor); + WM_operatortype_append(VIEW3D_OT_snap_selected_to_active); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_grid); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_center); WM_operatortype_append(VIEW3D_OT_snap_cursor_to_selected); diff --git a/source/blender/editors/space_view3d/view3d_project.c b/source/blender/editors/space_view3d/view3d_project.c index 797d97586c7..7448d4c658e 100644 --- a/source/blender/editors/space_view3d/view3d_project.c +++ b/source/blender/editors/space_view3d/view3d_project.c @@ -302,8 +302,9 @@ float ED_view3d_calc_zfac(const RegionView3D *rv3d, const float co[3], bool *r_f return zfac; } -static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) +static void view3d_win_to_ray_segment( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_dir[3], float r_ray_start[3], float r_ray_end[3]) { RegionView3D *rv3d = ar->regiondata; float _ray_co[3], _ray_dir[3], start_offset, end_offset; @@ -311,25 +312,9 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa if (!r_ray_co) r_ray_co = _ray_co; if (!r_ray_dir) r_ray_dir = _ray_dir; + ED_view3d_win_to_origin(ar, mval, r_ray_co); ED_view3d_win_to_vector(ar, mval, r_ray_dir); - if (rv3d->is_persp) { - copy_v3_v3(r_ray_co, rv3d->viewinv[3]); - } - else { - r_ray_co[0] = 2.0f * mval[0] / ar->winx - 1.0f; - r_ray_co[1] = 2.0f * mval[1] / ar->winy - 1.0f; - - if (rv3d->persp == RV3D_CAMOB) { - r_ray_co[2] = -1.0f; - } - else { - r_ray_co[2] = 0.0f; - } - - mul_project_m4_v3(rv3d->persinv, r_ray_co); - } - if ((rv3d->is_persp == false) && (rv3d->persp != RV3D_CAMOB)) { end_offset = v3d->far / 2.0f; start_offset = -end_offset; @@ -346,7 +331,7 @@ static void view3d_win_to_ray_segment(const ARegion *ar, View3D *v3d, const floa } } -BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], float ray_end[3]) +bool ED_view3d_clip_segment(const RegionView3D *rv3d, float ray_start[3], float ray_end[3]) { if ((rv3d->rflag & RV3D_CLIPPING) && (clip_segment_v3_plane_n(ray_start, ray_end, rv3d->clip, 6, @@ -373,8 +358,9 @@ BLI_INLINE bool view3d_clip_segment(RegionView3D *rv3d, float ray_start[3], floa * \param do_clip Optionally clip the start of the ray by the view clipping planes. * \return success, false if the ray is totally clipped. */ -bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) +bool ED_view3d_win_to_ray_ex( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_co[3], float r_ray_normal[3], float r_ray_start[3], bool do_clip) { float ray_end[3]; @@ -382,7 +368,7 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2] /* bounds clipping */ if (do_clip) { - return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, ray_end); + return ED_view3d_clip_segment(ar->regiondata, r_ray_start, ray_end); } return true; @@ -401,8 +387,9 @@ bool ED_view3d_win_to_ray_ex(const ARegion *ar, View3D *v3d, const float mval[2] * \param do_clip Optionally clip the start of the ray by the view clipping planes. * \return success, false if the ray is totally clipped. */ -bool ED_view3d_win_to_ray(const ARegion *ar, View3D *v3d, const float mval[2], - float r_ray_start[3], float r_ray_normal[3], const bool do_clip) +bool ED_view3d_win_to_ray( + const ARegion *ar, const View3D *v3d, const float mval[2], + float r_ray_start[3], float r_ray_normal[3], const bool do_clip) { return ED_view3d_win_to_ray_ex(ar, v3d, mval, NULL, r_ray_normal, r_ray_start, do_clip); } @@ -546,6 +533,37 @@ void ED_view3d_win_to_delta(const ARegion *ar, const float mval[2], float out[3] } /** + * Calculate a 3d origin from 2d window coordinates. + * \note Orthographic views have a less obvious origin, + * Since far clip can be a very large value resulting in numeric precision issues, + * the origin in this case is close to zero coordinate. + * + * \param ar The region (used for the window width and height). + * \param mval The area relative 2d location (such as event->mval converted to floats). + * \param out The resulting normalized world-space direction vector. + */ +void ED_view3d_win_to_origin(const ARegion *ar, const float mval[2], float out[3]) +{ + RegionView3D *rv3d = ar->regiondata; + if (rv3d->is_persp) { + copy_v3_v3(out, rv3d->viewinv[3]); + } + else { + out[0] = 2.0f * mval[0] / ar->winx - 1.0f; + out[1] = 2.0f * mval[1] / ar->winy - 1.0f; + + if (rv3d->persp == RV3D_CAMOB) { + out[2] = -1.0f; + } + else { + out[2] = 0.0f; + } + + mul_project_m4_v3(rv3d->persinv, out); + } +} + +/** * Calculate a 3d direction vector from 2d window coordinates. * This direction vector starts and the view in the direction of the 2d window coordinates. * In orthographic view all window coordinates yield the same vector. @@ -596,7 +614,7 @@ bool ED_view3d_win_to_segment(const ARegion *ar, View3D *v3d, const float mval[2 /* bounds clipping */ if (do_clip) { - return view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); + return ED_view3d_clip_segment((RegionView3D *)ar->regiondata, r_ray_start, r_ray_end); } return true; diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index c6951c79609..f46608b7d5e 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -259,6 +259,37 @@ static bool view3d_ruler_pick(RulerInfo *ruler_info, const float mval[2], } } +/** + * Ensure the 'snap_context' is only cached while dragging, + * needed since the user may toggle modes between tool use. + */ +static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) +{ + if (state == ruler_info->state) { + return; + } + + /* always remove */ + if (ruler_info->snap_context) { + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + ruler_info->snap_context = NULL; + } + + if (state == RULER_STATE_NORMAL) { + /* pass */ + } + else if (state == RULER_STATE_DRAG) { + ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( + CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, + ruler_info->ar, CTX_wm_view3d(C)); + } + else { + BLI_assert(0); + } + + ruler_info->state = state; +} + #define RULER_ID "RulerData3D" static bool view3d_ruler_to_gpencil(bContext *C, RulerInfo *ruler_info) { @@ -640,7 +671,9 @@ static void view3d_ruler_free(RulerInfo *ruler_info) { BLI_freelistN(&ruler_info->items); - ED_transform_snap_object_context_destroy(ruler_info->snap_context); + if (ruler_info->snap_context) { + ED_transform_snap_object_context_destroy(ruler_info->snap_context); + } MEM_freeN(ruler_info); } @@ -757,10 +790,6 @@ static int view3d_ruler_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSE op->customdata = ruler_info; - ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), SNAP_OBJECT_USE_CACHE, - ar, CTX_wm_view3d(C)); - ruler_info->win = win; ruler_info->sa = sa; ruler_info->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ruler_info_draw_pixel, @@ -818,7 +847,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) ruler_info->snap_flag &= ~RULER_SNAP_OK; do_draw = true; } - ruler_info->state = RULER_STATE_NORMAL; + ruler_state_set(C, ruler_info, RULER_STATE_NORMAL); } } else { @@ -835,7 +864,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) RulerItem *ruler_item_prev = ruler_item_active_get(ruler_info); RulerItem *ruler_item; /* check if we want to drag an existing point or add a new one */ - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); ruler_item = ruler_item_add(ruler_info); ruler_item_active_set(ruler_info, ruler_item); @@ -877,7 +906,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->flag |= RULERITEM_USE_ANGLE; ruler_item_pick->co_index = 1; - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); /* find the factor */ { @@ -904,7 +933,7 @@ static int view3d_ruler_modal(bContext *C, wmOperator *op, const wmEvent *event) else { ruler_item_active_set(ruler_info, ruler_item_pick); ruler_item_pick->co_index = co_index; - ruler_info->state = RULER_STATE_DRAG; + ruler_state_set(C, ruler_info, RULER_STATE_DRAG); /* store the initial depth */ copy_v3_v3(ruler_info->drag_start_co, ruler_item_pick->co[ruler_item_pick->co_index]); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bedcf413bfa..a460d8900b4 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -94,6 +94,8 @@ #include "UI_interface.h" +#include "GPU_draw.h" + #include "view3d_intern.h" /* own include */ float ED_view3d_select_dist_px(void) @@ -1690,7 +1692,7 @@ static int do_paintvert_box_select(ViewContext *vc, rcti *rect, bool select, boo if (ENDIAN_ORDER == B_ENDIAN) { IMB_convert_rgba_to_abgr(ibuf); } - WM_framebuffer_to_index_array(ibuf->rect, size[0] * size[1]); + GPU_select_to_index_array(ibuf->rect, size[0] * size[1]); a = size[0] * size[1]; while (a--) { diff --git a/source/blender/editors/space_view3d/view3d_snap.c b/source/blender/editors/space_view3d/view3d_snap.c index e8e7d3c62fb..5dd69cc66eb 100644 --- a/source/blender/editors/space_view3d/view3d_snap.c +++ b/source/blender/editors/space_view3d/view3d_snap.c @@ -44,6 +44,7 @@ #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_object.h" +#include "BKE_report.h" #include "BKE_tracking.h" #include "WM_api.h" @@ -204,7 +205,7 @@ void VIEW3D_OT_snap_selected_to_grid(wmOperatorType *ot) /* *************************************************** */ -static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) +static int snap_selected_to_location(bContext *C, const float snap_target_global[3], const bool use_offset) { Scene *scene = CTX_data_scene(C); Object *obedit = CTX_data_edit_object(C); @@ -213,15 +214,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) TransVertStore tvs = {NULL}; TransVert *tv; float imat[3][3], bmat[3][3]; - const float *cursor_global; float center_global[3]; float offset_global[3]; int a; - const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); - - cursor_global = ED_view3d_cursor3d_get(scene, v3d); - if (use_offset) { if ((v3d && v3d->around == V3D_AROUND_ACTIVE) && snap_calc_active_center(C, true, center_global)) @@ -231,11 +227,11 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { snap_curs_to_sel_ex(C, center_global); } - sub_v3_v3v3(offset_global, cursor_global, center_global); + sub_v3_v3v3(offset_global, snap_target_global, center_global); } if (obedit) { - float cursor_local[3]; + float snap_target_local[3]; if (ED_transverts_check_obedit(obedit)) ED_transverts_create_from_obedit(&tvs, obedit, 0); @@ -246,8 +242,8 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) invert_m3_m3(imat, bmat); /* get the cursor in object space */ - sub_v3_v3v3(cursor_local, cursor_global, obedit->obmat[3]); - mul_m3_v3(imat, cursor_local); + sub_v3_v3v3(snap_target_local, snap_target_global, obedit->obmat[3]); + mul_m3_v3(imat, snap_target_local); if (use_offset) { float offset_local[3]; @@ -262,7 +258,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) else { tv = tvs.transverts; for (a = 0; a < tvs.transverts_tot; a++, tv++) { - copy_v3_v3(tv->loc, cursor_local); + copy_v3_v3(tv->loc, snap_target_local); } } @@ -274,10 +270,10 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) bPoseChannel *pchan; bArmature *arm = obact->data; - float cursor_local[3]; + float snap_target_local[3]; invert_m4_m4(obact->imat, obact->obmat); - mul_v3_m4v3(cursor_local, obact->imat, cursor_global); + mul_v3_m4v3(snap_target_local, obact->imat, snap_target_global); for (pchan = obact->pose->chanbase.first; pchan; pchan = pchan->next) { if ((pchan->bone->flag & BONE_SELECTED) && @@ -311,7 +307,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) BKE_armature_loc_pose_to_bone(pchan, cursor_pose, cursor_pose); } else { - BKE_armature_loc_pose_to_bone(pchan, cursor_local, cursor_pose); + BKE_armature_loc_pose_to_bone(pchan, snap_target_local, cursor_pose); } /* copy new position */ @@ -367,7 +363,7 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) add_v3_v3v3(cursor_parent, ob->obmat[3], offset_global); } else { - copy_v3_v3(cursor_parent, cursor_global); + copy_v3_v3(cursor_parent, snap_target_global); } sub_v3_v3(cursor_parent, ob->obmat[3]); @@ -401,6 +397,18 @@ static int snap_sel_to_curs_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +static int snap_selected_to_cursor_exec(bContext *C, wmOperator *op) +{ + const bool use_offset = RNA_boolean_get(op->ptr, "use_offset"); + + Scene *scene = CTX_data_scene(C); + View3D *v3d = CTX_wm_view3d(C); + + const float *snap_target_global = ED_view3d_cursor3d_get(scene, v3d); + + return snap_selected_to_location(C, snap_target_global, use_offset); +} + void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) { /* identifiers */ @@ -409,7 +417,7 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) ot->idname = "VIEW3D_OT_snap_selected_to_cursor"; /* api callbacks */ - ot->exec = snap_sel_to_curs_exec; + ot->exec = snap_selected_to_cursor_exec; ot->poll = ED_operator_view3d_active; /* flags */ @@ -419,6 +427,34 @@ void VIEW3D_OT_snap_selected_to_cursor(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_offset", 1, "Offset", ""); } +static int snap_selected_to_active_exec(bContext *C, wmOperator *op) +{ + float snap_target_global[3]; + + if (snap_calc_active_center(C, false, snap_target_global) == false) { + BKE_report(op->reports, RPT_ERROR, "No active element found!"); + return OPERATOR_CANCELLED; + } + + return snap_selected_to_location(C, snap_target_global, false); +} + +void VIEW3D_OT_snap_selected_to_active(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Snap Selection to Active"; + ot->description = "Snap selected item(s) to the active item"; + ot->idname = "VIEW3D_OT_snap_selected_to_active"; + + /* api callbacks */ + ot->exec = snap_selected_to_active_exec; + ot->poll = ED_operator_view3d_active; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + + /* *************************************************** */ static int snap_curs_to_grid_exec(bContext *C, wmOperator *UNUSED(op)) diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c index c35646b9e92..bc7a9989c72 100644 --- a/source/blender/editors/space_view3d/view3d_view.c +++ b/source/blender/editors/space_view3d/view3d_view.c @@ -221,7 +221,7 @@ void ED_view3d_smooth_view_ex( copy_v3_v3(sms.dyn_ofs, sview->dyn_ofs); sms.use_dyn_ofs = true; - /* calcualte the final destination offset */ + /* calculate the final destination offset */ view3d_orbit_apply_dyn_ofs(sms.dst.ofs, sms.src.ofs, sms.src.quat, sms.dst.quat, sms.dyn_ofs); } @@ -507,7 +507,7 @@ static int view3d_camera_to_view_poll(bContext *C) if (ED_view3d_context_user_region(C, &v3d, &ar)) { RegionView3D *rv3d = ar->regiondata; - if (v3d && v3d->camera && v3d->camera->id.lib == NULL) { + if (v3d && v3d->camera && !ID_IS_LINKED_DATABLOCK(v3d->camera)) { if (rv3d && (rv3d->viewlock & RV3D_LOCKED) == 0) { if (rv3d->persp != RV3D_CAMOB) { return 1; diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 384da277612..c9e4bb301b8 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -505,7 +505,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->persp = RV3D_PERSP; } - if (walk->rv3d->persp == RV3D_CAMOB && walk->v3d->camera->id.lib) { + if (walk->rv3d->persp == RV3D_CAMOB && ID_IS_LINKED_DATABLOCK(walk->v3d->camera)) { BKE_report(op->reports, RPT_ERROR, "Cannot navigate a camera from an external library"); return false; } @@ -924,8 +924,7 @@ static void walkEvent(bContext *C, wmOperator *op, WalkInfo *walk, const wmEvent copy_v3_v3(teleport->origin, walk->rv3d->viewinv[3]); /* stop the camera from a distance (camera height) */ - normalize_v3(nor); - mul_v3_fl(nor, walk->view_height); + normalize_v3_length(nor, walk->view_height); add_v3_v3(loc, nor); sub_v3_v3v3(teleport->direction, loc, teleport->origin); diff --git a/source/blender/editors/transform/transform.c b/source/blender/editors/transform/transform.c index 74ed2014f55..f18493e4b34 100644 --- a/source/blender/editors/transform/transform.c +++ b/source/blender/editors/transform/transform.c @@ -100,7 +100,6 @@ static void doVertSlide(TransInfo *t, float perc); static void drawEdgeSlide(TransInfo *t); static void drawVertSlide(TransInfo *t); -static void len_v3_ensure(float v[3], const float length); static void postInputRotation(TransInfo *t, float values[3]); static void ElementRotation(TransInfo *t, TransData *td, float mat[3][3], short around); @@ -1202,8 +1201,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) if (t->flag & T_PROP_EDIT) { float fac = 1.0f + 0.005f *(event->y - event->prevy); t->prop_size *= fac; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) - t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { + t->prop_size = max_ff(min_ff(t->prop_size, ((View3D *)t->view)->far), T_PROP_SIZE_MIN); + } + else { + t->prop_size = max_ff(min_ff(t->prop_size, T_PROP_SIZE_MAX), T_PROP_SIZE_MIN); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1212,8 +1215,12 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_UP: if (t->flag & T_PROP_EDIT) { t->prop_size *= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; - if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) + if (t->spacetype == SPACE_VIEW3D && t->persp != RV3D_ORTHO) { t->prop_size = min_ff(t->prop_size, ((View3D *)t->view)->far); + } + else { + t->prop_size = min_ff(t->prop_size, T_PROP_SIZE_MAX); + } calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -1222,6 +1229,7 @@ int transformEvent(TransInfo *t, const wmEvent *event) case TFM_MODAL_PROPSIZE_DOWN: if (t->flag & T_PROP_EDIT) { t->prop_size /= (t->modifiers & MOD_PRECISION) ? 1.01f : 1.1f; + t->prop_size = max_ff(t->prop_size, T_PROP_SIZE_MIN); calculatePropRatio(t); t->redraw |= TREDRAW_HARD; handled = true; @@ -4948,9 +4956,7 @@ static void applyPushPull(TransInfo *t, const int UNUSED(mval[2])) project_v3_v3v3(vec, vec, axis); } } - normalize_v3(vec); - mul_v3_fl(vec, distance); - mul_v3_fl(vec, td->factor); + normalize_v3_length(vec, distance * td->factor); add_v3_v3v3(td->loc, td->iloc, vec); } @@ -5366,7 +5372,9 @@ static void slide_origdata_init_data( BMesh *bm = em->bm; sod->origfaces = BLI_ghash_ptr_new(__func__); - sod->bm_origfaces = BM_mesh_create(&bm_mesh_allocsize_default); + sod->bm_origfaces = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = false,})); /* we need to have matching customdata */ BM_mesh_copy_init_customdata(sod->bm_origfaces, bm, NULL); } @@ -5742,13 +5750,6 @@ static void interp_line_v3_v3v3v3(float p[3], const float v1[3], const float v2[ } } - -static void len_v3_ensure(float v[3], const float length) -{ - normalize_v3(v); - mul_v3_fl(v, length); -} - /** * Find the closest point on the ngon on the opposite side. * used to set the edge slide distance for ngons. @@ -5812,7 +5813,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, if (l->e == e_next) { if (i) { - len_v3_ensure(vec_accum, vec_accum_len / (float)i); + normalize_v3_length(vec_accum, vec_accum_len / (float)i); } else { /* When there is no edge to slide along, @@ -5832,7 +5833,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, cross_v3_v3v3(vec_accum, l_tmp->f->no, tdir); #if 0 /* rough guess, we can do better! */ - len_v3_ensure(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f); + normalize_v3_length(vec_accum, (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f); #else /* be clever, check the opposite ngon edge to slide into. * this gives best results */ @@ -5847,7 +5848,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, dist = (BM_edge_calc_length(e_prev) + BM_edge_calc_length(e_next)) / 2.0f; } - len_v3_ensure(vec_accum, dist); + normalize_v3_length(vec_accum, dist); } #endif } @@ -5868,7 +5869,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, if (BM_loop_other_edge_loop(l, v)->e == e_next) { if (i) { - len_v3_ensure(vec_accum, vec_accum_len / (float)i); + normalize_v3_length(vec_accum, vec_accum_len / (float)i); } copy_v3_v3(r_slide_vec, vec_accum); @@ -5879,7 +5880,7 @@ static BMLoop *get_next_loop(BMVert *v, BMLoop *l, ((l = l->radial_next) != l_first)); if (i) { - len_v3_ensure(vec_accum, vec_accum_len / (float)i); + normalize_v3_length(vec_accum, vec_accum_len / (float)i); } copy_v3_v3(r_slide_vec, vec_accum); diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 0e0d085bf6f..50168e78dda 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -592,6 +592,10 @@ typedef struct TransInfo { #define POINT_INIT 4 #define MULTI_POINTS 8 +/* Hard min/max for proportional size. */ +#define T_PROP_SIZE_MIN 1e-6f +#define T_PROP_SIZE_MAX 1e12f + bool initTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op, const struct wmEvent *event, int mode); void saveTransform(struct bContext *C, struct TransInfo *t, struct wmOperator *op); int transformEvent(TransInfo *t, const struct wmEvent *event); diff --git a/source/blender/editors/transform/transform_constraints.c b/source/blender/editors/transform/transform_constraints.c index 13cc0c22778..d7b670b6476 100644 --- a/source/blender/editors/transform/transform_constraints.c +++ b/source/blender/editors/transform/transform_constraints.c @@ -187,9 +187,7 @@ static void viewAxisCorrectCenter(TransInfo *t, float t_con_center[3]) if (l < min_dist) { float diff[3]; - normalize_v3_v3(diff, t->viewinv[2]); - mul_v3_fl(diff, min_dist - l); - + normalize_v3_v3_length(diff, t->viewinv[2], min_dist - l); sub_v3_v3(t_con_center, diff); } } @@ -225,9 +223,8 @@ static void axisProjection(TransInfo *t, const float axis[3], const float in[3], if (factor < 0.0f) factor *= -factor; else factor *= factor; - copy_v3_v3(out, axis); - normalize_v3(out); - mul_v3_fl(out, -factor); /* -factor makes move down going backwards */ + /* -factor makes move down going backwards */ + normalize_v3_v3_length(out, axis, -factor); } else { float v[3], i1[3], i2[3]; diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index f98fc7bf226..fc32613c1ab 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -6429,7 +6429,7 @@ static void createTransObject(bContext *C, TransInfo *t) } /* select linked objects, but skip them later */ - if (ob->id.lib != NULL) { + if (ID_IS_LINKED_DATABLOCK(ob)) { td->flag |= TD_SKIP; } @@ -7607,7 +7607,7 @@ static void createTransPaintCurveVerts(bContext *C, TransInfo *t) for (pcp = pc->points, i = 0; i < pc->tot_points; i++, pcp++) { if (PC_IS_ANY_SEL(pcp)) { - PaintCurvePointToTransData (pcp, td, td2d, tdpc); + PaintCurvePointToTransData(pcp, td, td2d, tdpc); if (pcp->bez.f2 & SELECT) { td += 3; diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index 67740644afe..728b10f5e6f 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -563,7 +563,7 @@ static void recalcData_nla(TransInfo *t) } /* Use RNA to write the values to ensure that constraints on these are obeyed - * (e.g. for transition strips, the values are taken from the neighbours) + * (e.g. for transition strips, the values are taken from the neighbors) * * NOTE: we write these twice to avoid truncation errors which can arise when * moving the strips a large distance using numeric input [#33852] diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index 992fde0cce3..309ad22e31c 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -995,8 +995,7 @@ static void draw_manipulator_rotate( vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); vec[2] = 0.0f; - normalize_v3(vec); - mul_v3_fl(vec, 1.2f * size); + normalize_v3_length(vec, 1.2f * size); glBegin(GL_LINES); glVertex3f(0.0f, 0.0f, 0.0f); glVertex3fv(vec); @@ -1516,8 +1515,7 @@ static void draw_manipulator_rotate_cyl( vec[0] = 0; // XXX (float)(t->mouse.imval[0] - t->center2d[0]); vec[1] = 0; // XXX (float)(t->mouse.imval[1] - t->center2d[1]); vec[2] = 0.0f; - normalize_v3(vec); - mul_v3_fl(vec, 1.2f * size); + normalize_v3_length(vec, 1.2f * size); glBegin(GL_LINES); glVertex3f(0.0, 0.0, 0.0); glVertex3fv(vec); diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 2fb92d73515..6e399d9fde3 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -528,7 +528,8 @@ void Transform_Properties(struct wmOperatorType *ot, int flags) prop = RNA_def_enum(ot->srna, "proportional_edit_falloff", rna_enum_proportional_falloff_items, 0, "Proportional Editing Falloff", "Falloff type for proportional editing mode"); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_CURVE); /* Abusing id_curve :/ */ - RNA_def_float(ot->srna, "proportional_size", 1, 0.00001f, FLT_MAX, "Proportional Size", "", 0.001, 100); + RNA_def_float(ot->srna, "proportional_size", 1, T_PROP_SIZE_MIN, T_PROP_SIZE_MAX, + "Proportional Size", "", 0.001f, 100.0f); } if (flags & P_SNAP) { diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index e1cf7436236..0bb64315845 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -599,15 +599,15 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, SNAP_OBJECT_USE_CACHE, - t->ar, t->view); + G.main, t->scene, SNAP_OBJECT_USE_CACHE, + t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( - t->tsnap.object_context, - (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, - bm_edge_is_snap_target, - bm_face_is_snap_target, - SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + bm_edge_is_snap_target, + bm_face_is_snap_target, + SET_UINT_IN_POINTER((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } } } @@ -842,6 +842,14 @@ static void ApplySnapTranslation(TransInfo *t, float vec[3]) vec[1] = point[1] - t->tsnap.snapTarget[1]; } else { + if (t->spacetype == SPACE_VIEW3D) { + if (t->options & CTX_PAINT_CURVE) { + if (ED_view3d_project_float_global(t->ar, point, point, V3D_PROJ_TEST_NOP) != V3D_PROJ_RET_OK) { + zero_v3(point); /* no good answer here... */ + } + } + } + sub_v3_v3v3(vec, point, t->tsnap.snapTarget); } } diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index f92f0b33faa..c3adebec9d8 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -68,13 +68,13 @@ typedef struct SnapObjectData { typedef struct SnapObjectData_Mesh { SnapObjectData sd; - BVHTreeFromMesh *bvh_trees[2]; + BVHTreeFromMesh *bvh_trees[3]; } SnapObjectData_Mesh; typedef struct SnapObjectData_EditMesh { SnapObjectData sd; - BVHTreeFromEditMesh *bvh_trees[2]; + BVHTreeFromEditMesh *bvh_trees[3]; } SnapObjectData_EditMesh; @@ -87,8 +87,8 @@ struct SnapObjectContext { * otherwise this doesn't take viewport into account. */ bool use_v3d; struct { - struct View3D *v3d; - struct ARegion *ar; + const struct View3D *v3d; + const struct ARegion *ar; } v3d_data; @@ -110,6 +110,12 @@ struct SnapObjectContext { }; +enum eViewProj { + VIEW_PROJ_NONE = -1, + VIEW_PROJ_ORTHO = 0, + VIEW_PROJ_PERSP = -1, +}; + static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt); @@ -137,10 +143,6 @@ struct RayCastAll_Data { Object *ob; unsigned int ob_uuid; - /* DerivedMesh only */ - DerivedMesh *dm; - const struct MLoopTri *dm_looptri; - /* output data */ ListBase *hit_list; bool retval; @@ -218,188 +220,557 @@ static void raycast_all_cb(void *userdata, int index, const BVHTreeRay *ray, BVH /* -------------------------------------------------------------------- */ -/** \name Internal Object Snapping API +/** \Common utilities * \{ */ -static bool snapEdge( - ARegion *ar, const float v1co[3], const short v1no[3], const float v2co[3], const short v2no[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, - float r_loc[3], float r_no[3]) -{ - float intersect[3] = {0, 0, 0}, ray_end[3], dvec[3]; - int result; - bool retval = false; - copy_v3_v3(ray_end, ray_normal_local); - mul_v3_fl(ray_end, 2000); - add_v3_v3v3(ray_end, ray_start_local, ray_end); +/** + * Struct that kepts basic information about a BVHTree build from a editmesh. + */ +typedef struct BVHTreeFromMeshType { + void *userdata; + char type; +} BVHTreeFromMeshType; + +typedef struct PreDefProject { + float pmat[4][4]; /* perspective matrix multiplied by object matrix */ + float win_half[2]; + float dist_px_sq; +} PreDefProject; + +static void precalc_project( + PreDefProject *projectdefs, const ARegion *ar, + const float dist_px, float obmat[4][4]) +{ + float (*pmat)[4] = ((RegionView3D *)ar->regiondata)->persmat; + if (obmat) { + mul_m4_m4m4(projectdefs->pmat, pmat, obmat); + } + else { + copy_m4_m4(projectdefs->pmat, pmat); + } + projectdefs->win_half[0] = ar->winx / 2; + projectdefs->win_half[1] = ar->winy / 2; + projectdefs->dist_px_sq = SQUARE(dist_px); +} - /* dvec used but we don't care about result */ - result = isect_line_line_v3(v1co, v2co, ray_start_local, ray_end, intersect, dvec); +/** + * From a threshold (maximum distance to snap in pixels) returns: + * + * - The *real* distance (3D) if you are in orthographic-view. + * - The *tangent* (view cone radius at distance 1.0) if you are in perspective-view. + */ +static float dist_px_to_dist3d_or_tangent(const ARegion *ar, const float dist_px) +{ + const RegionView3D *rv3d = ar->regiondata; + if (ar->winx >= ar->winy) + return 2 * (dist_px / ar->winx) / rv3d->winmat[0][0]; + else + return 2 * (dist_px / ar->winy) / rv3d->winmat[1][1]; +} - if (result) { - float edge_loc[3], vec[3]; - float mul; +static const float *get_vert_co(const BVHTreeFromMeshType *meshdata, const int index) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + return vert[index].co; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + return eve->co; + } + } + return NULL; +} - /* check for behind ray_start */ - sub_v3_v3v3(dvec, intersect, ray_start_local); +static void copy_vert_no(const BVHTreeFromMeshType *meshdata, const int index, float r_no[3]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; + const MVert *vert = data->vert; + normal_short_to_float_v3(r_no, vert->no); + break; + } + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMVert *eve = BM_vert_at_index(data->em->bm, index); + copy_v3_v3(r_no, eve->no); + break; + } + } +} - sub_v3_v3v3(edge_loc, v1co, v2co); - sub_v3_v3v3(vec, intersect, v2co); +static void get_edge_verts( + const BVHTreeFromMeshType *meshdata, const int index, + const float *v_pair[2]) +{ + switch (meshdata->type) { + case SNAP_MESH: + { + BVHTreeFromMesh *data = meshdata->userdata; - mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); + const MVert *vert = data->vert; + const MEdge *edge = data->edge + index; - if (mul > 1) { - mul = 1; - copy_v3_v3(intersect, v1co); + v_pair[0] = vert[edge->v1].co; + v_pair[1] = vert[edge->v2].co; + break; } - else if (mul < 0) { - mul = 0; - copy_v3_v3(intersect, v2co); + case SNAP_EDIT_MESH: + { + BVHTreeFromEditMesh *data = meshdata->userdata; + BMEdge *eed = BM_edge_at_index(data->em->bm, index); + + v_pair[0] = eed->v1->co; + v_pair[1] = eed->v2->co; + break; } + } +} - if (dot_v3v3(ray_normal_local, dvec) > 0) { - float location[3]; - float new_depth; - float screen_loc[2]; - float new_dist; +#define V3_MUL_ELEM(a, b) \ + (a)[0] * (b)[0], \ + (a)[1] * (b)[1], \ + (a)[2] * (b)[2] - copy_v3_v3(location, intersect); +static bool test_vert_dist( + const float vco[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, + /* return args */ + float r_co[3]) +{ + const float vco_sc[3] = {V3_MUL_ELEM(vco, scale)}; + const float origin_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; - mul_m4_v3(obmat, location); + float depth, dist_sq; + dist_sq = dist_squared_to_ray_v3(origin_sc, dir_sc, vco_sc, &depth); - new_depth = len_v3v3(location, ray_start); + if (depth < ray_depth_range[0]) { + return false; + } - if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - new_dist = len_manhattan_v2v2(mval_fl, screen_loc); - } - else { - new_dist = TRANSFORM_DIST_MAX_PX; - } + if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { + *dist_to_ray_sq = dist_sq; - /* 10% threshold if edge is closer but a bit further - * this takes care of series of connected edges a bit slanted w.r.t the viewport - * otherwise, it would stick to the verts of the closest edge and not slide along merrily - * */ - if (new_dist <= *dist_px && new_depth < *ray_depth * 1.001f) { - float n1[3], n2[3]; + copy_v3_v3(r_co, vco); - *ray_depth = new_depth; - retval = true; + *ray_depth = depth; + return true; + } + return false; +} + +static bool test_edge_dist( + const float v1[3], const float v2[3], const float ray_co[3], const float ray_dir[3], + const float ray_depth_range[2], const float scale[3], + /* read/write args */ + float *ray_depth, float *dist_to_ray_sq, + /* return args */ + float r_co[3]) +{ + const float v1_sc[3] = {V3_MUL_ELEM(v1, scale)}; + const float v2_sc[3] = {V3_MUL_ELEM(v2, scale)}; + const float co_sc[3] = {V3_MUL_ELEM(ray_co, scale)}; + const float dir_sc[3] = {V3_MUL_ELEM(ray_dir, scale)}; + + float tmp_co[3], depth, dist_sq; + dist_sq = dist_squared_ray_to_seg_v3(co_sc, dir_sc, v1_sc, v2_sc, tmp_co, &depth); - sub_v3_v3v3(edge_loc, v1co, v2co); - sub_v3_v3v3(vec, intersect, v2co); + if (depth < ray_depth_range[0]) { + return false; + } - mul = dot_v3v3(vec, edge_loc) / dot_v3v3(edge_loc, edge_loc); + if ((dist_sq < *dist_to_ray_sq) && (depth < *ray_depth)) { + *dist_to_ray_sq = dist_sq; - if (r_no) { - normal_short_to_float_v3(n1, v1no); - normal_short_to_float_v3(n2, v2no); - interp_v3_v3v3(r_no, n2, n1, mul); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } + tmp_co[0] /= scale[0]; + tmp_co[1] /= scale[1]; + tmp_co[2] /= scale[2]; - copy_v3_v3(r_loc, location); + copy_v3_v3(r_co, tmp_co); - *dist_px = new_dist; - } + *ray_depth = depth; + return true; + } + return false; +} + +#undef V3_MUL_ELEM + +static bool test_projected_vert_dist( + PreDefProject *projectdefs, + const float co[3], const enum eViewProj view_proj, + const float mval[2], const float depth_range[2], + float r_co[3]) +{ + float depth; + float(*pmat)[4] = projectdefs->pmat; + if (view_proj == VIEW_PROJ_PERSP) { + depth = mul_project_m4_v3_zfac(pmat, co); + if (depth < depth_range[0] || depth > depth_range[1]) { + return false; } } - return retval; + float co2d[2] = { + (dot_m4_v3_row_x(pmat, co) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, co) + pmat[3][1]), + }; + + if (view_proj == VIEW_PROJ_PERSP) { + mul_v2_fl(co2d, 1 / depth); + } + + co2d[0] += 1.0f; + co2d[1] += 1.0f; + co2d[0] *= projectdefs->win_half[0]; + co2d[1] *= projectdefs->win_half[1]; + + const float dist_sq = len_squared_v2v2(mval, co2d); + if (dist_sq < projectdefs->dist_px_sq) { + copy_v3_v3(r_co, co); + projectdefs->dist_px_sq = dist_sq; + return true; + } + return false; } -static bool snapVertex( - ARegion *ar, const float vco[3], const float vno[3], - float obmat[4][4], float timat[3][3], const float mval_fl[2], float *dist_px, - const float ray_start[3], const float ray_start_local[3], const float ray_normal_local[3], float *ray_depth, - float r_loc[3], float r_no[3]) +static bool test_projected_edge_dist( + PreDefProject *projectdefs, + const float va[3], const float vb[3], const float ray_start[3], const float ray_normal[3], + const enum eViewProj view_proj, const float mval[2], const float depth_range[2], + float r_co[3]) { - bool retval = false; - float dvec[3]; - sub_v3_v3v3(dvec, vco, ray_start_local); + float tmp_co[3], depth; + dist_squared_ray_to_seg_v3(ray_start, ray_normal, va, vb, tmp_co, &depth); + return test_projected_vert_dist(projectdefs, tmp_co, view_proj, mval, depth_range, r_co); +} + +/** \} */ + + +/* -------------------------------------------------------------------- */ + +/** \Walk DFS + * \{ */ +typedef struct Object_Nearest2dPrecalc { + float ray_origin_local[3]; + float ray_direction_local[3]; + float ray_inv_dir[3]; + + PreDefProject projectdefs; + float mval[2]; + bool sign[3]; + bool r_axis_closest[3]; + float depth_range[2]; + + void *userdata; + int index; + float co[3]; + float no[3]; +} Object_Nearest2dPrecalc; + + +static void nearest2d_precalc( + Object_Nearest2dPrecalc *neasrest_precalc, const ARegion *ar, + const float dist_px, float obmat[4][4], + const float ray_origin_local[3], const float ray_direction_local[3], + const float mval[2], const float depth_range[2]) +{ + precalc_project(&neasrest_precalc->projectdefs, ar, dist_px, obmat); + copy_v3_v3(neasrest_precalc->ray_origin_local, ray_origin_local); + copy_v3_v3(neasrest_precalc->ray_direction_local, ray_direction_local); + copy_v2_v2(neasrest_precalc->mval, mval); + copy_v2_v2(neasrest_precalc->depth_range, depth_range); - if (dot_v3v3(ray_normal_local, dvec) > 0) { - float location[3]; - float new_depth; - float screen_loc[2]; - float new_dist; + for (int i = 0; i < 3; i++) { + neasrest_precalc->ray_inv_dir[i] = + (neasrest_precalc->ray_direction_local[i] != 0.0f) ? + (1.0f / neasrest_precalc->ray_direction_local[i]) : FLT_MAX; + neasrest_precalc->sign[i] = (neasrest_precalc->ray_inv_dir[i] < 0.0f); + neasrest_precalc->r_axis_closest[i] = true; + } +} - copy_v3_v3(location, vco); +static bool cb_walk_parent_snap_project(const BVHTreeAxisRange *bounds, void *user_data) +{ + Object_Nearest2dPrecalc *data = user_data; + float local_bvmin[3], local_bvmax[3]; + if (data->sign[0]) { + local_bvmin[0] = bounds[0].max; + local_bvmax[0] = bounds[0].min; + } + else { + local_bvmin[0] = bounds[0].min; + local_bvmax[0] = bounds[0].max; + } + if (data->sign[1]) { + local_bvmin[1] = bounds[1].max; + local_bvmax[1] = bounds[1].min; + } + else { + local_bvmin[1] = bounds[1].min; + local_bvmax[1] = bounds[1].max; + } + if (data->sign[2]) { + local_bvmin[2] = bounds[2].max; + local_bvmax[2] = bounds[2].min; + } + else { + local_bvmin[2] = bounds[2].min; + local_bvmax[2] = bounds[2].max; + } - mul_m4_v3(obmat, location); + const float tmin[3] = { + (local_bvmin[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmin[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmin[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + const float tmax[3] = { + (local_bvmax[0] - data->ray_origin_local[0]) * data->ray_inv_dir[0], + (local_bvmax[1] - data->ray_origin_local[1]) * data->ray_inv_dir[1], + (local_bvmax[2] - data->ray_origin_local[2]) * data->ray_inv_dir[2], + }; + float va[3], vb[3]; + float rtmin, rtmax; + int main_axis; + + if ((tmax[0] <= tmax[1]) && (tmax[0] <= tmax[2])) { + rtmax = tmax[0]; + va[0] = vb[0] = local_bvmax[0]; + main_axis = 3; + data->r_axis_closest[0] = data->sign[0]; + } + else if ((tmax[1] <= tmax[0]) && (tmax[1] <= tmax[2])) { + rtmax = tmax[1]; + va[1] = vb[1] = local_bvmax[1]; + main_axis = 2; + data->r_axis_closest[1] = data->sign[1]; + } + else { + rtmax = tmax[2]; + va[2] = vb[2] = local_bvmax[2]; + main_axis = 1; + data->r_axis_closest[2] = data->sign[2]; + } - new_depth = len_v3v3(location, ray_start); + if ((tmin[0] >= tmin[1]) && (tmin[0] >= tmin[2])) { + rtmin = tmin[0]; + va[0] = vb[0] = local_bvmin[0]; + main_axis -= 3; + data->r_axis_closest[0] = !data->sign[0]; + } + else if ((tmin[1] >= tmin[0]) && (tmin[1] >= tmin[2])) { + rtmin = tmin[1]; + va[1] = vb[1] = local_bvmin[1]; + main_axis -= 1; + data->r_axis_closest[1] = !data->sign[1]; + } + else { + rtmin = tmin[2]; + va[2] = vb[2] = local_bvmin[2]; + main_axis -= 2; + data->r_axis_closest[2] = !data->sign[2]; + } + if (main_axis < 0) { + main_axis += 3; + } - if (ED_view3d_project_float_global(ar, location, screen_loc, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - new_dist = len_manhattan_v2v2(mval_fl, screen_loc); + /* if rtmin < rtmax, ray intersect `AABB` */ + if (rtmin <= rtmax) { +#ifdef IGNORE_BEHIND_RAY + /* `if rtmax < depth_min`, the whole `AABB` is behind us */ + if (rtmax < min_depth) { + return fallback; + } +#endif + const float proj = rtmin * data->ray_direction_local[main_axis]; + data->r_axis_closest[main_axis] = (proj - va[main_axis]) < (vb[main_axis] - proj); + return true; + } +#ifdef IGNORE_BEHIND_RAY + /* `if rtmin < depth_min`, the whole `AABB` is behing us */ + else if (rtmin < min_depth) { + return fallback; + } +#endif + if (data->sign[main_axis]) { + va[main_axis] = local_bvmax[main_axis]; + vb[main_axis] = local_bvmin[main_axis]; + } + else { + va[main_axis] = local_bvmin[main_axis]; + vb[main_axis] = local_bvmax[main_axis]; + } + float scale = fabsf(local_bvmax[main_axis] - local_bvmin[main_axis]); + + float (*pmat)[4] = data->projectdefs.pmat; + float depth_a = mul_project_m4_v3_zfac(pmat, va); + float depth_b = depth_a + pmat[main_axis][3] * scale; + + float va2d[2] = { + (dot_m4_v3_row_x(pmat, va) + pmat[3][0]), + (dot_m4_v3_row_y(pmat, va) + pmat[3][1]), + }; + float vb2d[2] = { + (va2d[0] + pmat[main_axis][0] * scale) / depth_b, + (va2d[1] + pmat[main_axis][1] * scale) / depth_b, + }; + + va2d[0] /= depth_a; + va2d[1] /= depth_a; + + va2d[0] += 1.0f; + va2d[1] += 1.0f; + vb2d[0] += 1.0f; + vb2d[1] += 1.0f; + + va2d[0] *= data->projectdefs.win_half[0]; + va2d[1] *= data->projectdefs.win_half[1]; + vb2d[0] *= data->projectdefs.win_half[0]; + vb2d[1] *= data->projectdefs.win_half[1]; + + //float dvec[2], edge[2], rdist; + //sub_v2_v2v2(dvec, data->mval, va2d); + //sub_v2_v2v2(edge, vb2d, va2d); + float rdist; + short dvec[2] = {data->mval[0] - va2d[0], data->mval[1] - va2d[1]}; + short edge[2] = {vb2d[0] - va2d[0], vb2d[1] - va2d[1]}; + float lambda = dvec[0] * edge[0] + dvec[1] * edge[1]; + if (lambda != 0.0f) { + lambda /= edge[0] * edge[0] + edge[1] * edge[1]; + if (lambda <= 0.0f) { + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = true; + } + else if (lambda >= 1.0f) { + rdist = len_squared_v2v2(data->mval, vb2d); + data->r_axis_closest[main_axis] = false; } else { - new_dist = TRANSFORM_DIST_MAX_PX; + va2d[0] += edge[0] * lambda; + va2d[1] += edge[1] * lambda; + rdist = len_squared_v2v2(data->mval, va2d); + data->r_axis_closest[main_axis] = lambda < 0.5f; } + } + else { + rdist = len_squared_v2v2(data->mval, va2d); + } + return rdist < data->projectdefs.dist_px_sq; +} +static bool cb_walk_leaf_snap_vert(const BVHTreeAxisRange *bounds, int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + const float co[3] = { + (bounds[0].min + bounds[0].max) / 2, + (bounds[1].min + bounds[1].max) / 2, + (bounds[2].min + bounds[2].max) / 2, + }; + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_vert_dist( + &neasrest_precalc->projectdefs, co, VIEW_PROJ_PERSP, + neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + copy_vert_no(neasrest_precalc->userdata, index, neasrest_precalc->no); + neasrest_precalc->index = index; + } + return true; +} - if (new_dist <= *dist_px && new_depth < *ray_depth) { - *ray_depth = new_depth; - retval = true; +static bool cb_walk_leaf_snap_edge(const BVHTreeAxisRange *UNUSED(bounds), int index, void *userdata) +{ + struct Object_Nearest2dPrecalc *neasrest_precalc = userdata; + + const float *v_pair[2]; + get_edge_verts(neasrest_precalc->userdata, index, v_pair); + + /* Currently the `BLI_bvhtree_walk_dfs` is being used only in the perspective view mode (VIEW_PROJ_PERSP) + * It could be used in orthographic view mode too (VIEW_PROJ_ORTHO), + * but in this case the `BLI_bvhtree_find_nearest_to_ray` is more efficient.*/ + if (test_projected_edge_dist( + &neasrest_precalc->projectdefs, v_pair[0], v_pair[1], + neasrest_precalc->ray_origin_local, neasrest_precalc->ray_direction_local, + VIEW_PROJ_PERSP, neasrest_precalc->mval, neasrest_precalc->depth_range, + neasrest_precalc->co)) + { + sub_v3_v3v3(neasrest_precalc->no, v_pair[0], v_pair[1]); + neasrest_precalc->index = index; + } + return true; +} - copy_v3_v3(r_loc, location); +static bool cb_nearest_walk_order(const BVHTreeAxisRange *UNUSED(bounds), char axis, void *userdata) +{ + const bool *r_axis_closest = ((struct Object_Nearest2dPrecalc *)userdata)->r_axis_closest; + return r_axis_closest[axis]; +} - if (r_no) { - copy_v3_v3(r_no, vno); - mul_m3_v3(timat, r_no); - normalize_v3(r_no); - } +/** \} */ - *dist_px = new_dist; - } - } +/* -------------------------------------------------------------------- */ - return retval; -} +/** \name Internal Object Snapping API + * \{ */ static bool snapArmature( - ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, bArmature *arm, float obmat[4][4], + const short snap_to, const float origin[3], const float dir[3], + const float mval[2], const enum eViewProj view_proj, const float depth_range[2], + /* read/write args */ + float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_start_local[3], ray_normal_local[3]; bool retval = false; - invert_m4_m4(imat, obmat); + float ray_start_local[3], ray_normal_local[3]; + if (snap_to != SCE_SNAP_MODE_VERTEX) { + float imat[4][4]; + invert_m4_m4(imat, obmat); + + copy_v3_v3(ray_start_local, origin); + copy_v3_v3(ray_normal_local, dir); + mul_m4_v3(imat, ray_start_local); + mul_mat3_m4_v3(imat, ray_normal_local); + } - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); if (arm->edbo) { - EditBone *eBone; - - for (eBone = arm->edbo->first; eBone; eBone = eBone->next) { + for (EditBone *eBone = arm->edbo->first; eBone; eBone = eBone->next) { if (eBone->layer & arm->layer) { /* skip hidden or moving (selected) bones */ if ((eBone->flag & (BONE_HIDDEN_A | BONE_ROOTSEL | BONE_TIPSEL)) == 0) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= snapVertex( - ar, eBone->head, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); - retval |= snapVertex( - ar, eBone->tail, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, eBone->head, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, eBone->tail, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= snapEdge( - ar, eBone->head, NULL, eBone->tail, NULL, - obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, - ray_depth, r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, eBone->head, eBone->tail, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } @@ -407,11 +778,8 @@ static bool snapArmature( } } else if (ob->pose && ob->pose->chanbase.first) { - bPoseChannel *pchan; - Bone *bone; - - for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - bone = pchan->bone; + for (bPoseChannel *pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { + Bone *bone = pchan->bone; /* skip hidden bones */ if (bone && !(bone->flag & (BONE_HIDDEN_P | BONE_HIDDEN_PG))) { const float *head_vec = pchan->pose_head; @@ -419,58 +787,49 @@ static bool snapArmature( switch (snap_to) { case SCE_SNAP_MODE_VERTEX: - retval |= snapVertex( - ar, head_vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, - ray_depth, r_loc, NULL); - retval |= snapVertex( - ar, tail_vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, head_vec, view_proj, mval, depth_range, r_loc); + retval |= test_projected_vert_dist( + &projectdefs, tail_vec, view_proj, mval, depth_range, r_loc); break; case SCE_SNAP_MODE_EDGE: - retval |= snapEdge( - ar, head_vec, NULL, tail_vec, NULL, - obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, - ray_depth, r_loc, NULL); + retval |= test_projected_edge_dist( + &projectdefs, head_vec, tail_vec, ray_start_local, ray_normal_local, + view_proj, mval, depth_range, r_loc); break; } } } } - - return retval; + if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + mul_m4_v3(obmat, r_loc); + return true; + } + return false; } static bool snapCurve( - ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, Curve *cu, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], + /* read/write args */ + float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_start_local[3], ray_normal_local[3]; bool retval = false; - int u; - - Nurb *nu; /* only vertex snapping mode (eg control points and handles) supported for now) */ if (snap_to != SCE_SNAP_MODE_VERTEX) { return retval; } - invert_m4_m4(imat, obmat); - - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, obmat); - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); - - for (nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { - for (u = 0; u < nu->pntsu; u++) { + for (Nurb *nu = (ob->mode == OB_MODE_EDIT ? cu->editnurb->nurbs.first : cu->nurb.first); nu; nu = nu->next) { + for (int u = 0; u < nu->pntsu; u++) { switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { @@ -480,26 +839,20 @@ static bool snapCurve( if (nu->bezt[u].f2 & SELECT || nu->bezt[u].hide != 0) { break; } - retval |= snapVertex( - ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); /* don't snap if handle is selected (moving), or if it is aligning to a moving handle */ if (!(nu->bezt[u].f1 & SELECT) && !(nu->bezt[u].h1 & HD_ALIGN && nu->bezt[u].f3 & SELECT)) { - retval |= snapVertex( - ar, nu->bezt[u].vec[0], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[0], view_proj, mval, depth_range, r_loc); } if (!(nu->bezt[u].f3 & SELECT) && !(nu->bezt[u].h2 & HD_ALIGN && nu->bezt[u].f1 & SELECT)) { - retval |= snapVertex( - ar, nu->bezt[u].vec[2], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[2], view_proj, mval, depth_range, r_loc); } } else { @@ -507,26 +860,20 @@ static bool snapCurve( if (nu->bp[u].f1 & SELECT || nu->bp[u].hide != 0) { break; } - retval |= snapVertex( - ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } else { /* curve is not visible outside editmode if nurb length less than two */ if (nu->pntsu > 1) { if (nu->bezt) { - retval |= snapVertex( - ar, nu->bezt[u].vec[1], NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bezt[u].vec[1], view_proj, mval, depth_range, r_loc); } else { - retval |= snapVertex( - ar, nu->bp[u].vec, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + retval |= test_projected_vert_dist( + &projectdefs, nu->bp[u].vec, view_proj, mval, depth_range, r_loc); } } } @@ -537,41 +884,42 @@ static bool snapCurve( } } } - return retval; + if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + mul_m4_v3(obmat, r_loc); + return true; + } + return false; } /* may extend later (for now just snaps to empty center) */ static bool snapEmpty( - ARegion *ar, Object *ob, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const ARegion *ar, Object *ob, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], + /* read/write args */ + float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { - float imat[4][4]; - float ray_start_local[3], ray_normal_local[3]; bool retval = false; if (ob->transflag & OB_DUPLI) { return retval; } - /* for now only vertex supported */ - if (snap_to != SCE_SNAP_MODE_VERTEX) { - return retval; - } - - invert_m4_m4(imat, obmat); - - mul_v3_m4v3(ray_start_local, imat, ray_start); - mul_v3_mat3_m4v3(ray_normal_local, imat, ray_normal); + /* for now only vertex supported */ switch (snap_to) { case SCE_SNAP_MODE_VERTEX: { - const float zero_co[3] = {0.0f}; - retval |= snapVertex( - ar, zero_co, NULL, obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + PreDefProject projectdefs; + precalc_project(&projectdefs, ar, *dist_px, NULL); + float tmp_co[3]; + copy_v3_v3(tmp_co, obmat[3]); + if (test_projected_vert_dist(&projectdefs, tmp_co, view_proj, mval, depth_range, r_loc)) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + retval = true; + } break; } default: @@ -582,16 +930,23 @@ static bool snapEmpty( } static bool snapCamera( - ARegion *ar, Scene *scene, Object *object, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const SnapObjectContext *sctx, Object *object, float obmat[4][4], + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float depth_range[2], + /* read/write args */ + float *dist_px, + /* return args */ float r_loc[3], float *UNUSED(r_no)) { + Scene *scene = sctx->scene; + + PreDefProject projectdefs; + precalc_project(&projectdefs, sctx->v3d_data.ar, *dist_px, NULL); + float orig_camera_mat[4][4], orig_camera_imat[4][4], imat[4][4]; bool retval = false; MovieClip *clip = BKE_object_movieclip_get(scene, object, false); MovieTracking *tracking; - float ray_start_local[3], ray_normal_local[3]; if (clip == NULL) { return retval; @@ -622,9 +977,6 @@ static bool snapCamera( reconstructed_camera_imat[4][4]; float (*vertex_obmat)[4]; - copy_v3_v3(ray_start_local, ray_start); - copy_v3_v3(ray_normal_local, ray_normal); - if ((tracking_object->flag & TRACKING_OBJECT_CAMERA) == 0) { BKE_tracking_camera_get_reconstructed_interpolate(tracking, tracking_object, CFRA, reconstructed_camera_mat); @@ -641,21 +993,16 @@ static bool snapCamera( copy_v3_v3(bundle_pos, track->bundle_pos); if (tracking_object->flag & TRACKING_OBJECT_CAMERA) { - mul_m4_v3(orig_camera_imat, ray_start_local); - mul_mat3_m4_v3(orig_camera_imat, ray_normal_local); vertex_obmat = orig_camera_mat; } else { mul_m4_v3(reconstructed_camera_imat, bundle_pos); - mul_m4_v3(imat, ray_start_local); - mul_mat3_m4_v3(imat, ray_normal_local); vertex_obmat = obmat; } - retval |= snapVertex( - ar, bundle_pos, NULL, vertex_obmat, NULL, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, NULL); + mul_m4_v3(vertex_obmat, bundle_pos); + retval |= test_projected_vert_dist( + &projectdefs, bundle_pos, view_proj, mval, depth_range, r_loc); } } @@ -665,7 +1012,11 @@ static bool snapCamera( break; } - return retval; + if (retval) { + *dist_px = sqrtf(projectdefs.dist_px_sq); + return true; + } + return false; } static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) @@ -674,16 +1025,63 @@ static int dm_looptri_to_poly_index(DerivedMesh *dm, const MLoopTri *lt) return index_mp_to_orig ? index_mp_to_orig[lt->poly] : lt->poly; } +struct NearestDM_Data { + void *bvhdata; + const float *depth_range; + float *ray_depth; +}; + +static void test_vert_ray_dist_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + const struct BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *co = get_vert_co(data, index); + + if (test_vert_dist( + co, origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) + { + copy_vert_no(data, index, nearest->no); + nearest->index = index; + } +} + +static void test_edge_ray_dist_cb( + void *userdata, const float origin[3], const float dir[3], + const float scale[3], int index, BVHTreeNearest *nearest) +{ + struct NearestDM_Data *ndata = userdata; + BVHTreeFromMeshType *data = ndata->bvhdata; + + const float *v_pair[2]; + get_edge_verts(data, index, v_pair); + + if (test_edge_dist( + v_pair[0], v_pair[1], origin, dir, ndata->depth_range, + scale, ndata->ray_depth, &nearest->dist_sq, + nearest->co)) + { + sub_v3_v3v3(nearest->no, v_pair[0], v_pair[1]); + nearest->index = index; + } +} + static bool snapDerivedMesh( SnapObjectContext *sctx, - Object *ob, DerivedMesh *dm, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, bool do_bb, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, unsigned int ob_index, + Object *ob, DerivedMesh *dm, float obmat[4][4], const unsigned int ob_index, + const short snap_to, const float mval[2], const enum eViewProj view_proj, bool do_bb, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (snap_to == SCE_SNAP_MODE_FACE) { @@ -691,7 +1089,7 @@ static bool snapDerivedMesh( return retval; } } - if (snap_to == SCE_SNAP_MODE_EDGE) { + else if (snap_to == SCE_SNAP_MODE_EDGE) { if (dm->getNumEdges(dm) == 0) { return retval; } @@ -703,10 +1101,7 @@ static bool snapDerivedMesh( } { - const bool do_ray_start_correction = ( - ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && - (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); - bool need_ray_start_correction_init = do_ray_start_correction; + bool need_ray_start_correction_init = (snap_to == SCE_SNAP_MODE_FACE) && (view_proj == VIEW_PROJ_ORTHO); float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ @@ -772,6 +1167,9 @@ static bool snapDerivedMesh( int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: tree_index = 1; break; case SCE_SNAP_MODE_VERTEX: @@ -793,10 +1191,8 @@ static bool snapDerivedMesh( } } else { - if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); - } + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); } if (treedata && treedata->tree == NULL) { @@ -804,144 +1200,180 @@ static bool snapDerivedMesh( case SCE_SNAP_MODE_FACE: bvhtree_from_mesh_looptri(treedata, dm, 0.0f, 4, 6); break; + case SCE_SNAP_MODE_EDGE: + bvhtree_from_mesh_edges(treedata, dm, 0.0f, 2, 6); + break; case SCE_SNAP_MODE_VERTEX: bvhtree_from_mesh_verts(treedata, dm, 0.0f, 2, 6); break; } } - if (need_ray_start_correction_init) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. + if (!treedata || !treedata->tree) { + return retval; + } + + if (snap_to == SCE_SNAP_MODE_FACE) { + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (treedata && treedata->tree != NULL) { - BVHTreeNearest nearest; - nearest.index = -1; - nearest.dist_sq = FLT_MAX; - /* Compute and store result. */ - BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); - if (nearest.index != -1) { - len_diff = sqrtf(nearest.dist_sq); + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ + if (need_ray_start_correction_init) { + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ + BVHTreeNearest nearest; + nearest.index = -1; + nearest.dist_sq = FLT_MAX; + /* Compute and store result. */ + BLI_bvhtree_find_nearest( + treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata); + if (nearest.index != -1) { + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); + } } + float ray_org_local[3]; + + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far + * away ray_start values (as returned in case of ortho view3d), see T38358. + */ + len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0]); + local_depth -= len_diff; } - } - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - if (do_ray_start_correction) { - float ray_org_local[3]; + else { + len_diff = 0.0f; + } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - copy_v3_v3(ray_org_local, ray_origin); - mul_m4_v3(imat, ray_org_local); + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far - * away ray_start values (as returned in case of ortho view3d), see T38358. - */ - len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff - len_v3v3(ray_start_local, ray_org_local)); - local_depth -= len_diff; - } - else { - len_diff = 0.0f; - } + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); - switch (snap_to) { - case SCE_SNAP_MODE_FACE: - { - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index, - data.dm = dm; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; - } - else { - BVHTreeRayHit hit; - - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); + if (r_no) { copy_v3_v3(r_no, hit.no); - - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); mul_m3_v3(timat, r_no); normalize_v3(r_no); + } - retval = true; + retval = true; - if (r_index) { - *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); - } + if (r_index) { + *r_index = dm_looptri_to_poly_index(dm, &treedata->looptri[hit.index]); } } } - break; } - case SCE_SNAP_MODE_VERTEX: - { + } + else { + const ARegion *ar = sctx->v3d_data.ar; + + float ray_org_local[3]; + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_MESH}; + + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; + + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); + + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; + + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); + + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; + } + } + else { BVHTreeNearest nearest; nearest.index = -1; - nearest.dist_sq = local_depth * local_depth; - if (treedata->tree && - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_start_local, ray_normal_local, - &nearest, NULL, NULL) != -1) + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) { - const MVert *v = &treedata->vert[nearest.index]; - float vno[3]; - normal_short_to_float_v3(vno, v->no); - retval = snapVertex( - ar, v->co, vno, obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); - } - break; - } - case SCE_SNAP_MODE_EDGE: - { - MVert *verts = dm->getVertArray(dm); - MEdge *edges = dm->getEdgeArray(dm); - int totedge = dm->getNumEdges(dm); - - for (int i = 0; i < totedge; i++) { - MEdge *e = edges + i; - retval |= snapEdge( - ar, verts[e->v1].co, verts[e->v1].no, verts[e->v2].co, verts[e->v2].no, - obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); - } + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; - break; + retval = true; + } } } @@ -955,17 +1387,18 @@ static bool snapDerivedMesh( return retval; } - static bool snapEditMesh( SnapObjectContext *sctx, - Object *ob, BMEditMesh *em, float obmat[4][4], - const float mval[2], float *dist_px, const short snap_to, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, const unsigned int ob_index, + Object *ob, BMEditMesh *em, float obmat[4][4], const unsigned int ob_index, + const short snap_to, const float mval[2], const enum eViewProj view_proj, + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_px, + /* return args */ float r_loc[3], float r_no[3], int *r_index, ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; bool retval = false; if (snap_to == SCE_SNAP_MODE_FACE) { @@ -985,31 +1418,17 @@ static bool snapEditMesh( } { - const bool do_ray_start_correction = ( - ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX) && - (sctx->use_v3d && !((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp)); - float imat[4][4]; float timat[3][3]; /* transpose inverse matrix for normals */ - float ray_start_local[3], ray_normal_local[3]; - float local_scale, local_depth; + float ray_normal_local[3]; invert_m4_m4(imat, obmat); transpose_m3_m4(timat, imat); - copy_v3_v3(ray_start_local, ray_start); copy_v3_v3(ray_normal_local, ray_normal); - mul_m4_v3(imat, ray_start_local); mul_mat3_m4_v3(imat, ray_normal_local); - /* local scale in normal direction */ - local_scale = normalize_v3(ray_normal_local); - local_depth = *ray_depth; - if (local_depth != BVH_RAYCAST_DIST_MAX) { - local_depth *= local_scale; - } - SnapObjectData_EditMesh *sod = NULL; BVHTreeFromEditMesh *treedata = NULL, treedata_stack; @@ -1027,6 +1446,9 @@ static bool snapEditMesh( int tree_index = -1; switch (snap_to) { case SCE_SNAP_MODE_FACE: + tree_index = 2; + break; + case SCE_SNAP_MODE_EDGE: tree_index = 1; break; case SCE_SNAP_MODE_VERTEX: @@ -1041,10 +1463,8 @@ static bool snapEditMesh( } } else { - if (ELEM(snap_to, SCE_SNAP_MODE_FACE, SCE_SNAP_MODE_VERTEX)) { - treedata = &treedata_stack; - memset(treedata, 0, sizeof(*treedata)); - } + treedata = &treedata_stack; + memset(treedata, 0, sizeof(*treedata)); } if (treedata && treedata->tree == NULL) { @@ -1059,12 +1479,29 @@ static bool snapEditMesh( em->bm, looptri_mask, sctx->callbacks.edit_mesh.test_face_fn, sctx->callbacks.edit_mesh.user_data); } - bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6); + bvhtree_from_editmesh_looptri_ex(treedata, em, looptri_mask, looptri_num_active, 0.0f, 4, 6, NULL); if (looptri_mask) { MEM_freeN(looptri_mask); } break; } + case SCE_SNAP_MODE_EDGE: + { + BLI_bitmap *edges_mask = NULL; + int edges_num_active = -1; + if (sctx->callbacks.edit_mesh.test_edge_fn) { + edges_mask = BLI_BITMAP_NEW(em->bm->totedge, __func__); + edges_num_active = BM_iter_mesh_bitmap_from_filter( + BM_EDGES_OF_MESH, em->bm, edges_mask, + (bool (*)(BMElem *, void *))sctx->callbacks.edit_mesh.test_edge_fn, + sctx->callbacks.edit_mesh.user_data); + } + bvhtree_from_editmesh_edges_ex(treedata, em, edges_mask, edges_num_active, 0.0f, 2, 6); + if (edges_mask) { + MEM_freeN(edges_mask); + } + break; + } case SCE_SNAP_MODE_VERTEX: { BLI_bitmap *verts_mask = NULL; @@ -1085,139 +1522,179 @@ static bool snapEditMesh( } } - /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already - * been *inside* boundbox, leading to snap failures (see T38409). - * Note also ar might be null (see T38435), in this case we assume ray_start is ok! - */ - float len_diff = 0.0f; - if (do_ray_start_correction) { - /* We *need* a reasonably valid len_diff in this case. - * Use BHVTree to find the closest face from ray_start_local. + if (!treedata || !treedata->tree) { + return retval; + } + + if (snap_to == SCE_SNAP_MODE_FACE) { + float ray_start_local[3]; + copy_v3_v3(ray_start_local, ray_start); + mul_m4_v3(imat, ray_start_local); + + /* local scale in normal direction */ + float local_scale = normalize_v3(ray_normal_local); + float local_depth = *ray_depth; + if (local_depth != BVH_RAYCAST_DIST_MAX) { + local_depth *= local_scale; + } + + /* Only use closer ray_start in case of ortho view! In perspective one, ray_start may already + * been *inside* boundbox, leading to snap failures (see T38409). + * Note also ar might be null (see T38435), in this case we assume ray_start is ok! */ - if (treedata && treedata->tree != NULL) { + float len_diff = 0.0f; + if (view_proj == VIEW_PROJ_ORTHO) { /* do_ray_start_correction */ + /* We *need* a reasonably valid len_diff in this case. + * Use BHVTree to find the closest face from ray_start_local. + */ BVHTreeNearest nearest; nearest.index = -1; nearest.dist_sq = FLT_MAX; /* Compute and store result. */ if (BLI_bvhtree_find_nearest( - treedata->tree, ray_start_local, &nearest, treedata->nearest_callback, treedata) != -1) + treedata->tree, ray_start_local, &nearest, NULL, NULL) != -1) { - len_diff = sqrtf(nearest.dist_sq); + float dvec[3]; + sub_v3_v3v3(dvec, nearest.co, ray_start_local); + len_diff = dot_v3v3(dvec, ray_normal_local); float ray_org_local[3]; copy_v3_v3(ray_org_local, ray_origin); mul_m4_v3(imat, ray_org_local); - /* We pass a temp ray_start, set from object's boundbox, to avoid precision issues with very far - * away ray_start values (as returned in case of ortho view3d), see T38358. - */ + /* We pass a temp ray_start, set from object's boundbox, + * to avoid precision issues with very far away ray_start values + * (as returned in case of ortho view3d), see T38358. + */ len_diff -= local_scale; /* make temp start point a bit away from bbox hit point. */ - madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, - len_diff - len_v3v3(ray_start_local, ray_org_local)); + madd_v3_v3v3fl(ray_start_local, ray_org_local, ray_normal_local, len_diff + depth_range[0]); local_depth -= len_diff; } } - } + if (r_hit_list) { + struct RayCastAll_Data data; + + data.bvhdata = treedata; + data.raycast_callback = treedata->raycast_callback; + data.obmat = obmat; + data.timat = timat; + data.len_diff = len_diff; + data.local_scale = local_scale; + data.ob = ob; + data.ob_uuid = ob_index; + data.hit_list = r_hit_list; + data.retval = retval; + + BLI_bvhtree_ray_cast_all( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + *ray_depth, raycast_all_cb, &data); + + retval = data.retval; + } + else { + BVHTreeRayHit hit = {.index = -1, .dist = local_depth}; - switch (snap_to) { - case SCE_SNAP_MODE_FACE: - { - if (r_hit_list) { - struct RayCastAll_Data data; - - data.bvhdata = treedata; - data.raycast_callback = treedata->raycast_callback; - data.obmat = obmat; - data.timat = timat; - data.len_diff = len_diff; - data.local_scale = local_scale; - data.ob = ob; - data.ob_uuid = ob_index; - data.dm = NULL; - data.hit_list = r_hit_list; - data.retval = retval; - - BLI_bvhtree_ray_cast_all( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - *ray_depth, raycast_all_cb, &data); - - retval = data.retval; - } - else { - BVHTreeRayHit hit; - - hit.index = -1; - hit.dist = local_depth; - - if (treedata->tree && - BLI_bvhtree_ray_cast( - treedata->tree, ray_start_local, ray_normal_local, 0.0f, - &hit, treedata->raycast_callback, treedata) != -1) - { - hit.dist += len_diff; - hit.dist /= local_scale; - if (hit.dist <= *ray_depth) { - *ray_depth = hit.dist; - copy_v3_v3(r_loc, hit.co); - copy_v3_v3(r_no, hit.no); + if (BLI_bvhtree_ray_cast( + treedata->tree, ray_start_local, ray_normal_local, 0.0f, + &hit, treedata->raycast_callback, treedata) != -1) + { + hit.dist += len_diff; + hit.dist /= local_scale; + if (hit.dist <= *ray_depth) { + *ray_depth = hit.dist; + copy_v3_v3(r_loc, hit.co); + + /* back to worldspace */ + mul_m4_v3(obmat, r_loc); - /* back to worldspace */ - mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, hit.no); mul_m3_v3(timat, r_no); normalize_v3(r_no); + } - retval = true; + retval = true; - if (r_index) { - *r_index = hit.index; - } + if (r_index) { + *r_index = hit.index; } } } - break; } - case SCE_SNAP_MODE_VERTEX: - { + } + else { + const ARegion *ar = sctx->v3d_data.ar; + + float ray_org_local[3]; + copy_v3_v3(ray_org_local, ray_origin); + mul_m4_v3(imat, ray_org_local); + + BVHTreeFromMeshType treedata_type = {.userdata = treedata, .type = SNAP_EDIT_MESH}; + + if (view_proj == VIEW_PROJ_PERSP) { + Object_Nearest2dPrecalc neasrest_precalc; + neasrest_precalc.userdata = &treedata_type; + neasrest_precalc.index = -1; + + nearest2d_precalc(&neasrest_precalc, ar, *dist_px, obmat, + ray_org_local, ray_normal_local, mval, depth_range); + + BVHTree_WalkLeafCallback cb_walk_leaf = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + cb_walk_leaf_snap_vert : cb_walk_leaf_snap_edge; + + BLI_bvhtree_walk_dfs( + treedata->tree, + cb_walk_parent_snap_project, cb_walk_leaf, cb_nearest_walk_order, &neasrest_precalc); + + if (neasrest_precalc.index != -1) { + copy_v3_v3(r_loc, neasrest_precalc.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, neasrest_precalc.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); + } + *dist_px = sqrtf(neasrest_precalc.projectdefs.dist_px_sq); + + retval = true; + } + } + else { BVHTreeNearest nearest; nearest.index = -1; - nearest.dist_sq = local_depth * local_depth; - if (treedata->tree && - BLI_bvhtree_find_nearest_to_ray( - treedata->tree, ray_start_local, ray_normal_local, - &nearest, NULL, NULL) != -1) + float dist_3d = dist_px_to_dist3d_or_tangent(ar, *dist_px); + nearest.dist_sq = SQUARE(dist_3d); + + + float ob_scale[3]; + mat4_to_size(ob_scale, obmat); + + struct NearestDM_Data userdata; + userdata.bvhdata = &treedata_type; + userdata.depth_range = depth_range; + userdata.ray_depth = ray_depth; + + BVHTree_NearestToRayCallback cb_test_ray_dist = + (snap_to == SCE_SNAP_MODE_VERTEX) ? + test_vert_ray_dist_cb : test_edge_ray_dist_cb; + + if (BLI_bvhtree_find_nearest_to_ray( + treedata->tree, ray_org_local, ray_normal_local, + false, ob_scale, &nearest, cb_test_ray_dist, &userdata) != -1) { - const BMVert *v = BM_vert_at_index(em->bm, nearest.index); - retval = snapVertex( - ar, v->co, v->no, obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); - } - break; - } - case SCE_SNAP_MODE_EDGE: - { - BM_mesh_elem_table_ensure(em->bm, BM_EDGE); - int totedge = em->bm->totedge; - for (int i = 0; i < totedge; i++) { - BMEdge *eed = BM_edge_at_index(em->bm, i); - - if (!BM_elem_flag_test(eed, BM_ELEM_HIDDEN) && - !BM_elem_flag_test(eed->v1, BM_ELEM_SELECT) && - !BM_elem_flag_test(eed->v2, BM_ELEM_SELECT)) - { - short v1no[3], v2no[3]; - normal_float_to_short_v3(v1no, eed->v1->no); - normal_float_to_short_v3(v2no, eed->v2->no); - retval |= snapEdge( - ar, eed->v1->co, v1no, eed->v2->co, v2no, - obmat, timat, mval, dist_px, - ray_start, ray_start_local, ray_normal_local, ray_depth, - r_loc, r_no); + copy_v3_v3(r_loc, nearest.co); + mul_m4_v3(obmat, r_loc); + if (r_no) { + copy_v3_v3(r_no, nearest.no); + mul_m3_v3(timat, r_no); + normalize_v3(r_no); } - } + *dist_px *= sqrtf(nearest.dist_sq) / dist_3d; - break; + retval = true; + } } } @@ -1231,18 +1708,30 @@ static bool snapEditMesh( return retval; } +/** + * \param use_obedit: Uses the coordinates of BMesh (if any) to do the snapping; + * + * \note Duplicate args here are documented at #snapObjectsRay + */ static bool snapObject( SnapObjectContext *sctx, - Object *ob, float obmat[4][4], bool use_obedit, const short snap_to, - const float mval[2], float *dist_px, const unsigned int ob_index, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], - float *ray_depth, + Object *ob, float obmat[4][4], const unsigned int ob_index, + bool use_obedit, const short snap_to, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { - ARegion *ar = sctx->v3d_data.ar; + const enum eViewProj view_proj = + ((sctx->use_v3d == false) || (mval == NULL)) ? VIEW_PROJ_NONE : + (((RegionView3D *)sctx->v3d_data.ar->regiondata)->is_persp ? VIEW_PROJ_PERSP : VIEW_PROJ_ORTHO); + + const ARegion *ar = sctx->v3d_data.ar; + bool retval = false; if (ob->type == OB_MESH) { @@ -1251,9 +1740,10 @@ static bool snapObject( if (use_obedit) { em = BKE_editmesh_from_object(ob); retval = snapEditMesh( - sctx, ob, em, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_origin, - ray_depth, ob_index, + sctx, ob, em, obmat, ob_index, + snap_to, mval, view_proj, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_hit_list); } @@ -1269,37 +1759,44 @@ static bool snapObject( dm = mesh_get_derived_final(sctx->scene, ob, CD_MASK_BAREMESH); } retval = snapDerivedMesh( - sctx, ob, dm, obmat, mval, dist_px, snap_to, true, - ray_start, ray_normal, ray_origin, - ray_depth, ob_index, - r_loc, r_no, r_index, r_hit_list); + sctx, ob, dm, obmat, ob_index, + snap_to, mval, view_proj, true, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, + r_loc, r_no, + r_index, r_hit_list); dm->release(dm); } } - else if (ob->type == OB_ARMATURE) { - retval = snapArmature( - ar, ob, ob->data, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no); - } - else if (ob->type == OB_CURVE) { - retval = snapCurve( - ar, ob, ob->data, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no); - } - else if (ob->type == OB_EMPTY) { - retval = snapEmpty( - ar, ob, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no); - } - else if (ob->type == OB_CAMERA) { - retval = snapCamera( - ar, sctx->scene, ob, obmat, mval, dist_px, snap_to, - ray_start, ray_normal, ray_depth, - r_loc, r_no); + else if (snap_to != SCE_SNAP_MODE_FACE) { + if (ob->type == OB_ARMATURE) { + retval = snapArmature( + ar, ob, ob->data, obmat, snap_to, ray_origin, ray_normal, + mval, view_proj, depth_range, dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CURVE) { + retval = snapCurve( + ar, ob, ob->data, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_EMPTY) { + retval = snapEmpty( + ar, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } + else if (ob->type == OB_CAMERA) { + retval = snapCamera( + sctx, ob, obmat, snap_to, mval, view_proj, + depth_range, + dist_px, + r_loc, r_no); + } } if (retval) { @@ -1312,18 +1809,59 @@ static bool snapObject( return retval; } +/** + * Main Snapping Function + * ====================== + * + * Walks through all objects in the scene to find the closest snap element ray. + * + * \param sctx: Snap context to store data. + * \param snap_to: Element to snap, Vertice, Edge or Face. + * Currently only works one at a time, but can eventually operate as flag. + * + * \param snap_select: from enum SnapSelect. + * + * \param use_object_edit_cage: Uses the coordinates of BMesh (if any) to do the snapping. + * \param mval: Mouse coords. + * When NULL, ray-casting is handled without any projection matrix correction. + * \param ray_origin: ray_start before being moved toward the ray_normal at the distance from vew3d clip_min. + * \param ray_start: ray_origin moved for the start clipping plane (clip_min). + * \param ray_normal: Unit length direction of the ray. + * \param depth_range: distances of clipe plane min and clip plane max; + * + * Read/Write Args + * --------------- + * + * \param ray_depth: maximum depth allowed for r_co, elements deeper than this value will be ignored. + * \param dist_px: Maximum threshold distance (in pixels). + * + * Output Args + * ----------- + * + * \param r_loc: Hit location. + * \param r_no: Hit normal (optional). + * \param r_index: Hit index or -1 when no valid index is found. + * (currently only set to the polygon index when when using ``snap_to == SCE_SNAP_MODE_FACE``). + * \param r_ob: Hit object. + * \param r_obmat: Object matrix (may not be #Object.obmat with dupli-instances). + * \param r_hit_list: List of #SnapObjectHitDepth (caller must free). + * + */ static bool snapObjectsRay( SnapObjectContext *sctx, const unsigned short snap_to, const SnapSelect snap_select, - const bool use_object_edit_cage, - const float mval[2], float *dist_px, - const float ray_start[3], const float ray_normal[3], const float ray_origin[3], float *ray_depth, + const bool use_object_edit_cage, const float mval[2], + const float ray_origin[3], const float ray_start[3], const float ray_normal[3], + const float depth_range[2], + /* read/write args */ + float *ray_depth, float *dist_px, /* return args */ float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4], ListBase *r_hit_list) { bool retval = false; + unsigned int ob_index = 0; Object *obedit = use_object_edit_cage ? sctx->scene->obedit : NULL; @@ -1337,9 +1875,10 @@ static bool snapObjectsRay( Object *ob = base_act->object; retval |= snapObject( - sctx, ob, ob->obmat, false, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, ob, ob->obmat, ob_index++, + false, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1372,9 +1911,10 @@ static bool snapObjectsRay( Object *dupli_snap = (use_obedit_dupli) ? obedit : dupli_ob->ob; retval |= snapObject( - sctx, dupli_snap, dupli_ob->mat, use_obedit_dupli, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, dupli_snap, dupli_ob->mat, ob_index++, + use_obedit_dupli, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } @@ -1385,9 +1925,10 @@ static bool snapObjectsRay( Object *ob_snap = use_obedit ? obedit : ob; retval |= snapObject( - sctx, ob_snap, ob->obmat, use_obedit, snap_to, - mval, dist_px, ob_index++, - ray_start, ray_normal, ray_origin, ray_depth, + sctx, ob_snap, ob->obmat, ob_index++, + use_obedit, snap_to, mval, + ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, r_ob, r_obmat, r_hit_list); } } @@ -1419,7 +1960,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( SnapObjectContext *ED_transform_snap_object_context_create_view3d( Main *bmain, Scene *scene, int flag, /* extra args for view3d */ - ARegion *ar, View3D *v3d) + const ARegion *ar, const View3D *v3d) { SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, flag); @@ -1489,15 +2030,17 @@ bool ED_transform_snap_object_project_ray_ex( SnapObjectContext *sctx, const unsigned short snap_to, const struct SnapObjectParams *params, - const float ray_start[3], const float ray_normal[3], float *ray_depth, + const float ray_start[3], const float ray_normal[3], + float *ray_depth, float r_loc[3], float r_no[3], int *r_index, Object **r_ob, float r_obmat[4][4]) { + const float depth_range[2] = {0.0f, FLT_MAX}; return snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - NULL, NULL, - ray_start, ray_normal, ray_start, ray_depth, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + ray_depth, NULL, r_loc, r_no, r_index, r_ob, r_obmat, NULL); } @@ -1516,6 +2059,7 @@ bool ED_transform_snap_object_project_ray_all( float ray_depth, bool sort, ListBase *r_hit_list) { + const float depth_range[2] = {0.0f, FLT_MAX}; if (ray_depth == -1.0f) { ray_depth = BVH_RAYCAST_DIST_MAX; } @@ -1526,9 +2070,9 @@ bool ED_transform_snap_object_project_ray_all( bool retval = snapObjectsRay( sctx, - snap_to, params->snap_select, params->use_object_edit_cage, - NULL, NULL, - ray_start, ray_normal, ray_start, &ray_depth, + snap_to, params->snap_select, params->use_object_edit_cage, NULL, + ray_start, ray_start, ray_normal, depth_range, + &ray_depth, NULL, NULL, NULL, NULL, NULL, NULL, r_hit_list); @@ -1583,11 +2127,6 @@ bool ED_transform_snap_object_project_ray( ray_depth = &ray_depth_fallback; } - float no_fallback[3]; - if (r_no == NULL) { - r_no = no_fallback; - } - return transform_snap_context_project_ray_impl( sctx, params, @@ -1606,11 +2145,6 @@ static bool transform_snap_context_project_view3d_mixed_impl( float ray_depth = BVH_RAYCAST_DIST_MAX; bool is_hit = false; - float r_no_dummy[3]; - if (r_no == NULL) { - r_no = r_no_dummy; - } - const int elem_type[3] = {SCE_SNAP_MODE_VERTEX, SCE_SNAP_MODE_EDGE, SCE_SNAP_MODE_FACE}; BLI_assert(snap_to_flag != 0); @@ -1642,7 +2176,7 @@ static bool transform_snap_context_project_view3d_mixed_impl( * Given a 2D region value, snap to vert/edge/face. * * \param sctx: Snap context. - * \param mval: Screenspace coordinate. + * \param mval_fl: Screenspace coordinate. * \param dist_px: Maximum distance to snap (in pixels). * \param use_depth: Snap to the closest element, use when using more than one snap type. * \param r_co: hit location. @@ -1672,7 +2206,24 @@ bool ED_transform_snap_object_project_view3d_ex( float *ray_depth, float r_loc[3], float r_no[3], int *r_index) { - float ray_start[3], ray_normal[3], ray_orgigin[3]; + float ray_origin[3], ray_start[3], ray_normal[3], depth_range[2], ray_end[3]; + + const ARegion *ar = sctx->v3d_data.ar; + const RegionView3D *rv3d = ar->regiondata; + + ED_view3d_win_to_origin(ar, mval, ray_origin); + ED_view3d_win_to_vector(ar, mval, ray_normal); + + ED_view3d_clip_range_get( + sctx->v3d_data.v3d, sctx->v3d_data.ar->regiondata, + &depth_range[0], &depth_range[1], false); + + madd_v3_v3v3fl(ray_start, ray_origin, ray_normal, depth_range[0]); + madd_v3_v3v3fl(ray_end, ray_origin, ray_normal, depth_range[1]); + + if (!ED_view3d_clip_segment(rv3d, ray_start, ray_end)) { + return false; + } float ray_depth_fallback; if (ray_depth == NULL) { @@ -1680,18 +2231,11 @@ bool ED_transform_snap_object_project_view3d_ex( ray_depth = &ray_depth_fallback; } - if (!ED_view3d_win_to_ray_ex( - sctx->v3d_data.ar, sctx->v3d_data.v3d, - mval, ray_orgigin, ray_normal, ray_start, true)) - { - return false; - } - return snapObjectsRay( sctx, snap_to, params->snap_select, params->use_object_edit_cage, - mval, dist_px, - ray_start, ray_normal, ray_orgigin, ray_depth, + mval, ray_origin, ray_start, ray_normal, depth_range, + ray_depth, dist_px, r_loc, r_no, r_index, NULL, NULL, NULL); } diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 1f4ce926f16..1f1a778cac7 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -57,6 +57,7 @@ #include "BKE_multires.h" #include "BKE_packedFile.h" #include "BKE_paint.h" +#include "BKE_screen.h" #include "ED_armature.h" #include "ED_buttons.h" @@ -104,7 +105,7 @@ void ED_editors_init(bContext *C) ob->mode = OB_MODE_OBJECT; data = ob->data; - if (ob == obact && !ob->id.lib && !(data && data->lib)) + if (ob == obact && !ID_IS_LINKED_DATABLOCK(ob) && !(data && ID_IS_LINKED_DATABLOCK(data))) ED_object_toggle_modes(C, mode); } } @@ -326,22 +327,14 @@ void ED_region_draw_mouse_line_cb(const bContext *C, ARegion *ar, void *arg_info /** * Use to free ID references within runtime data (stored outside of DNA) * - * \note Typically notifiers take care of this, - * but there are times we have to free references immediately, see: T44376 + * \param new_id may be NULL to unlink \a old_id. */ -void ED_spacedata_id_unref(struct SpaceLink *sl, const ID *id) +void ED_spacedata_id_remap(struct ScrArea *sa, struct SpaceLink *sl, ID *old_id, ID *new_id) { + SpaceType *st = BKE_spacetype_from_id(sl->spacetype); - switch (sl->spacetype) { - case SPACE_OUTLINER: - ED_outliner_id_unref((SpaceOops *)sl, id); - break; - case SPACE_BUTS: - ED_buttons_id_unref((SpaceButs *)sl, id); - break; - case SPACE_NODE: - ED_node_id_unref((SpaceNode *)sl, id); - break; + if (st && st->id_remap) { + st->id_remap(sa, sl, old_id, new_id); } } diff --git a/source/blender/editors/uvedit/uvedit_parametrizer.c b/source/blender/editors/uvedit/uvedit_parametrizer.c index 59f9cd16908..bdfff123aa4 100644 --- a/source/blender/editors/uvedit/uvedit_parametrizer.c +++ b/source/blender/editors/uvedit/uvedit_parametrizer.c @@ -740,6 +740,16 @@ static PVert *p_vert_add(PHandle *handle, PHashKey key, const float co[3], PEdge { PVert *v = (PVert *)BLI_memarena_alloc(handle->arena, sizeof(*v)); copy_v3_v3(v->co, co); + + /* Sanity check, a single nan/inf point causes the entire result to be invalid. + * Note that values within the calculation may _become_ non-finite, + * so the rest of the code still needs to take this possibility into account. */ + for (int i = 0; i < 3; i++) { + if (UNLIKELY(!isfinite(v->co[i]))) { + v->co[i] = 0.0f; + } + } + v->u.key = key; v->edge = e; v->flag = 0; @@ -2794,7 +2804,7 @@ static PBool p_chart_abf_solve(PChart *chart) static void p_chart_pin_positions(PChart *chart, PVert **pin1, PVert **pin2) { - if (pin1 == pin2) { + if (!*pin1 || !*pin2 || *pin1 == *pin2) { /* degenerate case */ PFace *f = chart->faces; *pin1 = f->edge->vert; @@ -3040,8 +3050,10 @@ static void p_chart_lscm_begin(PChart *chart, PBool live, PBool abf) p_chart_boundaries(chart, NULL, &outer); - if (!p_chart_symmetry_pins(chart, outer, &pin1, &pin2)) + /* outer can be NULL with non-finite coords. */ + if (!(outer && p_chart_symmetry_pins(chart, outer, &pin1, &pin2))) { p_chart_extrema_verts(chart, &pin1, &pin2); + } chart->u.lscm.pin1 = pin1; chart->u.lscm.pin2 = pin2; diff --git a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp index 5c361de8d8d..f63cf771120 100644 --- a/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp +++ b/source/blender/freestyle/intern/blender_interface/BlenderStrokeRenderer.cpp @@ -907,7 +907,7 @@ void BlenderStrokeRenderer::GenerateStrokeMesh(StrokeGroup *group, bool hasTex) material_index++; } // loop over strokes - test_object_materials(freestyle_bmain, (ID *)mesh); + test_object_materials(object_mesh, (ID *)mesh); #if 0 // XXX BLI_assert(mesh->totvert == vertex_index); diff --git a/source/blender/freestyle/intern/geometry/normal_cycle.h b/source/blender/freestyle/intern/geometry/normal_cycle.h index 53bc23c6eb3..8d06865e31b 100644 --- a/source/blender/freestyle/intern/geometry/normal_cycle.h +++ b/source/blender/freestyle/intern/geometry/normal_cycle.h @@ -63,13 +63,13 @@ template <class T> inline void ogf_swap(T& x, T& y) //_________________________________________________________ /** -* NormalCycle evaluates the curvature tensor in function -* of a set of dihedral angles and associated vectors. -* Reference: -* Restricted Delaunay Triangulation and Normal Cycle, -* D. Cohen-Steiner and J.M. Morvan, -* SOCG 2003 -*/ + * NormalCycle evaluates the curvature tensor in function + * of a set of dihedral angles and associated vectors. + * Reference: + * Restricted Delaunay Triangulation and Normal Cycle, + * D. Cohen-Steiner and J.M. Morvan, + * SOCG 2003 + */ class NormalCycle { public: NormalCycle(); diff --git a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp index 3f29d9899e8..9efbe6b53be 100644 --- a/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp +++ b/source/blender/freestyle/intern/python/BPy_FrsNoise.cpp @@ -111,7 +111,7 @@ static PyObject *FrsNoise_drand(BPy_FrsNoise * /*self*/, PyObject *args, PyObjec PyErr_SetString(PyExc_TypeError, "optional argument 1 must be of type int"); return NULL; } - if (seed){ + if (seed) { RandGen::srand48(seed); } return PyFloat_FromDouble(RandGen::drand48()); diff --git a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp index e35076ec7fe..96a8bee9394 100644 --- a/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp +++ b/source/blender/freestyle/intern/python/Iterator/BPy_StrokeVertexIterator.cpp @@ -121,7 +121,7 @@ static PyObject *StrokeVertexIterator_iternext(BPy_StrokeVertexIterator *self) return NULL; } /* If at the start of the iterator, only return the object - * and don't increment, to keep for-loops in sync */ + * and don't increment, to keep for-loops in sync */ else if (self->at_start) { self->at_start = false; } diff --git a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h index a00f983bbcf..220c966a5d0 100644 --- a/source/blender/freestyle/intern/scene_graph/FrsMaterial.h +++ b/source/blender/freestyle/intern/scene_graph/FrsMaterial.h @@ -298,9 +298,9 @@ public: inline void setShininess(const float s); /*! Sets the line color priority. - * \param priority - * Priority - */ + * \param priority + * Priority + */ inline void setPriority(const int priority); /* operators */ diff --git a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h index 4b079df5632..8dc93d84201 100644 --- a/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h +++ b/source/blender/freestyle/intern/scene_graph/NodeSceneRenderLayer.h @@ -52,16 +52,6 @@ public: return _SceneRenderLayer; } - inline void setSceneRenderLayer(Scene& scene) - { - _Scene = scene; - } - - inline void setSceneRenderLayer(SceneRenderLayer& srl) - { - _SceneRenderLayer = srl; - } - /*! Accept the corresponding visitor */ virtual void accept(SceneVisitor& v); diff --git a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h index f650e32b278..c65f121e9ba 100644 --- a/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h +++ b/source/blender/freestyle/intern/stroke/AdvancedPredicates1D.h @@ -46,8 +46,8 @@ namespace Predicates1D { // DensityLowerThanUP1D /*! Returns true if the density evaluated for the -* Interface1D is less than a user-defined density value. -*/ + * Interface1D is less than a user-defined density value. + */ class DensityLowerThanUP1D : public UnaryPredicate1D { public: diff --git a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h index e3842f45eb0..cc935a7e311 100644 --- a/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h +++ b/source/blender/freestyle/intern/stroke/BasicStrokeShaders.h @@ -619,9 +619,9 @@ public: } /*! Builds the shader. - * \param nodetree - * A node tree (of new shading nodes) to define textures. - */ + * \param nodetree + * A node tree (of new shading nodes) to define textures. + */ BlenderTextureShader(bNodeTree *nodetree) : StrokeShader() { _nodeTree = nodetree; diff --git a/source/blender/freestyle/intern/stroke/Stroke.h b/source/blender/freestyle/intern/stroke/Stroke.h index 5f0b4eab309..db96a27e073 100644 --- a/source/blender/freestyle/intern/stroke/Stroke.h +++ b/source/blender/freestyle/intern/stroke/Stroke.h @@ -605,15 +605,15 @@ public: */ int Resample(float iSampling); - /*! Removes all vertices from the Stroke. - */ - void RemoveAllVertices(); + /*! Removes all vertices from the Stroke. + */ + void RemoveAllVertices(); /*! Removes the stroke vertex iVertex - * from the stroke. - * The length and curvilinear abscissa are updated - * consequently. - */ + * from the stroke. + * The length and curvilinear abscissa are updated + * consequently. + */ void RemoveVertex(StrokeVertex *iVertex); /*! Inserts the stroke vertex iVertex in the stroke before next. diff --git a/source/blender/freestyle/intern/system/PythonInterpreter.h b/source/blender/freestyle/intern/system/PythonInterpreter.h index 5403ec6b13b..0e08af1bac8 100644 --- a/source/blender/freestyle/intern/system/PythonInterpreter.h +++ b/source/blender/freestyle/intern/system/PythonInterpreter.h @@ -84,8 +84,7 @@ public: Text *text = BKE_text_load(&_freestyle_bmain, fn, G.main->name); if (text) { ok = BPY_execute_text(_context, text, reports, false); - BKE_text_unlink(&_freestyle_bmain, text); - BKE_libblock_free(&_freestyle_bmain, text); + BKE_libblock_delete(&_freestyle_bmain, text); } else { BKE_reportf(reports, RPT_ERROR, "Cannot open file: %s", fn); diff --git a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp index 85c6390cb9e..a97e60d5f60 100644 --- a/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp +++ b/source/blender/freestyle/intern/view_map/FEdgeXDetector.cpp @@ -640,7 +640,7 @@ void FEdgeXDetector::postProcessSuggestiveContourFace(WXFace *iFace) normal_vec = wxf->GetVertexNormal(v); // FIXME: what about e1 ^ e2 ? radial_normal_vec = er_vec ^ normal_vec; - // Test wether the radial plan intersects with the edge at the opposite of v. + // Test whether the radial plan intersects with the edge at the opposite of v. res = GeomUtils::intersectRayPlane(opposite_vertex_a->GetVertex(), opposite_edge->GetVec(), radial_normal_vec, -(v_vec * radial_normal_vec), t, 1.0e-06); diff --git a/source/blender/freestyle/intern/view_map/Functions0D.h b/source/blender/freestyle/intern/view_map/Functions0D.h index 647a3a530c6..f0009fca6ea 100644 --- a/source/blender/freestyle/intern/view_map/Functions0D.h +++ b/source/blender/freestyle/intern/view_map/Functions0D.h @@ -429,12 +429,12 @@ public: // QiF0D /*! Returns the quantitative invisibility of this Interface0D. -* This evaluation can be ambiguous (in the case of a TVertex for example). -* This functor tries to remove this ambiguity using the context offered by the 1D element to which the -* Interface0DIterator& belongs to. -* However, there still can be problematic cases, and the user willing to deal with this cases in a specific way -* should implement its own getQIF0D functor. -*/ + * This evaluation can be ambiguous (in the case of a TVertex for example). + * This functor tries to remove this ambiguity using the context offered by the 1D element to which the + * Interface0DIterator& belongs to. + * However, there still can be problematic cases, and the user willing to deal with this cases in a specific way + * should implement its own getQIF0D functor. + */ class QuantitativeInvisibilityF0D : public UnaryFunction0D<unsigned int> { public: diff --git a/source/blender/freestyle/intern/view_map/Silhouette.h b/source/blender/freestyle/intern/view_map/Silhouette.h index 0b20c9f6aa2..b9924e6ad95 100644 --- a/source/blender/freestyle/intern/view_map/Silhouette.h +++ b/source/blender/freestyle/intern/view_map/Silhouette.h @@ -1204,9 +1204,9 @@ public: } /*! Returns the index of the material of the face lying on the - * right of the FEdge. If this FEdge is a border, - * it has no Face on its right and therefore, no material. - */ + * right of the FEdge. If this FEdge is a border, + * it has no Face on its right and therefore, no material. + */ inline unsigned aFrsMaterialIndex() const { return _aFrsMaterialIndex; diff --git a/source/blender/freestyle/intern/winged_edge/Curvature.cpp b/source/blender/freestyle/intern/winged_edge/Curvature.cpp index 97dcc86cf31..989e101dd1a 100644 --- a/source/blender/freestyle/intern/winged_edge/Curvature.cpp +++ b/source/blender/freestyle/intern/winged_edge/Curvature.cpp @@ -372,21 +372,21 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V f2 = e->GetbFace(); /* We are solving for the values of the curvature tensor - * B = [ a b ; b c ]. - * The computations here are from section 5 of [Meyer et al 2002]. - * - * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed - * by setting the derivatives of the error E to zero (section 5.3). - * - * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002] - * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect). - * - * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale - * factor because the solution of the linear equations doesn't rely on it. - * - * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy - * terms that are the constant factors in the equations. - */ + * B = [ a b ; b c ]. + * The computations here are from section 5 of [Meyer et al 2002]. + * + * The first step is to calculate the linear equations governing the values of (a,b,c). These can be computed + * by setting the derivatives of the error E to zero (section 5.3). + * + * Since a + c = norm(Kh), we only compute the linear equations for dE/da and dE/db. (NB: [Meyer et al 2002] + * has the equation a + b = norm(Kh), but I'm almost positive this is incorrect). + * + * Note that the w_ij (defined in section 5.2) are all scaled by (1/8*A_mixed). We drop this uniform scale + * factor because the solution of the linear equations doesn't rely on it. + * + * The terms of the linear equations are xterm_dy with x in {a,b,c} and y in {a,b}. There are also const_dy + * terms that are the constant factors in the equations. + */ /* find the vector from v along edge e */ vec_edge = Vec3r(-1 * e->GetVec()); @@ -400,7 +400,7 @@ void gts_vertex_principal_directions(WVertex *v, Vec3r Kh, real Kg, Vec3r &e1, V /* section 5.2 */ /* I don't like performing a minimization where some of the weights can be negative (as can be the case - * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */ + * if f1 or f2 are obtuse). To ensure all-positive weights, we check for obtuseness. */ weight = 0.0; if (!triangle_obtuse(v, f1)) { weight += ve2 * cotan(f1->GetNextOEdge(e->twin())->GetbVertex(), e->GetaVertex(), e->GetbVertex()) / 8.0; diff --git a/source/blender/gpu/GPU_buffers.h b/source/blender/gpu/GPU_buffers.h index aefaf1a0f54..b693d473bd8 100644 --- a/source/blender/gpu/GPU_buffers.h +++ b/source/blender/gpu/GPU_buffers.h @@ -223,14 +223,14 @@ typedef struct GPU_PBVH_Buffers GPU_PBVH_Buffers; /* build */ GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( - const int (*face_vert_indices)[4], + const int (*face_vert_indices)[3], const struct MPoly *mpoly, const struct MLoop *mloop, const struct MLoopTri *looptri, const struct MVert *verts, const int *face_indices, const int face_indices_len); GPU_PBVH_Buffers *GPU_build_grid_pbvh_buffers( - int *grid_indices, int totgrid,unsigned int **grid_hidden, int gridsize, const struct CCGKey *key, + int *grid_indices, int totgrid, unsigned int **grid_hidden, int gridsize, const struct CCGKey *key, struct GridCommonGPUBuffer **grid_common_gpu_buffer); GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading); @@ -240,7 +240,7 @@ GPU_PBVH_Buffers *GPU_build_bmesh_pbvh_buffers(bool smooth_shading); void GPU_update_mesh_pbvh_buffers( GPU_PBVH_Buffers *buffers, const struct MVert *mvert, const int *vert_indices, int totvert, const float *vmask, - const int (*face_vert_indices)[4], bool show_diffuse_color); + const int (*face_vert_indices)[3], bool show_diffuse_color); void GPU_update_bmesh_pbvh_buffers(GPU_PBVH_Buffers *buffers, struct BMesh *bm, diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index bc732387c85..90b65af87c8 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -160,6 +160,12 @@ struct DerivedMesh; void GPU_draw_update_fvar_offset(struct DerivedMesh *dm); #endif +/* utilities */ +void GPU_select_index_set(int index); +void GPU_select_index_get(int index, int *r_col); +int GPU_select_to_index(unsigned int col); +void GPU_select_to_index_array(unsigned int *col, const unsigned int size); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index a79334df8ce..0d92d22a173 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -337,6 +337,7 @@ void GPU_mist_update_enable(short enable); void GPU_mist_update_values(int type, float start, float dist, float inten, float color[3]); void GPU_horizon_update_color(float color[3]); void GPU_ambient_update_color(float color[3]); +void GPU_zenith_update_color(float color[3]); struct GPUParticleInfo { diff --git a/source/blender/gpu/intern/gpu_buffers.c b/source/blender/gpu/intern/gpu_buffers.c index 36d297fb9fe..370841327aa 100644 --- a/source/blender/gpu/intern/gpu_buffers.c +++ b/source/blender/gpu/intern/gpu_buffers.c @@ -916,7 +916,7 @@ void GPU_buffer_unlock(GPUBuffer *UNUSED(buffer), GPUBindingType binding) { int bindtypegl = gpu_binding_type_gl[binding]; /* note: this operation can fail, could return - * an error code from this function? */ + * an error code from this function? */ glUnmapBuffer(bindtypegl); glBindBuffer(bindtypegl, 0); } @@ -1033,7 +1033,7 @@ static void gpu_color_from_mask_quad_copy(const CCGKey *key, void GPU_update_mesh_pbvh_buffers( GPU_PBVH_Buffers *buffers, const MVert *mvert, const int *vert_indices, int totvert, const float *vmask, - const int (*face_vert_indices)[4], bool show_diffuse_color) + const int (*face_vert_indices)[3], bool show_diffuse_color) { VertexBufferFormat *vert_data; int i, j; @@ -1161,7 +1161,7 @@ void GPU_update_mesh_pbvh_buffers( } GPU_PBVH_Buffers *GPU_build_mesh_pbvh_buffers( - const int (*face_vert_indices)[4], + const int (*face_vert_indices)[3], const MPoly *mpoly, const MLoop *mloop, const MLoopTri *looptri, const MVert *mvert, const int *face_indices, diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index f998dc9904e..7936811ab4d 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -91,7 +91,6 @@ #ifdef WITH_OPENSUBDIV # include "BKE_subsurf.h" -# include "BKE_DerivedMesh.h" # include "BKE_editmesh.h" # include "gpu_codegen.h" @@ -804,7 +803,7 @@ static void **gpu_gen_cube_map(unsigned int *rect, float *frect, int rectw, int * | | | | * | NegZ | PosZ | PosY | * |______|______|______| - */ + */ if (use_high_bit_depth) { float (*frectb)[4] = (float(*)[4])frect; float (**fsides)[4] = (float(**)[4])sides; @@ -2362,3 +2361,152 @@ void GPU_draw_update_fvar_offset(DerivedMesh *dm) } } #endif + + +/** \name Framebuffer color depth, for selection codes + * \{ */ + +#ifdef __APPLE__ + +/* apple seems to round colors to below and up on some configs */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x070707; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x030303; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x010101; + break; + } + + return i; +} + +#else + +/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ + +static unsigned int index_to_framebuffer(int index) +{ + unsigned int i = index; + + switch (GPU_color_depth()) { + case 8: + i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); + i |= 0x3F3F3F; + break; + case 12: + i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); + /* sometimes dithering subtracts! */ + i |= 0x0F0F0F; + break; + case 15: + case 16: + i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); + i |= 0x070707; + break; + case 24: + break; + default: /* 18 bits... */ + i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); + i |= 0x030303; + break; + } + + return i; +} + +#endif + + +void GPU_select_index_set(int index) +{ + const int col = index_to_framebuffer(index); + glColor3ub(( (col) & 0xFF), + (((col) >> 8) & 0xFF), + (((col) >> 16) & 0xFF)); +} + +void GPU_select_index_get(int index, int *r_col) +{ + const int col = index_to_framebuffer(index); + char *c_col = (char *)r_col; + c_col[0] = (col & 0xFF); /* red */ + c_col[1] = ((col >> 8) & 0xFF); /* green */ + c_col[2] = ((col >> 16) & 0xFF); /* blue */ + c_col[3] = 0xFF; /* alpha */ +} + + +#define INDEX_FROM_BUF_8(col) ((((col) & 0xC00000) >> 18) + (((col) & 0xC000) >> 12) + (((col) & 0xC0) >> 6)) +#define INDEX_FROM_BUF_12(col) ((((col) & 0xF00000) >> 12) + (((col) & 0xF000) >> 8) + (((col) & 0xF0) >> 4)) +#define INDEX_FROM_BUF_15_16(col) ((((col) & 0xF80000) >> 9) + (((col) & 0xF800) >> 6) + (((col) & 0xF8) >> 3)) +#define INDEX_FROM_BUF_18(col) ((((col) & 0xFC0000) >> 6) + (((col) & 0xFC00) >> 4) + (((col) & 0xFC) >> 2)) +#define INDEX_FROM_BUF_24(col) ((col) & 0xFFFFFF) + +int GPU_select_to_index(unsigned int col) +{ + if (col == 0) { + return 0; + } + + switch (GPU_color_depth()) { + case 8: return INDEX_FROM_BUF_8(col); + case 12: return INDEX_FROM_BUF_12(col); + case 15: + case 16: return INDEX_FROM_BUF_15_16(col); + case 24: return INDEX_FROM_BUF_24(col); + default: return INDEX_FROM_BUF_18(col); + } +} + +void GPU_select_to_index_array(unsigned int *col, const unsigned int size) +{ +#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ + for (i = size; i--; col++) { \ + if ((c = *col)) { \ + *col = INDEX_FROM_BUF_BITS(c); \ + } \ + } ((void)0) + + if (size > 0) { + unsigned int i, c; + + switch (GPU_color_depth()) { + case 8: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); + break; + case 12: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); + break; + case 15: + case 16: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); + break; + case 24: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); + break; + default: + INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); + break; + } + } + +#undef INDEX_BUF_ARRAY +} + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index b8a39c81122..d41573b681b 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -77,9 +77,10 @@ static struct GPUGlobal { GPUDeviceType device; GPUOSType os; GPUDriverType driver; - float dfdyfactors[2]; /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers - calculate dfdy in shader differently when drawing to an offscreen buffer. First - number is factor on screen and second is off-screen */ + /* workaround for different calculation of dfdy factors on GPUs. Some GPUs/drivers + * calculate dfdy in shader differently when drawing to an offscreen buffer. First + * number is factor on screen and second is off-screen */ + float dfdyfactors[2]; float max_anisotropy; } GG = {1, 0}; diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index f14b2e6e170..98a2ceb472e 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -88,6 +88,7 @@ static struct GPUWorld { float mistcol[4]; float horicol[3]; float ambcol[4]; + float zencol[3]; } GPUWorld; struct GPUMaterial { @@ -1673,6 +1674,11 @@ void GPU_ambient_update_color(float color[3]) GPUWorld.ambcol[3] = 1.0f; } +void GPU_zenith_update_color(float color[3]) +{ + copy_v3_v3(GPUWorld.zencol, color); +} + void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) { GPUMaterial *mat = shi->gpumat; @@ -1729,6 +1735,36 @@ void GPU_shaderesult_set(GPUShadeInput *shi, GPUShadeResult *shr) ulinfac, ulogfac, &shr->spec); } + /* environment lighting */ + if (!(mat->scene->gm.flag & GAME_GLSL_NO_ENV_LIGHTING) && + (world->mode & WO_ENV_LIGHT) && + (mat->scene->r.mode & R_SHADOW) && + !BKE_scene_use_new_shading_nodes(mat->scene)) + { + if ((world->ao_env_energy != 0.0f) && (GPU_link_changed(shi->amb) || ma->amb != 0.0f) && + (GPU_link_changed(shi->refl) || ma->ref != 0.0f)) + { + if (world->aocolor != WO_AOPLAIN) { + if (!(is_zero_v3(&world->horr) & is_zero_v3(&world->zenr))) { + GPUNodeLink *fcol, *f; + GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); + GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); + GPU_link(mat, "shade_mul_value", f, shi->rgb, &fcol); + GPU_link(mat, "env_apply", shr->combined, + GPU_dynamic_uniform(GPUWorld.horicol, GPU_DYNAMIC_HORIZON_COLOR, NULL), + GPU_dynamic_uniform(GPUWorld.zencol, GPU_DYNAMIC_ZENITH_COLOR, NULL), fcol, + GPU_builtin(GPU_VIEW_MATRIX), shi->vn, &shr->combined); + } + } + else { + GPUNodeLink *f; + GPU_link(mat, "math_multiply", shi->amb, shi->refl, &f); + GPU_link(mat, "math_multiply", f, GPU_uniform(&world->ao_env_energy), &f); + GPU_link(mat, "shade_maddf", shr->combined, f, shi->rgb, &shr->combined); + } + } + } + /* ambient color */ if (GPU_link_changed(shi->amb) || ma->amb != 0.0f) { GPU_link(mat, "shade_maddf", shr->combined, GPU_uniform(&ma->amb), @@ -2552,7 +2588,7 @@ int GPU_lamp_shadow_bind_code(GPULamp *lamp) float *GPU_lamp_dynpersmat(GPULamp *lamp) { - return lamp->dynpersmat ? (float *)lamp->dynpersmat : NULL; + return &lamp->dynpersmat[0][0]; } int GPU_lamp_shadow_layer(GPULamp *lamp) diff --git a/source/blender/gpu/shaders/gpu_shader_material.glsl b/source/blender/gpu/shaders/gpu_shader_material.glsl index 9914c4bb362..f3bd817a7cc 100644 --- a/source/blender/gpu/shaders/gpu_shader_material.glsl +++ b/source/blender/gpu/shaders/gpu_shader_material.glsl @@ -1358,6 +1358,13 @@ void mtex_cube_map(vec3 co, samplerCube ima, out float value, out vec4 color) value = 1.0; } +void mtex_cube_map_refl_from_refldir( + samplerCube ima, vec3 reflecteddirection, out float value, out vec4 color) +{ + color = textureCube(ima, reflecteddirection); + value = 1.0; +} + void mtex_cube_map_refl( samplerCube ima, vec3 vp, vec3 vn, mat4 viewmatrixinverse, mat4 viewmatrix, out float value, out vec4 color) @@ -2182,6 +2189,13 @@ void shade_madd_clamped(vec4 col, vec4 col1, vec4 col2, out vec4 outcol) outcol = col + max(col1 * col2, vec4(0.0, 0.0, 0.0, 0.0)); } +void env_apply(vec4 col, vec4 hor, vec4 zen, vec4 f, mat4 vm, vec3 vn, out vec4 outcol) +{ + vec3 vv = normalize(vm[2].xyz); + float skyfac = 0.5 * (1.0 + dot(vn, -vv)); + outcol = col + f * mix(hor, zen, skyfac); +} + void shade_maddf(vec4 col, float f, vec4 col1, out vec4 outcol) { outcol = col + f * col1; diff --git a/source/blender/gpu/shaders/gpu_shader_vertex.glsl b/source/blender/gpu/shaders/gpu_shader_vertex.glsl index 9a6537b4f09..db0068d2f3d 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex.glsl @@ -14,6 +14,9 @@ varying vec3 varnormal; varying float gl_ClipDistance[6]; #endif + +/* Color, keep in sync with: gpu_shader_vertex_world.glsl */ + float srgb_to_linearrgb(float c) { if (c < 0.04045) @@ -76,6 +79,9 @@ void set_var_from_attr(vec4 attr, int info, out vec4 var) } } +/* end color code */ + + void main() { #ifndef USE_OPENSUBDIV diff --git a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl index 9dbcaeb7a32..d45a4b316a8 100644 --- a/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl +++ b/source/blender/gpu/shaders/gpu_shader_vertex_world.glsl @@ -2,6 +2,74 @@ varying vec3 varposition; varying vec3 varnormal; + +/* Color, keep in sync with: gpu_shader_vertex.glsl */ + +float srgb_to_linearrgb(float c) +{ + if (c < 0.04045) + return (c < 0.0) ? 0.0 : c * (1.0 / 12.92); + else + return pow((c + 0.055) * (1.0 / 1.055), 2.4); +} + +void srgb_to_linearrgb(vec3 col_from, out vec3 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); +} + +void srgb_to_linearrgb(vec4 col_from, out vec4 col_to) +{ + col_to.r = srgb_to_linearrgb(col_from.r); + col_to.g = srgb_to_linearrgb(col_from.g); + col_to.b = srgb_to_linearrgb(col_from.b); + col_to.a = col_from.a; +} + +bool is_srgb(int info) +{ +#ifdef USE_NEW_SHADING + return (info == 1)? true: false; +#else + return false; +#endif +} + +void set_var_from_attr(float attr, int info, out float var) +{ + var = attr; +} + +void set_var_from_attr(vec2 attr, int info, out vec2 var) +{ + var = attr; +} + +void set_var_from_attr(vec3 attr, int info, out vec3 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +void set_var_from_attr(vec4 attr, int info, out vec4 var) +{ + if (is_srgb(info)) { + srgb_to_linearrgb(attr, var); + } + else { + var = attr; + } +} + +/* end color code */ + + void main() { /* position does not need to be transformed, we already have it */ diff --git a/source/blender/ikplugin/intern/iksolver_plugin.c b/source/blender/ikplugin/intern/iksolver_plugin.c index b3c83bffb3f..6ea311b2c7b 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.c +++ b/source/blender/ikplugin/intern/iksolver_plugin.c @@ -50,6 +50,8 @@ #include <string.h> /* memcpy */ +#define USE_NONUNIFORM_SCALE + /* ********************** THE IK SOLVER ******************* */ /* allocates PoseTree, and links that to root bone/channel */ @@ -525,10 +527,10 @@ void iksolver_initialize_tree(struct Scene *UNUSED(scene), struct Object *ob, fl ob->pose->flag &= ~POSE_WAS_REBUILT; } -void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime) +void iksolver_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) { - while (pchan->iktree.first) { - PoseTree *tree = pchan->iktree.first; + while (pchan_root->iktree.first) { + PoseTree *tree = pchan_root->iktree.first; int a; /* stop on the first tree that isn't a standard IK chain */ @@ -542,6 +544,19 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose /* tell blender that this channel was controlled by IK, it's cleared on each BKE_pose_where_is() */ tree->pchan[a]->flag |= POSE_CHAIN; } + +#ifdef USE_NONUNIFORM_SCALE + float (*pchan_scale_data)[3] = MEM_mallocN(sizeof(float[3]) * tree->totchannel, __func__); + + for (a = 0; a < tree->totchannel; a++) { + mat4_to_size(pchan_scale_data[a], tree->pchan[a]->pose_mat); + + /* make uniform at y scale since this controls the length */ + normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][1]); + normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][1]); + } +#endif + /* 5. execute the IK solver */ execute_posetree(scene, ob, tree); @@ -556,8 +571,16 @@ void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPose where_is_ik_bone(tree->pchan[a], tree->basis_change[a]); } +#ifdef USE_NONUNIFORM_SCALE + for (a = 0; a < tree->totchannel; a++) { + normalize_v3_length(tree->pchan[a]->pose_mat[0], pchan_scale_data[a][0]); + normalize_v3_length(tree->pchan[a]->pose_mat[2], pchan_scale_data[a][2]); + } + MEM_freeN(pchan_scale_data); +#endif + /* 7. and free */ - BLI_remlink(&pchan->iktree, tree); + BLI_remlink(&pchan_root->iktree, tree); free_posetree(tree); } } diff --git a/source/blender/ikplugin/intern/iksolver_plugin.h b/source/blender/ikplugin/intern/iksolver_plugin.h index c2ae4f937e7..07264280a25 100644 --- a/source/blender/ikplugin/intern/iksolver_plugin.h +++ b/source/blender/ikplugin/intern/iksolver_plugin.h @@ -41,7 +41,7 @@ extern "C" { #endif void iksolver_initialize_tree(struct Scene *scene, struct Object *ob, float ctime); -void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); +void iksolver_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime); #ifdef __cplusplus } diff --git a/source/blender/ikplugin/intern/itasc_plugin.cpp b/source/blender/ikplugin/intern/itasc_plugin.cpp index d4814a4e3a2..b8ed780397f 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.cpp +++ b/source/blender/ikplugin/intern/itasc_plugin.cpp @@ -1770,7 +1770,7 @@ void itasc_initialize_tree(struct Scene *scene, Object *ob, float ctime) ob->pose->flag &= ~POSE_WAS_REBUILT; } -void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime) +void itasc_execute_tree(struct Scene *scene, Object *ob, bPoseChannel *pchan_root, float ctime) { if (!ob->pose->ikdata) { // IK tree not yet created, no it now @@ -1784,7 +1784,7 @@ void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseCha if (!ikparam) ikparam = &DefIKParam; for (IK_Scene *ikscene = ikdata->first; ikscene; ikscene = ikscene->next) { - if (ikscene->channels[0].pchan == pchan) { + if (ikscene->channels[0].pchan == pchan_root) { float timestep = scene->r.frs_sec_base / scene->r.frs_sec; if (ob->pose->flag & POSE_GAME_ENGINE) { timestep = ob->pose->ctime; diff --git a/source/blender/ikplugin/intern/itasc_plugin.h b/source/blender/ikplugin/intern/itasc_plugin.h index 0500125b4c7..bcd95bc31ca 100644 --- a/source/blender/ikplugin/intern/itasc_plugin.h +++ b/source/blender/ikplugin/intern/itasc_plugin.h @@ -41,7 +41,7 @@ extern "C" { #endif void itasc_initialize_tree(struct Scene *scene, struct Object *ob, float ctime); -void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan, float ctime); +void itasc_execute_tree(struct Scene *scene, struct Object *ob, struct bPoseChannel *pchan_root, float ctime); void itasc_release_tree(struct Scene *scene, struct Object *ob, float ctime); void itasc_clear_data(struct bPose *pose); void itasc_clear_cache(struct bPose *pose); diff --git a/source/blender/imbuf/intern/openexr/openexr_api.cpp b/source/blender/imbuf/intern/openexr/openexr_api.cpp index fdadb783815..89e796fb7ee 100644 --- a/source/blender/imbuf/intern/openexr/openexr_api.cpp +++ b/source/blender/imbuf/intern/openexr/openexr_api.cpp @@ -77,7 +77,7 @@ extern "C" { // The following prevents a linking error in debug mode for MSVC using the libs in CVS -#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) +#if defined(WITH_OPENEXR) && defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && _MSC_VER < 1900 _CRTIMP void __cdecl _invalid_parameter_noinfo(void) { } @@ -127,7 +127,7 @@ class Mem_IStream : public Imf::IStream { public: - Mem_IStream (unsigned char *exrbuf, size_t exrsize) : + Mem_IStream(unsigned char *exrbuf, size_t exrsize) : IStream("dummy"), _exrpos(0), _exrsize(exrsize) { _exrbuf = exrbuf; diff --git a/source/blender/imbuf/intern/thumbs.c b/source/blender/imbuf/intern/thumbs.c index 95d061bcb75..3629332a4ac 100644 --- a/source/blender/imbuf/intern/thumbs.c +++ b/source/blender/imbuf/intern/thumbs.c @@ -46,6 +46,8 @@ #include "BLO_readfile.h" +#include "DNA_space_types.h" /* For FILE_MAX_LIBEXTRA */ + #include "IMB_imbuf_types.h" #include "IMB_imbuf.h" #include "IMB_thumbs.h" @@ -533,7 +535,7 @@ ImBuf *IMB_thumb_manage(const char *org_path, ThumbSize size, ThumbSource source char thumb_path[FILE_MAX]; char thumb_name[40]; char uri[URI_MAX]; - char path_buff[FILE_MAX]; + char path_buff[FILE_MAX_LIBEXTRA]; const char *file_path; const char *path; BLI_stat_t st; diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index b0812a81ee1..bb5d2b4cf29 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -269,6 +269,8 @@ typedef struct PreviewImage { #define ID_MISSING(_id) (((_id)->tag & LIB_TAG_MISSING) != 0) +#define ID_IS_LINKED_DATABLOCK(_id) (((ID *)(_id))->lib != NULL) + #ifdef GS # undef GS #endif diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 4d82e4528d6..9a19606d6c8 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -330,7 +330,7 @@ typedef enum ePchan_DrawFlag { /* PoseChannel->bboneflag */ typedef enum ePchan_BBoneFlag { - /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbours */ + /* Use custom reference bones (for roll and handle alignment), instead of immediate neighbors */ PCHAN_BBONE_CUSTOM_HANDLES = (1 << 1), /* Evaluate start handle as being "relative" */ PCHAN_BBONE_CUSTOM_START_REL = (1 << 2), @@ -627,8 +627,9 @@ typedef enum eDopeSheet_FilterFlag { typedef enum eDopeSheet_Flag { ADS_FLAG_SUMMARY_COLLAPSED = (1 << 0), /* when summary is shown, it is collapsed, so all other channels get hidden */ ADS_FLAG_SHOW_DBFILTERS = (1 << 1), /* show filters for datablocks */ - + ADS_FLAG_FUZZY_NAMES = (1 << 2), /* use fuzzy/partial string matches when ADS_FILTER_BY_FCU_NAME is enabled (WARNING: expensive operation) */ + ADS_FLAG_NO_DB_SORT = (1 << 3), /* do not sort datablocks (mostly objects) by name (NOTE: potentially expensive operation) */ /* NOTE: datablock filter flags continued (1 << 10) onwards... */ } eDopeSheet_Flag; diff --git a/source/blender/makesdna/DNA_anim_types.h b/source/blender/makesdna/DNA_anim_types.h index 4c1283452ff..6bd7b3a4999 100644 --- a/source/blender/makesdna/DNA_anim_types.h +++ b/source/blender/makesdna/DNA_anim_types.h @@ -537,8 +537,9 @@ typedef enum eFCurve_Extend { /* curve coloring modes */ typedef enum eFCurve_Coloring { FCURVE_COLOR_AUTO_RAINBOW = 0, /* automatically determine color using rainbow (calculated at drawtime) */ - FCURVE_COLOR_AUTO_RGB, /* automatically determine color using XYZ (array index) <-> RGB */ - FCURVE_COLOR_CUSTOM /* custom color */ + FCURVE_COLOR_AUTO_RGB = 1, /* automatically determine color using XYZ (array index) <-> RGB */ + FCURVE_COLOR_AUTO_YRGB = 3, /* automatically determine color where XYZ <-> RGB, but index(X) != 0 */ + FCURVE_COLOR_CUSTOM = 2, /* custom color */ } eFCurve_Coloring; /* ************************************************ */ diff --git a/source/blender/makesdna/DNA_camera_types.h b/source/blender/makesdna/DNA_camera_types.h index 68741578f27..52e40cbc098 100644 --- a/source/blender/makesdna/DNA_camera_types.h +++ b/source/blender/makesdna/DNA_camera_types.h @@ -85,8 +85,8 @@ typedef struct Camera { char sensor_fit; char pad[7]; - /* Stereo settings */ - struct CameraStereoSettings stereo; + /* Stereo settings */ + struct CameraStereoSettings stereo; } Camera; /* **************** CAMERA ********************* */ diff --git a/source/blender/makesdna/DNA_cloth_types.h b/source/blender/makesdna/DNA_cloth_types.h index 07bc2478837..d385e303a7c 100644 --- a/source/blender/makesdna/DNA_cloth_types.h +++ b/source/blender/makesdna/DNA_cloth_types.h @@ -42,7 +42,7 @@ * * I've tried to keep similar, if not exact names for the variables as * are presented in the paper. Where I've changed the concept slightly, - * as in stepsPerFrame comapred to the time step in the paper, I've used + * as in stepsPerFrame compared to the time step in the paper, I've used * variables with different names to minimize confusion. */ diff --git a/source/blender/makesdna/DNA_color_types.h b/source/blender/makesdna/DNA_color_types.h index c9a5e056e4a..1d88b01cf62 100644 --- a/source/blender/makesdna/DNA_color_types.h +++ b/source/blender/makesdna/DNA_color_types.h @@ -157,10 +157,11 @@ typedef struct Scopes { /* scopes->wavefrm_mode */ #define SCOPES_WAVEFRM_LUMA 0 -#define SCOPES_WAVEFRM_RGB 1 +#define SCOPES_WAVEFRM_RGB_PARADE 1 #define SCOPES_WAVEFRM_YCC_601 2 #define SCOPES_WAVEFRM_YCC_709 3 #define SCOPES_WAVEFRM_YCC_JPEG 4 +#define SCOPES_WAVEFRM_RGB 5 typedef struct ColorManagedViewSettings { int flag, pad; diff --git a/source/blender/makesdna/DNA_curve_types.h b/source/blender/makesdna/DNA_curve_types.h index 8f711c1b23b..902fa4ce987 100644 --- a/source/blender/makesdna/DNA_curve_types.h +++ b/source/blender/makesdna/DNA_curve_types.h @@ -230,7 +230,7 @@ typedef struct Curve { /* font part */ short lines; - char spacemode, pad1; + char spacemode, align_y; float spacing, linedist, shear, fsize, wordspace, ulpos, ulheight; float xof, yof; float linewidth; @@ -322,11 +322,19 @@ enum { /* Curve.spacemode */ enum { - CU_LEFT = 0, - CU_MIDDLE = 1, - CU_RIGHT = 2, - CU_JUSTIFY = 3, - CU_FLUSH = 4, + CU_ALIGN_X_LEFT = 0, + CU_ALIGN_X_MIDDLE = 1, + CU_ALIGN_X_RIGHT = 2, + CU_ALIGN_X_JUSTIFY = 3, + CU_ALIGN_X_FLUSH = 4, +}; + +/* Curve.align_y */ +enum { + CU_ALIGN_Y_TOP_BASELINE = 0, + CU_ALIGN_Y_TOP = 1, + CU_ALIGN_Y_CENTER = 2, + CU_ALIGN_Y_BOTTOM = 3, }; /* Nurb.flag */ @@ -416,6 +424,7 @@ typedef enum eBezTriple_KeyframeType { BEZT_KEYTYPE_EXTREME = 1, /* 'extreme' keyframe */ BEZT_KEYTYPE_BREAKDOWN = 2, /* 'breakdown' keyframe */ BEZT_KEYTYPE_JITTER = 3, /* 'jitter' keyframe (for adding 'filler' secondary motion) */ + BEZT_KEYTYPE_MOVEHOLD = 4, /* one end of a 'moving hold' */ } eBezTriple_KeyframeType; /* checks if the given BezTriple is selected */ diff --git a/source/blender/makesdna/DNA_genfile.h b/source/blender/makesdna/DNA_genfile.h index d62369803d6..0e34792e624 100644 --- a/source/blender/makesdna/DNA_genfile.h +++ b/source/blender/makesdna/DNA_genfile.h @@ -74,13 +74,25 @@ enum eSDNA_StructCompare { SDNA_CMP_NOT_EQUAL = 2, }; -struct SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap); +struct SDNA *DNA_sdna_from_data( + const void *data, const int datalen, + bool do_endian_swap, bool data_alloc, + const char **r_error_message); void DNA_sdna_free(struct SDNA *sdna); -int DNA_struct_find_nr(struct SDNA *sdna, const char *str); -void DNA_struct_switch_endian(struct SDNA *oldsdna, int oldSDNAnr, char *data); -char *DNA_struct_get_compareflags(struct SDNA *sdna, struct SDNA *newsdna); -void *DNA_struct_reconstruct(struct SDNA *newsdna, struct SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data); +/* Access for current Blender versions SDNA*/ +void DNA_sdna_current_init(void); +/* borrowed reference */ +const struct SDNA *DNA_sdna_current_get(void); +void DNA_sdna_current_free(void); + +int DNA_struct_find_nr_ex(const struct SDNA *sdna, const char *str, unsigned int *index_last); +int DNA_struct_find_nr(const struct SDNA *sdna, const char *str); +void DNA_struct_switch_endian(const struct SDNA *oldsdna, int oldSDNAnr, char *data); +char *DNA_struct_get_compareflags(const struct SDNA *sdna, const struct SDNA *newsdna); +void *DNA_struct_reconstruct( + const struct SDNA *newsdna, const struct SDNA *oldsdna, + char *compflags, int oldSDNAnr, int blocks, void *data); int DNA_elem_array_size(const char *str); int DNA_elem_offset(struct SDNA *sdna, const char *stype, const char *vartype, const char *name); diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index a58e995f1c6..bbc8edf4344 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -641,8 +641,9 @@ typedef struct BooleanModifierData { struct Object *object; char operation; - char bm_flag, pad[2]; - float threshold; + char solver; + char pad[2]; + float double_threshold; } BooleanModifierData; typedef enum { @@ -651,13 +652,10 @@ typedef enum { eBooleanModifierOp_Difference = 2, } BooleanModifierOp; -/* temp bm_flag (debugging only) */ -enum { - eBooleanModifierBMeshFlag_Enabled = (1 << 0), - eBooleanModifierBMeshFlag_BMesh_Separate = (1 << 1), - eBooleanModifierBMeshFlag_BMesh_NoDissolve = (1 << 2), - eBooleanModifierBMeshFlag_BMesh_NoConnectRegions = (1 << 3), -}; +typedef enum { + eBooleanModifierSolver_Carve = 0, + eBooleanModifierSolver_BMesh = 1, +} BooleanSolver; typedef struct MDefInfluence { int vertex; diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 6cba3322135..46b30f41f5b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -912,7 +912,8 @@ typedef struct NodeSunBeams { #define SHD_GLOSSY_BECKMANN 0 #define SHD_GLOSSY_SHARP 1 #define SHD_GLOSSY_GGX 2 -#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_ASHIKHMIN_SHIRLEY 3 +#define SHD_GLOSSY_MULTI_GGX 4 /* vector transform */ #define SHD_VECT_TRANSFORM_TYPE_VECTOR 0 diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 79af1813a8f..60bd37799fb 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -902,6 +902,7 @@ typedef struct GameData { #define GAME_GLSL_NO_COLOR_MANAGEMENT (1 << 15) #define GAME_SHOW_OBSTACLE_SIMULATION (1 << 16) #define GAME_NO_MATERIAL_CACHING (1 << 17) +#define GAME_GLSL_NO_ENV_LIGHTING (1 << 18) /* Note: GameData.flag is now an int (max 32 flags). A short could only take 16 flags */ /* GameData.playerflag */ diff --git a/source/blender/makesdna/DNA_sdna_types.h b/source/blender/makesdna/DNA_sdna_types.h index 28204ebeb88..bd8f23f30c1 100644 --- a/source/blender/makesdna/DNA_sdna_types.h +++ b/source/blender/makesdna/DNA_sdna_types.h @@ -35,16 +35,17 @@ # # typedef struct SDNA { - char *data; /* full copy of 'encoded' data */ + const char *data; /* full copy of 'encoded' data (when data_alloc is set, otherwise borrowed). */ int datalen; /* length of data */ + bool data_alloc; int nr_names; /* total number of struct members */ - const char **names; /* struct member names */ + const char **names; /* struct member names */ int pointerlen; /* size of a pointer in bytes */ int nr_types; /* number of basic types + struct types */ - char **types; /* type names */ + const char **types; /* type names */ short *typelens; /* type lengths */ int nr_structs; /* number of struct types */ @@ -56,18 +57,13 @@ typedef struct SDNA { struct GHash *structs_map; /* ghash for faster lookups, * requires WITH_DNA_GHASH to be used for now */ - - /* wrong place for this really, its a simple - * cache for findstruct_nr. - */ - int lastfind; } SDNA; # # typedef struct BHead { int code, len; - void *old; + const void *old; int SDNAnr, nr; } BHead; # diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 46b7d717991..4ce0f369ebd 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -252,7 +252,7 @@ typedef struct SpaceOops { struct BLI_mempool *treestore; /* search stuff */ - char search_string[32]; + char search_string[64]; struct TreeStoreElem search_tse; short flag, outlinevis, storeflag, search_flags; @@ -412,6 +412,8 @@ typedef enum eSpaceNla_Flag { SNLA_NOSTRIPCURVES = (1 << 5), /* don't perform realtime updates */ SNLA_NOREALTIMEUPDATES = (1 << 6), + /* don't show local strip marker indications */ + SNLA_NOLOCALMARKERS = (1 << 7), } eSpaceNla_Flag; @@ -875,8 +877,6 @@ typedef struct SpaceImage { struct Image *image; struct ImageUser iuser; - struct CurveMapping *cumap DNA_DEPRECATED; /* was switched to scene's color management settings */ - struct Scopes scopes; /* histogram waveform and vectorscope */ struct Histogram sample_line_hist; /* sample line histogram */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index af1dfc62894..02a0b414bb3 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -284,7 +284,10 @@ typedef struct ThemeSpace { char nodeclass_pattern[4], nodeclass_layout[4]; char movie[4], movieclip[4], mask[4], image[4], scene[4], audio[4]; /* for sequence editor */ - char effect[4], transition[4], meta[4], text_strip[4], pad[4]; + char effect[4], transition[4], meta[4], text_strip[4]; + + float keyframe_scale_fac; /* for dopesheet - scale factor for size of keyframes (i.e. height of channels) */ + char editmesh_active[4]; char handle_vertex[4]; diff --git a/source/blender/makesdna/DNA_view3d_types.h b/source/blender/makesdna/DNA_view3d_types.h index 5b533d1ec48..4c243507e82 100644 --- a/source/blender/makesdna/DNA_view3d_types.h +++ b/source/blender/makesdna/DNA_view3d_types.h @@ -239,7 +239,7 @@ typedef struct View3D { float stereo3d_convergence_alpha; /* Previous viewport draw type. - * Runtime-only, set in the rendered viewport otggle operator. + * Runtime-only, set in the rendered viewport toggle operator. */ short prev_drawtype; short pad1; diff --git a/source/blender/makesdna/intern/CMakeLists.txt b/source/blender/makesdna/intern/CMakeLists.txt index 52487edfd2b..8c758c33dc5 100644 --- a/source/blender/makesdna/intern/CMakeLists.txt +++ b/source/blender/makesdna/intern/CMakeLists.txt @@ -52,12 +52,20 @@ endif() # SRC_DNA_INC is defined in the parent dir +add_cc_flags_custom_test(makesdna) + add_executable(makesdna ${SRC} ${SRC_DNA_INC}) # Output dna.c add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/dna.c - COMMAND "$<TARGET_FILE:makesdna>" ${CMAKE_CURRENT_BINARY_DIR}/dna.c ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + COMMAND + "$<TARGET_FILE:makesdna>" + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + ${CMAKE_SOURCE_DIR}/source/blender/makesdna/ DEPENDS makesdna ) @@ -78,7 +86,11 @@ set(SRC ${SRC_DNA_INC} ) -set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/dna.c PROPERTIES GENERATED TRUE) +set_source_files_properties( + ${CMAKE_CURRENT_BINARY_DIR}/dna.c + ${CMAKE_CURRENT_BINARY_DIR}/dna_type_offsets.h + PROPERTIES GENERATED TRUE +) blender_add_lib(bf_dna "${SRC}" "${INC}" "${INC_SYS}") @@ -94,10 +106,11 @@ set(INC_SYS ) set(SRC - ../../blenlib/intern/BLI_mempool.c - ../../blenlib/intern/listbase.c ../../blenlib/intern/BLI_ghash.c + ../../blenlib/intern/BLI_mempool.c + ../../blenlib/intern/endian_switch.c ../../blenlib/intern/hash_mm2a.c + ../../blenlib/intern/listbase.c ) blender_add_lib(bf_dna_blenlib "${SRC}" "${INC}" "${INC_SYS}") diff --git a/source/blender/makesdna/intern/dna_genfile.c b/source/blender/makesdna/intern/dna_genfile.c index 4f19e819625..4db98bda7dd 100644 --- a/source/blender/makesdna/intern/dna_genfile.c +++ b/source/blender/makesdna/intern/dna_genfile.c @@ -39,10 +39,12 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <limits.h> #include "MEM_guardedalloc.h" // for MEM_freeN MEM_mallocN MEM_callocN #include "BLI_utildefines.h" +#include "BLI_endian_switch.h" #ifdef WITH_DNA_GHASH # include "BLI_ghash.h" @@ -132,39 +134,6 @@ * */ -/* ************************* ENDIAN STUFF ********************** */ - -/** - * converts a short between big/little endian. - */ -static short le_short(short temp) -{ - short new; - char *rt = (char *)&temp, *rtn = (char *)&new; - - rtn[0] = rt[1]; - rtn[1] = rt[0]; - - return new; -} - -/** - * converts an int between big/little endian. - */ -static int le_int(int temp) -{ - int new; - char *rt = (char *)&temp, *rtn = (char *)&new; - - rtn[0] = rt[3]; - rtn[1] = rt[2]; - rtn[2] = rt[1]; - rtn[3] = rt[0]; - - return new; -} - - /* ************************* MAKE DNA ********************** */ /* allowed duplicate code from makesdna.c */ @@ -195,7 +164,10 @@ int DNA_elem_array_size(const char *str) void DNA_sdna_free(SDNA *sdna) { - MEM_freeN(sdna->data); + if (sdna->data_alloc) { + MEM_freeN((void *)sdna->data); + } + MEM_freeN((void *)sdna->names); MEM_freeN(sdna->types); MEM_freeN(sdna->structs); @@ -276,37 +248,16 @@ static void printstruct(SDNA *sdna, short strnr) #endif /** - * Returns a pointer to the start of the struct info for the struct with the specified name. - */ -static short *findstruct_name(SDNA *sdna, const char *str) -{ - int a; - short *sp = NULL; - - - for (a = 0; a < sdna->nr_structs; a++) { - - sp = sdna->structs[a]; - - if (strcmp(sdna->types[sp[0]], str) == 0) { - return sp; - } - } - - return NULL; -} - -/** * Returns the index of the struct info for the struct with the specified name. */ -int DNA_struct_find_nr(SDNA *sdna, const char *str) +int DNA_struct_find_nr_ex(const SDNA *sdna, const char *str, unsigned int *index_last) { const short *sp = NULL; - if (sdna->lastfind < sdna->nr_structs) { - sp = sdna->structs[sdna->lastfind]; + if (*index_last < sdna->nr_structs) { + sp = sdna->structs[*index_last]; if (strcmp(sdna->types[sp[0]], str) == 0) { - return sdna->lastfind; + return *index_last; } } @@ -319,7 +270,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str) if (index_p) { a = GET_INT_FROM_POINTER(*index_p); - sdna->lastfind = a; + *index_last = a; } else { a = -1; @@ -335,7 +286,7 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str) sp = sdna->structs[a]; if (strcmp(sdna->types[sp[0]], str) == 0) { - sdna->lastfind = a; + *index_last = a; return a; } } @@ -344,26 +295,51 @@ int DNA_struct_find_nr(SDNA *sdna, const char *str) #endif } +int DNA_struct_find_nr(const SDNA *sdna, const char *str) +{ + unsigned int index_last_dummy = UINT_MAX; + return DNA_struct_find_nr_ex(sdna, str, &index_last_dummy); +} + /* ************************* END DIV ********************** */ /* ************************* READ DNA ********************** */ +BLI_INLINE const char *pad_up_4(const char *ptr) +{ + return (const char *)((((uintptr_t)ptr) + 3) & ~3); +} + /** * In sdna->data the data, now we convert that to something understandable */ -static void init_structDNA(SDNA *sdna, bool do_endian_swap) +static bool init_structDNA( + SDNA *sdna, bool do_endian_swap, + const char **r_error_message) { int *data, *verg, gravity_fix = -1; - intptr_t nr; short *sp; - char str[8], *cp; + char str[8]; verg = (int *)str; data = (int *)sdna->data; + /* clear pointers incase of error */ + sdna->names = NULL; + sdna->types = NULL; + sdna->structs = NULL; +#ifdef WITH_DNA_GHASH + sdna->structs_map = NULL; +#endif + strcpy(str, "SDNA"); - if (*data == *verg) { - + if (*data != *verg) { + *r_error_message = "SDNA error in SDNA file"; + return false; + } + else { + const char *cp; + data++; /* load names array */ @@ -371,20 +347,21 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) if (*data == *verg) { data++; - if (do_endian_swap) sdna->nr_names = le_int(*data); - else sdna->nr_names = *data; + sdna->nr_names = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_names); + } data++; sdna->names = MEM_callocN(sizeof(void *) * sdna->nr_names, "sdnanames"); } else { - printf("NAME error in SDNA file\n"); - return; + *r_error_message = "NAME error in SDNA file"; + return false; } - nr = 0; cp = (char *)data; - while (nr < sdna->nr_names) { + for (int nr = 0; nr < sdna->nr_names; nr++) { sdna->names[nr] = cp; /* "float gravity [3]" was parsed wrong giving both "gravity" and @@ -399,32 +376,31 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) while (*cp) cp++; cp++; - nr++; } - nr = (intptr_t)cp; /* prevent BUS error */ - nr = (nr + 3) & ~3; - cp = (char *)nr; + + cp = pad_up_4(cp); /* load type names array */ data = (int *)cp; strcpy(str, "TYPE"); if (*data == *verg) { data++; - - if (do_endian_swap) sdna->nr_types = le_int(*data); - else sdna->nr_types = *data; + + sdna->nr_types = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_types); + } data++; sdna->types = MEM_callocN(sizeof(void *) * sdna->nr_types, "sdnatypes"); } else { - printf("TYPE error in SDNA file\n"); - return; + *r_error_message = "TYPE error in SDNA file"; + return false; } - nr = 0; cp = (char *)data; - while (nr < sdna->nr_types) { + for (int nr = 0; nr < sdna->nr_types; nr++) { sdna->types[nr] = cp; /* this is a patch, to change struct names without a conflict with SDNA */ @@ -437,11 +413,9 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) while (*cp) cp++; cp++; - nr++; } - nr = (intptr_t)cp; /* prevent BUS error */ - nr = (nr + 3) & ~3; - cp = (char *)nr; + + cp = pad_up_4(cp); /* load typelen array */ data = (int *)cp; @@ -452,20 +426,14 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) sdna->typelens = sp; if (do_endian_swap) { - short a, *spo = sp; - - a = sdna->nr_types; - while (a--) { - spo[0] = le_short(spo[0]); - spo++; - } + BLI_endian_switch_int16_array(sp, sdna->nr_types); } sp += sdna->nr_types; } else { - printf("TLEN error in SDNA file\n"); - return; + *r_error_message = "TLEN error in SDNA file"; + return false; } if (sdna->nr_types & 1) sp++; /* prevent BUS error */ @@ -475,92 +443,152 @@ static void init_structDNA(SDNA *sdna, bool do_endian_swap) if (*data == *verg) { data++; - if (do_endian_swap) sdna->nr_structs = le_int(*data); - else sdna->nr_structs = *data; + sdna->nr_structs = *data; + if (do_endian_swap) { + BLI_endian_switch_int32(&sdna->nr_structs); + } data++; sdna->structs = MEM_callocN(sizeof(void *) * sdna->nr_structs, "sdnastrcs"); } else { - printf("STRC error in SDNA file\n"); - return; + *r_error_message = "STRC error in SDNA file"; + return false; } - nr = 0; sp = (short *)data; - while (nr < sdna->nr_structs) { + for (int nr = 0; nr < sdna->nr_structs; nr++) { sdna->structs[nr] = sp; if (do_endian_swap) { short a; - sp[0] = le_short(sp[0]); - sp[1] = le_short(sp[1]); + BLI_endian_switch_int16(&sp[0]); + BLI_endian_switch_int16(&sp[1]); a = sp[1]; sp += 2; while (a--) { - sp[0] = le_short(sp[0]); - sp[1] = le_short(sp[1]); + BLI_endian_switch_int16(&sp[0]); + BLI_endian_switch_int16(&sp[1]); sp += 2; } } else { sp += 2 * sp[1] + 2; } - - nr++; } + } - /* finally pointerlen: use struct ListBase to test it, never change the size of it! */ - sp = findstruct_name(sdna, "ListBase"); - /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */ - - sdna->pointerlen = sdna->typelens[sp[0]] / 2; - - if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) { - printf("ListBase struct error! Needs it to calculate pointerize.\n"); - exit(1); - /* well, at least sizeof(ListBase) is error proof! (ton) */ - } - + { /* second part of gravity problem, setting "gravity" type to void */ if (gravity_fix > -1) { - for (nr = 0; nr < sdna->nr_structs; nr++) { + for (int nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; if (strcmp(sdna->types[sp[0]], "ClothSimSettings") == 0) sp[10] = SDNA_TYPE_VOID; } } + } #ifdef WITH_DNA_GHASH + { /* create a ghash lookup to speed up */ sdna->structs_map = BLI_ghash_str_new_ex("init_structDNA gh", sdna->nr_structs); - for (nr = 0; nr < sdna->nr_structs; nr++) { + for (intptr_t nr = 0; nr < sdna->nr_structs; nr++) { sp = sdna->structs[nr]; - BLI_ghash_insert(sdna->structs_map, sdna->types[sp[0]], SET_INT_IN_POINTER(nr)); + BLI_ghash_insert(sdna->structs_map, (void *)sdna->types[sp[0]], SET_INT_IN_POINTER(nr)); } + } #endif + + /* Calculate 'sdna->pointerlen' */ + { + intptr_t nr = DNA_struct_find_nr(sdna, "ListBase"); + + /* should never happen, only with corrupt file for example */ + if (UNLIKELY(nr == -1)) { + *r_error_message = "ListBase struct error! Not found."; + return false; + } + + /* finally pointerlen: use struct ListBase to test it, never change the size of it! */ + sp = sdna->structs[nr]; + /* weird; i have no memory of that... I think I used sizeof(void *) before... (ton) */ + + sdna->pointerlen = sdna->typelens[sp[0]] / 2; + + if (sp[1] != 2 || (sdna->pointerlen != 4 && sdna->pointerlen != 8)) { + *r_error_message = "ListBase struct error! Needs it to calculate pointerize."; + /* well, at least sizeof(ListBase) is error proof! (ton) */ + return false; + } } + + return true; } /** * Constructs and returns a decoded SDNA structure from the given encoded SDNA data block. */ -SDNA *DNA_sdna_from_data(const void *data, const int datalen, bool do_endian_swap) +SDNA *DNA_sdna_from_data( + const void *data, const int datalen, + bool do_endian_swap, bool data_alloc, + const char **r_error_message) { SDNA *sdna = MEM_mallocN(sizeof(*sdna), "sdna"); - - sdna->lastfind = 0; + const char *error_message = NULL; sdna->datalen = datalen; - sdna->data = MEM_mallocN(datalen, "sdna_data"); - memcpy(sdna->data, data, datalen); - - init_structDNA(sdna, do_endian_swap); + if (data_alloc) { + char *data_copy = MEM_mallocN(datalen, "sdna_data"); + memcpy(data_copy, data, datalen); + sdna->data = data_copy; + } + else { + sdna->data = data; + } + sdna->data_alloc = data_alloc; - return sdna; + + if (init_structDNA(sdna, do_endian_swap, &error_message)) { + return sdna; + } + else { + if (r_error_message == NULL) { + fprintf(stderr, "Error decoding blend file SDNA: %s\n", error_message); + } + else { + *r_error_message = error_message; + } + DNA_sdna_free(sdna); + return NULL; + } +} + +/** + * Using globals is acceptable here, the data is read-only and only changes between Blender versions. + * + * So it is safe to create once and reuse. + */ +static SDNA *g_sdna = NULL; + +void DNA_sdna_current_init(void) +{ + g_sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, NULL); +} + +const struct SDNA *DNA_sdna_current_get(void) +{ + BLI_assert(g_sdna != NULL); + return g_sdna; +} + +void DNA_sdna_current_free(void) +{ + DNA_sdna_free(g_sdna); + g_sdna = NULL; } /* ******************** END READ DNA ********************** */ @@ -610,7 +638,7 @@ static void recurs_test_compflags(const SDNA *sdna, char *compflags, int structn * - 1 Struct is the same (can be loaded with straight memory copy after any necessary endian conversion) * - 2 Struct is different in some way (needs to be copied/converted field by field) */ -char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna) +char *DNA_struct_get_compareflags(const SDNA *oldsdna, const SDNA *newsdna) { int a, b; const short *sp_old, *sp_new; @@ -627,14 +655,19 @@ char *DNA_struct_get_compareflags(SDNA *oldsdna, SDNA *newsdna) /* we check all structs in 'oldsdna' and compare them with * the structs in 'newsdna' */ + unsigned int newsdna_index_last = 0; for (a = 0; a < oldsdna->nr_structs; a++) { sp_old = oldsdna->structs[a]; /* search for type in cur */ - sp_new = findstruct_name(newsdna, oldsdna->types[sp_old[0]]); - - if (sp_new) { + int sp_new_index = DNA_struct_find_nr_ex(newsdna, oldsdna->types[sp_old[0]], &newsdna_index_last); + + /* The next indices will almost always match */ + newsdna_index_last++; + + if (sp_new_index != -1) { + sp_new = newsdna->structs[sp_new_index]; /* initial assumption */ compflags[a] = SDNA_CMP_NOT_EQUAL; @@ -1024,8 +1057,8 @@ static void reconstruct_elem( * \param cur Where to put converted struct contents */ static void reconstruct_struct( - SDNA *newsdna, - SDNA *oldsdna, + const SDNA *newsdna, + const SDNA *oldsdna, const char *compflags, int oldSDNAnr, @@ -1043,6 +1076,10 @@ static void reconstruct_struct( char *cpo, *cpc; const char *name, *nameo; + unsigned int oldsdna_index_last = UINT_MAX; + unsigned int cursdna_index_last = UINT_MAX; + + if (oldSDNAnr == -1) return; if (curSDNAnr == -1) return; @@ -1077,8 +1114,8 @@ static void reconstruct_struct( cpo = find_elem(oldsdna, type, name, spo, data, &sppo); if (cpo) { - oldSDNAnr = DNA_struct_find_nr(oldsdna, type); - curSDNAnr = DNA_struct_find_nr(newsdna, type); + oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last); + curSDNAnr = DNA_struct_find_nr_ex(newsdna, type, &cursdna_index_last); /* array! */ mul = DNA_elem_array_size(name); @@ -1119,15 +1156,16 @@ static void reconstruct_struct( * \param oldSDNAnr Index of struct info within oldsdna * \param data Struct data */ -void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) +void DNA_struct_switch_endian(const SDNA *oldsdna, int oldSDNAnr, char *data) { /* Recursive! * If element is a struct, call recursive. */ int a, mul, elemcount, elen, elena, firststructtypenr; const short *spo, *spc; - char *cpo, *cur, cval; + char *cur; const char *type, *name; + unsigned int oldsdna_index_last = UINT_MAX; if (oldSDNAnr == -1) return; firststructtypenr = *(oldsdna->structs[0]); @@ -1148,11 +1186,11 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) /* test: is type a struct? */ if (spc[0] >= firststructtypenr && !ispointer(name)) { - /* struct field type */ + /* struct field type */ /* where does the old data start (is there one?) */ - cpo = find_elem(oldsdna, type, name, spo, data, NULL); + char *cpo = find_elem(oldsdna, type, name, spo, data, NULL); if (cpo) { - oldSDNAnr = DNA_struct_find_nr(oldsdna, type); + oldSDNAnr = DNA_struct_find_nr_ex(oldsdna, type, &oldsdna_index_last); mul = DNA_elem_array_size(name); elena = elen / mul; @@ -1167,18 +1205,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) /* non-struct field type */ if (ispointer(name)) { if (oldsdna->pointerlen == 8) { - - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval; - cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval; - cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval; - cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval; - - cpo += 8; - } - + BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name)); } } else { @@ -1191,14 +1218,7 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) } if (skip == false) { - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; - cpo[0] = cpo[1]; - cpo[1] = cval; - cpo += 2; - } + BLI_endian_switch_int16_array((int16_t *)cur, DNA_elem_array_size(name)); } } else if (ELEM(spc[0], SDNA_TYPE_INT, SDNA_TYPE_FLOAT)) { @@ -1206,29 +1226,10 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) * but turns out we only used for runtime vars and * only once for a struct type thats no longer used. */ - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; - cpo[0] = cpo[3]; - cpo[3] = cval; - cval = cpo[1]; - cpo[1] = cpo[2]; - cpo[2] = cval; - cpo += 4; - } + BLI_endian_switch_int32_array((int32_t *)cur, DNA_elem_array_size(name)); } else if (ELEM(spc[0], SDNA_TYPE_INT64, SDNA_TYPE_UINT64, SDNA_TYPE_DOUBLE)) { - mul = DNA_elem_array_size(name); - cpo = cur; - while (mul--) { - cval = cpo[0]; cpo[0] = cpo[7]; cpo[7] = cval; - cval = cpo[1]; cpo[1] = cpo[6]; cpo[6] = cval; - cval = cpo[2]; cpo[2] = cpo[5]; cpo[5] = cval; - cval = cpo[3]; cpo[3] = cpo[4]; cpo[4] = cval; - - cpo += 8; - } + BLI_endian_switch_int64_array((int64_t *)cur, DNA_elem_array_size(name)); } } } @@ -1247,7 +1248,9 @@ void DNA_struct_switch_endian(SDNA *oldsdna, int oldSDNAnr, char *data) * \param data Array of struct data * \return An allocated reconstructed struct */ -void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int oldSDNAnr, int blocks, void *data) +void *DNA_struct_reconstruct( + const SDNA *newsdna, const SDNA *oldsdna, + char *compflags, int oldSDNAnr, int blocks, void *data) { int a, curSDNAnr, curlen = 0, oldlen; const short *spo, *spc; @@ -1287,7 +1290,6 @@ void *DNA_struct_reconstruct(SDNA *newsdna, SDNA *oldsdna, char *compflags, int */ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const char *name) { - const int SDNAnr = DNA_struct_find_nr(sdna, stype); const short * const spo = sdna->structs[SDNAnr]; const char * const cp = find_elem(sdna, vartype, name, spo, NULL, NULL); @@ -1297,7 +1299,6 @@ int DNA_elem_offset(SDNA *sdna, const char *stype, const char *vartype, const ch bool DNA_struct_elem_find(SDNA *sdna, const char *stype, const char *vartype, const char *name) { - const int SDNAnr = DNA_struct_find_nr(sdna, stype); if (SDNAnr != -1) { diff --git a/source/blender/makesdna/intern/makesdna.c b/source/blender/makesdna/intern/makesdna.c index fc94a8d9ff4..b78299316e1 100644 --- a/source/blender/makesdna/intern/makesdna.c +++ b/source/blender/makesdna/intern/makesdna.c @@ -968,7 +968,7 @@ void printStructLengths(void) } -static int make_structDNA(const char *baseDirectory, FILE *file) +static int make_structDNA(const char *baseDirectory, FILE *file, FILE *file_offsets) { int len, i; const short *sp; @@ -1159,6 +1159,19 @@ static int make_structDNA(const char *baseDirectory, FILE *file) /* end end padding test */ } + /* write a simple enum with all structs offsets, + * should only be accessed via SDNA_TYPE_FROM_STRUCT macro */ + { + fprintf(file_offsets, "#define SDNA_TYPE_FROM_STRUCT(id) _SDNA_TYPE_##id\n"); + fprintf(file_offsets, "enum {\n"); + for (i = 0; i < nr_structs; i++) { + const short *structpoin = structs[i]; + const int structtype = structpoin[0]; + fprintf(file_offsets, "\t_SDNA_TYPE_%s = %d,\n", types[structtype], i); + } + fprintf(file_offsets, "\tSDNA_TYPE_MAX = %d,\n", nr_structs); + fprintf(file_offsets, "};\n"); + } MEM_freeN(namedata); MEM_freeN(typedata); @@ -1190,43 +1203,53 @@ static void make_bad_file(const char *file, int line) int main(int argc, char **argv) { - FILE *file; int return_status = 0; - if (argc != 2 && argc != 3) { - printf("Usage: %s outfile.c [base directory]\n", argv[0]); + if (argc != 3 && argc != 4) { + printf("Usage: %s dna.c dna_struct_offsets.h [base directory]\n", argv[0]); return_status = 1; } else { - file = fopen(argv[1], "w"); - if (!file) { + FILE *file_dna = fopen(argv[1], "w"); + FILE *file_dna_offsets = fopen(argv[2], "w"); + if (!file_dna) { printf("Unable to open file: %s\n", argv[1]); return_status = 1; } + else if (!file_dna_offsets) { + printf("Unable to open file: %s\n", argv[2]); + return_status = 1; + } else { const char *baseDirectory; - if (argc == 3) { - baseDirectory = argv[2]; + if (argc == 4) { + baseDirectory = argv[3]; } else { baseDirectory = BASE_HEADER; } - fprintf(file, "const unsigned char DNAstr[] = {\n"); - if (make_structDNA(baseDirectory, file)) { + fprintf(file_dna, "const unsigned char DNAstr[] = {\n"); + if (make_structDNA(baseDirectory, file_dna, file_dna_offsets)) { /* error */ - fclose(file); + fclose(file_dna); + file_dna = NULL; make_bad_file(argv[1], __LINE__); return_status = 1; } else { - fprintf(file, "};\n"); - fprintf(file, "const int DNAlen = sizeof(DNAstr);\n"); - - fclose(file); + fprintf(file_dna, "};\n"); + fprintf(file_dna, "const int DNAlen = sizeof(DNAstr);\n"); } } + + if (file_dna) { + fclose(file_dna); + } + if (file_dna_offsets) { + fclose(file_dna_offsets); + } } diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index d8bea93bcbc..1d5f46a1814 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -285,6 +285,11 @@ typedef struct CollectionPointerLink { PointerRNA ptr; } CollectionPointerLink; +/* Copy of ListBase for RNA... */ +typedef struct CollectionListBase { + struct CollectionPointerLink *first, *last; +} CollectionListBase; + typedef enum RawPropertyType { PROP_RAW_UNSET = -1, PROP_RAW_INT, // XXX - abused for types that are not set, eg. MFace.verts, needs fixing. diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt index 29b55b861d3..2dee1fe3504 100644 --- a/source/blender/makesrna/intern/CMakeLists.txt +++ b/source/blender/makesrna/intern/CMakeLists.txt @@ -353,7 +353,10 @@ blender_include_dirs_sys( "${GLEW_INCLUDE_PATH}" ) +add_cc_flags_custom_test(makesrna) + add_executable(makesrna ${SRC} ${SRC_RNA_INC} ${SRC_DNA_INC}) + target_link_libraries(makesrna bf_dna) target_link_libraries(makesrna bf_dna_blenlib) diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index 099a1f1a544..b2355206071 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -227,6 +227,10 @@ static const char *rna_safe_id(const char *id) return "operator_value"; else if (STREQ(id, "new")) return "create"; + else if (STREQ(id, "co_return")) { + /* MSVC2015, C++ uses for coroutines */ + return "coord_return"; + } return id; } @@ -466,7 +470,7 @@ static const char *rna_parameter_type_name(PropertyRNA *parm) } case PROP_COLLECTION: { - return "ListBase"; + return "CollectionListBase"; } default: return "<error, no type specified>"; diff --git a/source/blender/makesrna/intern/rna_ID.c b/source/blender/makesrna/intern/rna_ID.c index 63ea836e3de..332ca190a08 100644 --- a/source/blender/makesrna/intern/rna_ID.c +++ b/source/blender/makesrna/intern/rna_ID.c @@ -87,10 +87,13 @@ EnumPropertyItem rna_enum_id_type_items[] = { #include "DNA_anim_types.h" +#include "BLI_listbase.h" + #include "BKE_font.h" #include "BKE_idprop.h" #include "BKE_library.h" #include "BKE_library_query.h" +#include "BKE_library_remap.h" #include "BKE_animsys.h" #include "BKE_material.h" #include "BKE_depsgraph.h" @@ -274,11 +277,11 @@ StructRNA *rna_PropertyGroup_refine(PointerRNA *ptr) return ptr->type; } -static ID *rna_ID_copy(ID *id) +static ID *rna_ID_copy(ID *id, Main *bmain) { ID *newid; - if (id_copy(id, &newid, false)) { + if (id_copy(bmain, id, &newid, false)) { if (newid) id_us_min(newid); return newid; } @@ -333,6 +336,14 @@ static void rna_ID_user_clear(ID *id) id->us = 0; /* don't save */ } +static void rna_ID_user_remap(ID *id, Main *bmain, ID *new_id) +{ + if (GS(id->name) == GS(new_id->name)) { + /* For now, do not allow remapping data in linked data from here... */ + BKE_libblock_remap(bmain, id, new_id, ID_REMAP_SKIP_INDIRECT_USAGE | ID_REMAP_SKIP_NEVER_NULL_USAGE); + } +} + static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) { AnimData *adt = BKE_animdata_add_id(id); @@ -342,7 +353,7 @@ static AnimData * rna_ID_animation_data_create(ID *id, Main *bmain) static void rna_ID_animation_data_free(ID *id, Main *bmain) { - BKE_animdata_free(id); + BKE_animdata_free(id, true); DAG_relations_tag_update(bmain); } @@ -687,7 +698,7 @@ static void rna_ImagePreview_icon_pixels_float_set(PointerRNA *ptr, const float static int rna_ImagePreview_icon_id_get(PointerRNA *ptr) { /* Using a callback here allows us to only generate icon matching that preview when icon_id is requested. */ - return BKE_icon_preview_ensure((PreviewImage *)(ptr->data)); + return BKE_icon_preview_ensure(ptr->id.data, (PreviewImage *)(ptr->data)); } static void rna_ImagePreview_icon_reload(PreviewImage *prv) { @@ -970,6 +981,7 @@ static void rna_def_ID(BlenderRNA *brna) /* functions */ func = RNA_def_function(srna, "copy", "rna_ID_copy"); RNA_def_function_ui_description(func, "Create a copy of this data-block (not supported for all data-blocks)"); + RNA_def_function_flag(func, FUNC_USE_MAIN); parm = RNA_def_pointer(func, "id", "ID", "", "New copy of the ID"); RNA_def_function_return(func, parm); @@ -977,6 +989,12 @@ static void rna_def_ID(BlenderRNA *brna) RNA_def_function_ui_description(func, "Clear the user count of a data-block so its not saved, " "on reload the data will be removed"); + func = RNA_def_function(srna, "user_remap", "rna_ID_user_remap"); + RNA_def_function_ui_description(func, "Replace all usage in the .blend file of this ID by new given one"); + RNA_def_function_flag(func, FUNC_USE_MAIN); + parm = RNA_def_pointer(func, "new_id", "ID", "", "New ID to use"); + RNA_def_property_flag(parm, PROP_NEVER_NULL); + func = RNA_def_function(srna, "user_of_id", "BKE_library_ID_use_ID"); RNA_def_function_ui_description(func, "Count the number of times that ID uses/references given one"); parm = RNA_def_pointer(func, "id", "ID", "", "ID to count usages"); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index c49a6197a4e..5a93e18a7dd 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1624,7 +1624,7 @@ bool RNA_property_editable(PointerRNA *ptr, PropertyRNA *prop) flag = prop->editable ? prop->editable(ptr) : prop->flag; return ((flag & PROP_EDITABLE) && (flag & PROP_REGISTER) == 0 && - (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION))); + (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION))); } bool RNA_property_editable_flag(PointerRNA *ptr, PropertyRNA *prop) @@ -1656,13 +1656,13 @@ bool RNA_property_editable_index(PointerRNA *ptr, PropertyRNA *prop, int index) id = ptr->id.data; - return (flag & PROP_EDITABLE) && (!id || !id->lib || (prop->flag & PROP_LIB_EXCEPTION)); + return (flag & PROP_EDITABLE) && (!id || !ID_IS_LINKED_DATABLOCK(id) || (prop->flag & PROP_LIB_EXCEPTION)); } bool RNA_property_animateable(PointerRNA *ptr, PropertyRNA *prop) { /* check that base ID-block can support animation data */ - if (!id_type_can_have_animdata(ptr->id.data)) + if (!id_can_have_animdata(ptr->id.data)) return false; prop = rna_ensure_property(prop); @@ -3127,8 +3127,11 @@ void RNA_property_collection_add(PointerRNA *ptr, PropertyRNA *prop, PointerRNA RNA_parameter_list_free(¶ms); } } - /*else - printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier);*/ +#if 0 + else { + printf("%s %s.%s: not implemented for this property.\n", __func__, ptr->type->identifier, prop->identifier); + } +#endif #endif if (r_ptr) { @@ -3187,8 +3190,11 @@ bool RNA_property_collection_remove(PointerRNA *ptr, PropertyRNA *prop, int key) return false; } - /*else - printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier);*/ +#if 0 + else { + printf("%s %s.%s: only supported for id properties.\n", __func__, ptr->type->identifier, prop->identifier); + } +#endif #endif return false; } @@ -4678,7 +4684,7 @@ static void rna_path_array_multi_string_from_flat_index( } /** - * \param index_dim: The dimensiuon to show, 0 disables. 1 for 1d array, 2 for 2d. etc. + * \param index_dim: The dimension to show, 0 disables. 1 for 1d array, 2 for 2d. etc. * \param index: The *flattened* index to use when \a ``index_dim > 0``, * this is expanded when used with multi-dimensional arrays. */ diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 7c21ce95a1d..8d7e47e8402 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -308,6 +308,14 @@ static void rna_def_dopesheet(BlenderRNA *brna) RNA_def_property_ui_icon(prop, ICON_GHOST_ENABLED, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + prop = RNA_def_property(srna, "use_datablock_sort", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", ADS_FLAG_NO_DB_SORT); + RNA_def_property_ui_text(prop, "Sort Datablocks", + "Alphabetically sorts datablocks - mainly objects in the scene " + "(disable to increase viewport speed)"); + RNA_def_property_ui_icon(prop, ICON_SORTALPHA, 0); + RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); + /* Debug Filtering Settings */ prop = RNA_def_property(srna, "show_only_errors", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_ONLY_ERRORS); @@ -706,7 +714,8 @@ static void rna_def_action(BlenderRNA *brna) prop = RNA_def_property(srna, "pose_markers", PROP_COLLECTION, PROP_NONE); RNA_def_property_collection_sdna(prop, NULL, "markers", NULL); RNA_def_property_struct_type(prop, "TimelineMarker"); - RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); /* T45689 - so that the list isn't greyed out; adding/removing is still banned though */ + /* Use lib exception so the list isn't grayed out; adding/removing is still banned though, see T45689 */ + RNA_def_property_flag(prop, PROP_LIB_EXCEPTION); RNA_def_property_ui_text(prop, "Pose Markers", "Markers specific to this action, for labeling poses"); rna_def_action_pose_markers(brna, prop); diff --git a/source/blender/makesrna/intern/rna_camera.c b/source/blender/makesrna/intern/rna_camera.c index 678b0ac8f1f..492430fbda6 100644 --- a/source/blender/makesrna/intern/rna_camera.c +++ b/source/blender/makesrna/intern/rna_camera.c @@ -257,13 +257,15 @@ void RNA_def_camera(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipsta"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip Start", "Camera near clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "clipend"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_ui_text(prop, "Clip End", "Camera far clipping distance"); RNA_def_property_update(prop, NC_OBJECT | ND_DRAW, NULL); diff --git a/source/blender/makesrna/intern/rna_color.c b/source/blender/makesrna/intern/rna_color.c index 440a57b5c29..1910493b933 100644 --- a/source/blender/makesrna/intern/rna_color.c +++ b/source/blender/makesrna/intern/rna_color.c @@ -1018,10 +1018,11 @@ static void rna_def_scopes(BlenderRNA *brna) static EnumPropertyItem prop_wavefrm_mode_items[] = { {SCOPES_WAVEFRM_LUMA, "LUMA", ICON_COLOR, "Luma", ""}, - {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""}, + {SCOPES_WAVEFRM_RGB_PARADE, "PARADE", ICON_COLOR, "Parade", ""}, {SCOPES_WAVEFRM_YCC_601, "YCBCR601", ICON_COLOR, "YCbCr (ITU 601)", ""}, {SCOPES_WAVEFRM_YCC_709, "YCBCR709", ICON_COLOR, "YCbCr (ITU 709)", ""}, {SCOPES_WAVEFRM_YCC_JPEG, "YCBCRJPG", ICON_COLOR, "YCbCr (Jpeg)", ""}, + {SCOPES_WAVEFRM_RGB, "RGB", ICON_COLOR, "Red Green Blue", ""}, {0, NULL, 0, NULL, NULL} }; diff --git a/source/blender/makesrna/intern/rna_curve.c b/source/blender/makesrna/intern/rna_curve.c index cb7a40a9238..fb4ff6f4856 100644 --- a/source/blender/makesrna/intern/rna_curve.c +++ b/source/blender/makesrna/intern/rna_curve.c @@ -952,23 +952,37 @@ static void rna_def_nurbs(BlenderRNA *UNUSED(brna), StructRNA *srna) static void rna_def_font(BlenderRNA *UNUSED(brna), StructRNA *srna) { PropertyRNA *prop; - + static EnumPropertyItem prop_align_items[] = { - {CU_LEFT, "LEFT", 0, "Left", "Align text to the left"}, - {CU_MIDDLE, "CENTER", 0, "Center", "Center text"}, - {CU_RIGHT, "RIGHT", 0, "Right", "Align text to the right"}, - {CU_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"}, - {CU_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"}, + {CU_ALIGN_X_LEFT, "LEFT", 0, "Left", "Align text to the left"}, + {CU_ALIGN_X_MIDDLE, "CENTER", 0, "Center", "Center text"}, + {CU_ALIGN_X_RIGHT, "RIGHT", 0, "Right", "Align text to the right"}, + {CU_ALIGN_X_JUSTIFY, "JUSTIFY", 0, "Justify", "Align to the left and the right"}, + {CU_ALIGN_X_FLUSH, "FLUSH", 0, "Flush", "Align to the left and the right, with equal character spacing"}, {0, NULL, 0, NULL, NULL} }; - + + static EnumPropertyItem prop_align_y_items[] = { + {CU_ALIGN_Y_TOP_BASELINE, "TOP_BASELINE", 0, "Top Base-Line", "Align to top but use the base-line of the text"}, + {CU_ALIGN_Y_TOP, "TOP", 0, "Top", "Align text to the top"}, + {CU_ALIGN_Y_CENTER, "CENTER", 0, "Center", "Align text to the middle"}, + {CU_ALIGN_Y_BOTTOM, "BOTTOM", 0, "Bottom", "Align text to the bottom"}, + {0, NULL, 0, NULL, NULL} + }; + /* Enums */ - prop = RNA_def_property(srna, "align", PROP_ENUM, PROP_NONE); + prop = RNA_def_property(srna, "align_x", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "spacemode"); RNA_def_property_enum_items(prop, prop_align_items); - RNA_def_property_ui_text(prop, "Text Align", "Text align from the object center"); + RNA_def_property_ui_text(prop, "Text Horizontal Align", "Text horizontal align from the object center"); RNA_def_property_update(prop, 0, "rna_Curve_update_data"); - + + prop = RNA_def_property(srna, "align_y", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "align_y"); + RNA_def_property_enum_items(prop, prop_align_y_items); + RNA_def_property_ui_text(prop, "Text Vertical Align", "Text vertical align from the object center"); + RNA_def_property_update(prop, 0, "rna_Curve_update_data"); + /* number values */ prop = RNA_def_property(srna, "size", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "fsize"); diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index 36e2b9b0572..7ff4eaea169 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -531,12 +531,18 @@ BlenderRNA *RNA_create(void) BlenderRNA *brna; brna = MEM_callocN(sizeof(BlenderRNA), "BlenderRNA"); + const char *error_message = NULL; - DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false); BLI_listbase_clear(&DefRNA.structs); DefRNA.error = 0; DefRNA.preprocess = 1; + DefRNA.sdna = DNA_sdna_from_data(DNAstr, DNAlen, false, false, &error_message); + if (DefRNA.sdna == NULL) { + fprintf(stderr, "Error decoding SDNA: %s\n", error_message); + DefRNA.error = 1; + } + return brna; } diff --git a/source/blender/makesrna/intern/rna_fcurve.c b/source/blender/makesrna/intern/rna_fcurve.c index 1487dfa074e..5fb581eb74a 100644 --- a/source/blender/makesrna/intern/rna_fcurve.c +++ b/source/blender/makesrna/intern/rna_fcurve.c @@ -72,6 +72,7 @@ EnumPropertyItem rna_enum_fmodifier_type_items[] = { EnumPropertyItem rna_enum_beztriple_keyframe_type_items[] = { {BEZT_KEYTYPE_KEYFRAME, "KEYFRAME", VICO_KEYTYPE_KEYFRAME_VEC, "Keyframe", "Normal keyframe - e.g. for key poses"}, {BEZT_KEYTYPE_BREAKDOWN, "BREAKDOWN", VICO_KEYTYPE_BREAKDOWN_VEC, "Breakdown", "A breakdown pose - e.g. for transitions between key poses"}, + {BEZT_KEYTYPE_MOVEHOLD, "MOVING_HOLD", VICO_KEYTYPE_MOVING_HOLD_VEC, "Moving Hold", "A keyframe that is part of a moving hold"}, {BEZT_KEYTYPE_EXTREME, "EXTREME", VICO_KEYTYPE_EXTREME_VEC, "Extreme", "An 'extreme' pose, or some other purpose as needed"}, {BEZT_KEYTYPE_JITTER, "JITTER", VICO_KEYTYPE_JITTER_VEC, "Jitter", "A filler or baked keyframe for keying on ones, or some other purpose as needed"}, {0, NULL, 0, NULL, NULL} @@ -1844,6 +1845,8 @@ static void rna_def_fcurve(BlenderRNA *brna) "Cycle through the rainbow, trying to give each curve a unique color"}, {FCURVE_COLOR_AUTO_RGB, "AUTO_RGB", 0, "Auto XYZ to RGB", "Use axis colors for transform and color properties, and auto-rainbow for the rest"}, + {FCURVE_COLOR_AUTO_YRGB, "AUTO_YRGB", 0, "Auto WXYZ to YRGB", + "Use axis colors for XYZ parts of transform, and yellow for the 'W' channel"}, {FCURVE_COLOR_CUSTOM, "CUSTOM", 0, "User Defined", "Use custom hand-picked color for F-Curve"}, {0, NULL, 0, NULL, NULL} diff --git a/source/blender/makesrna/intern/rna_fluidsim.c b/source/blender/makesrna/intern/rna_fluidsim.c index 16e0f17eac5..091950a8e66 100644 --- a/source/blender/makesrna/intern/rna_fluidsim.c +++ b/source/blender/makesrna/intern/rna_fluidsim.c @@ -204,18 +204,6 @@ static char *rna_FluidSettings_path(PointerRNA *ptr) return BLI_sprintfN("modifiers[\"%s\"].settings", name_esc); } -static void rna_FluidMeshVertex_data_begin(CollectionPropertyIterator *iter, PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - rna_iterator_array_begin(iter, fss->meshVelocities, sizeof(float) * 3, fss->totvert, 0, NULL); -} - -static int rna_FluidMeshVertex_data_length(PointerRNA *ptr) -{ - FluidsimSettings *fss = (FluidsimSettings *)ptr->data; - return fss->totvert; -} - #else static void rna_def_fluidsim_slip(StructRNA *srna) @@ -251,9 +239,8 @@ static void rna_def_fluid_mesh_vertices(BlenderRNA *brna) StructRNA *srna; PropertyRNA *prop; - srna = RNA_def_struct(brna, "FluidMeshVertex", NULL); - RNA_def_struct_sdna(srna, "FluidVertexVelocity"); - RNA_def_struct_ui_text(srna, "Fluid Mesh Vertex", "Vertex of a simulated fluid mesh"); + srna = RNA_def_struct(brna, "FluidVertexVelocity", NULL); + RNA_def_struct_ui_text(srna, "Fluid Mesh Velocity", "Velocity of a simulated fluid mesh"); RNA_def_struct_ui_icon(srna, ICON_VERTEXSEL); prop = RNA_def_property(srna, "velocity", PROP_FLOAT, PROP_VELOCITY); @@ -442,11 +429,10 @@ static void rna_def_fluidsim_domain(BlenderRNA *brna) /* simulated fluid mesh data */ prop = RNA_def_property(srna, "fluid_mesh_vertices", PROP_COLLECTION, PROP_NONE); - RNA_def_property_struct_type(prop, "FluidMeshVertex"); + RNA_def_property_collection_sdna(prop, NULL, "meshVelocities", "totvert"); + RNA_def_property_struct_type(prop, "FluidVertexVelocity"); RNA_def_property_ui_text(prop, "Fluid Mesh Vertices", "Vertices of the fluid mesh generated by simulation"); - RNA_def_property_collection_funcs(prop, "rna_FluidMeshVertex_data_begin", "rna_iterator_array_next", - "rna_iterator_array_end", "rna_iterator_array_get", - "rna_FluidMeshVertex_data_length", NULL, NULL, NULL); + rna_def_fluid_mesh_vertices(brna); } diff --git a/source/blender/makesrna/intern/rna_main_api.c b/source/blender/makesrna/intern/rna_main_api.c index 4b7ce640a56..0083207efd0 100644 --- a/source/blender/makesrna/intern/rna_main_api.c +++ b/source/blender/makesrna/intern/rna_main_api.c @@ -58,9 +58,11 @@ #include "BKE_armature.h" #include "BKE_lamp.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_object.h" #include "BKE_material.h" #include "BKE_icons.h" +#include "BKE_idcode.h" #include "BKE_image.h" #include "BKE_texture.h" #include "BKE_scene.h" @@ -113,30 +115,38 @@ # include "BPY_extern.h" #endif + +static void rna_Main_ID_remove(Main *bmain, ReportList *reports, PointerRNA *id_ptr, int do_unlink) +{ + ID *id = id_ptr->data; + if (do_unlink) { + BKE_libblock_delete(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else if (ID_REAL_USERS(id) <= 0) { + BKE_libblock_free(bmain, id); + RNA_POINTER_INVALIDATE(id_ptr); + } + else { + BKE_reportf(reports, RPT_ERROR, + "%s '%s' must have zero users to be removed, found %d (try with do_unlink=True parameter)", + BKE_idcode_to_name(GS(id->name)), id->name + 2, ID_REAL_USERS(id)); + } +} + + static Camera *rna_Main_cameras_new(Main *bmain, const char *name) { ID *id = BKE_camera_add(bmain, name); id_us_min(id); return (Camera *)id; } -static void rna_Main_cameras_remove(Main *bmain, ReportList *reports, PointerRNA *camera_ptr) -{ - Camera *camera = camera_ptr->data; - if (ID_REAL_USERS(camera) <= 0) { - BKE_libblock_free(bmain, camera); - RNA_POINTER_INVALIDATE(camera_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Camera '%s' must have zero users to be removed, found %d", - camera->id.name + 2, ID_REAL_USERS(camera)); - } -} static Scene *rna_Main_scenes_new(Main *bmain, const char *name) { return BKE_scene_add(bmain, name); } -static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr) +static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports, PointerRNA *scene_ptr, int do_unlink) { /* don't call BKE_libblock_free(...) directly */ Scene *scene = scene_ptr->data; @@ -145,23 +155,23 @@ static void rna_Main_scenes_remove(Main *bmain, bContext *C, ReportList *reports if ((scene_new = scene->id.prev) || (scene_new = scene->id.next)) { - bScreen *sc = CTX_wm_screen(C); - if (sc->scene == scene) { + if (do_unlink) { + bScreen *sc = CTX_wm_screen(C); + if (sc->scene == scene) { #ifdef WITH_PYTHON - BPy_BEGIN_ALLOW_THREADS; + BPy_BEGIN_ALLOW_THREADS; #endif - ED_screen_set_scene(C, sc, scene_new); + ED_screen_set_scene(C, sc, scene_new); #ifdef WITH_PYTHON - BPy_END_ALLOW_THREADS; + BPy_END_ALLOW_THREADS; #endif + } } - - BKE_scene_unlink(bmain, scene, scene_new); - RNA_POINTER_INVALIDATE(scene_ptr); + rna_Main_ID_remove(bmain, reports, scene_ptr, do_unlink); } else { BKE_reportf(reports, RPT_ERROR, "Scene '%s' is the last, cannot be removed", scene->id.name + 2); @@ -217,43 +227,17 @@ static Object *rna_Main_objects_new(Main *bmain, ReportList *reports, const char id_us_min(&ob->id); ob->data = data; - test_object_materials(bmain, ob->data); + test_object_materials(ob, ob->data); return ob; } -static void rna_Main_objects_remove(Main *bmain, ReportList *reports, PointerRNA *object_ptr) -{ - Object *object = object_ptr->data; - if (ID_REAL_USERS(object) <= 0) { - BKE_object_unlink(bmain, object); /* needed or ID pointers to this are not cleared */ - BKE_libblock_free(bmain, object); - RNA_POINTER_INVALIDATE(object_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Object '%s' must have zero users to be removed, found %d", - object->id.name + 2, ID_REAL_USERS(object)); - } -} - static Material *rna_Main_materials_new(Main *bmain, const char *name) { ID *id = (ID *)BKE_material_add(bmain, name); id_us_min(id); return (Material *)id; } -static void rna_Main_materials_remove(Main *bmain, ReportList *reports, PointerRNA *material_ptr) -{ - Material *material = material_ptr->data; - if (ID_REAL_USERS(material) <= 0) { - BKE_libblock_free(bmain, material); - RNA_POINTER_INVALIDATE(material_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Material '%s' must have zero users to be removed, found %d", - material->id.name + 2, ID_REAL_USERS(material)); - } -} static EnumPropertyItem *rna_Main_nodetree_type_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) { @@ -271,18 +255,6 @@ static struct bNodeTree *rna_Main_nodetree_new(Main *bmain, const char *name, in else return NULL; } -static void rna_Main_nodetree_remove(Main *bmain, ReportList *reports, PointerRNA *ntree_ptr) -{ - bNodeTree *ntree = ntree_ptr->data; - if (ID_REAL_USERS(ntree) <= 0) { - BKE_libblock_free(bmain, ntree); - RNA_POINTER_INVALIDATE(ntree_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Node tree '%s' must have zero users to be removed, found %d", - ntree->id.name + 2, ID_REAL_USERS(ntree)); - } -} static Mesh *rna_Main_meshes_new(Main *bmain, const char *name) { @@ -312,19 +284,6 @@ Mesh *rna_Main_meshes_new_from_object( return BKE_mesh_new_from_object(bmain, sce, ob, apply_modifiers, settings, calc_tessface, calc_undeformed); } -static void rna_Main_meshes_remove(Main *bmain, ReportList *reports, PointerRNA *mesh_ptr) -{ - Mesh *mesh = mesh_ptr->data; - if (ID_REAL_USERS(mesh) <= 0) { - BKE_libblock_free(bmain, mesh); - RNA_POINTER_INVALIDATE(mesh_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Mesh '%s' must have zero users to be removed, found %d", - mesh->id.name + 2, ID_REAL_USERS(mesh)); - } -} - static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) { Lamp *lamp = BKE_lamp_add(bmain, name); @@ -332,18 +291,6 @@ static Lamp *rna_Main_lamps_new(Main *bmain, const char *name, int type) id_us_min(&lamp->id); return lamp; } -static void rna_Main_lamps_remove(Main *bmain, ReportList *reports, PointerRNA *lamp_ptr) -{ - Lamp *lamp = lamp_ptr->data; - if (ID_REAL_USERS(lamp) <= 0) { - BKE_libblock_free(bmain, lamp); - RNA_POINTER_INVALIDATE(lamp_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lamp '%s' must have zero users to be removed, found %d", - lamp->id.name + 2, ID_REAL_USERS(lamp)); - } -} static Image *rna_Main_images_new(Main *bmain, const char *name, int width, int height, int alpha, int float_buffer, int stereo3d) { @@ -372,18 +319,6 @@ static Image *rna_Main_images_load(Main *bmain, ReportList *reports, const char id_us_min((ID *)ima); return ima; } -static void rna_Main_images_remove(Main *bmain, ReportList *reports, PointerRNA *image_ptr) -{ - Image *image = image_ptr->data; - if (ID_REAL_USERS(image) <= 0) { - BKE_libblock_free(bmain, image); - RNA_POINTER_INVALIDATE(image_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Image '%s' must have zero users to be removed, found %d", - image->id.name + 2, ID_REAL_USERS(image)); - } -} static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) { @@ -391,18 +326,6 @@ static Lattice *rna_Main_lattices_new(Main *bmain, const char *name) id_us_min(<->id); return lt; } -static void rna_Main_lattices_remove(Main *bmain, ReportList *reports, PointerRNA *lt_ptr) -{ - Lattice *lt = lt_ptr->data; - if (ID_REAL_USERS(lt) <= 0) { - BKE_libblock_free(bmain, lt); - RNA_POINTER_INVALIDATE(lt_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Lattice '%s' must have zero users to be removed, found %d", - lt->id.name + 2, ID_REAL_USERS(lt)); - } -} static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) { @@ -410,18 +333,6 @@ static Curve *rna_Main_curves_new(Main *bmain, const char *name, int type) id_us_min(&cu->id); return cu; } -static void rna_Main_curves_remove(Main *bmain, ReportList *reports, PointerRNA *cu_ptr) -{ - Curve *cu = cu_ptr->data; - if (ID_REAL_USERS(cu) <= 0) { - BKE_libblock_free(bmain, cu); - RNA_POINTER_INVALIDATE(cu_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Curve '%s' must have zero users to be removed, found %d", - cu->id.name + 2, ID_REAL_USERS(cu)); - } -} static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) { @@ -429,18 +340,6 @@ static MetaBall *rna_Main_metaballs_new(Main *bmain, const char *name) id_us_min(&mb->id); return mb; } -static void rna_Main_metaballs_remove(Main *bmain, ReportList *reports, PointerRNA *mb_ptr) -{ - MetaBall *mb = mb_ptr->data; - if (ID_REAL_USERS(mb) <= 0) { - BKE_libblock_free(bmain, mb); - RNA_POINTER_INVALIDATE(mb_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Metaball '%s' must have zero users to be removed, found %d", - mb->id.name + 2, ID_REAL_USERS(mb)); - } -} static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -462,18 +361,6 @@ static VFont *rna_Main_fonts_load(Main *bmain, ReportList *reports, const char * return font; } -static void rna_Main_fonts_remove(Main *bmain, ReportList *reports, PointerRNA *vfont_ptr) -{ - VFont *vfont = vfont_ptr->data; - if (ID_REAL_USERS(vfont) <= 0) { - BKE_libblock_free(bmain, vfont); - RNA_POINTER_INVALIDATE(vfont_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Font '%s' must have zero users to be removed, found %d", - vfont->id.name + 2, ID_REAL_USERS(vfont)); - } -} static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) { @@ -482,18 +369,6 @@ static Tex *rna_Main_textures_new(Main *bmain, const char *name, int type) id_us_min(&tex->id); return tex; } -static void rna_Main_textures_remove(Main *bmain, ReportList *reports, PointerRNA *tex_ptr) -{ - Tex *tex = tex_ptr->data; - if (ID_REAL_USERS(tex) <= 0) { - BKE_libblock_free(bmain, tex); - RNA_POINTER_INVALIDATE(tex_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Texture '%s' must have zero users to be removed, found %d", - tex->id.name + 2, ID_REAL_USERS(tex)); - } -} static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) { @@ -502,50 +377,17 @@ static Brush *rna_Main_brushes_new(Main *bmain, const char *name, int mode) return brush; } -static void rna_Main_brushes_remove(Main *bmain, ReportList *reports, PointerRNA *brush_ptr) -{ - Brush *brush = brush_ptr->data; - if (ID_REAL_USERS(brush) <= 0) { - BKE_brush_unlink(bmain, brush); - BKE_libblock_free(bmain, brush); - RNA_POINTER_INVALIDATE(brush_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Brush '%s' must have zero users to be removed, found %d", - brush->id.name + 2, ID_REAL_USERS(brush)); - } -} - static World *rna_Main_worlds_new(Main *bmain, const char *name) { World *world = add_world(bmain, name); id_us_min(&world->id); return world; } -static void rna_Main_worlds_remove(Main *bmain, ReportList *reports, PointerRNA *world_ptr) -{ - Group *world = world_ptr->data; - if (ID_REAL_USERS(world) <= 0) { - BKE_libblock_free(bmain, world); - RNA_POINTER_INVALIDATE(world_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "World '%s' must have zero users to be removed, found %d", - world->id.name + 2, ID_REAL_USERS(world)); - } -} static Group *rna_Main_groups_new(Main *bmain, const char *name) { return BKE_group_add(bmain, name); } -static void rna_Main_groups_remove(Main *bmain, PointerRNA *group_ptr) -{ - Group *group = group_ptr->data; - BKE_group_unlink(bmain, group); - BKE_libblock_free(bmain, group); - RNA_POINTER_INVALIDATE(group_ptr); -} static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) { @@ -553,18 +395,6 @@ static Speaker *rna_Main_speakers_new(Main *bmain, const char *name) id_us_min(&speaker->id); return speaker; } -static void rna_Main_speakers_remove(Main *bmain, ReportList *reports, PointerRNA *speaker_ptr) -{ - Speaker *speaker = speaker_ptr->data; - if (ID_REAL_USERS(speaker) <= 0) { - BKE_libblock_free(bmain, speaker); - RNA_POINTER_INVALIDATE(speaker_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Speaker '%s' must have zero users to be removed, found %d", - speaker->id.name + 2, ID_REAL_USERS(speaker)); - } -} static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_existing) { @@ -580,30 +410,11 @@ static bSound *rna_Main_sounds_load(Main *bmain, const char *name, int check_exi id_us_min(&sound->id); return sound; } -static void rna_Main_sounds_remove(Main *bmain, ReportList *reports, PointerRNA *sound_ptr) -{ - Speaker *sound = sound_ptr->data; - if (ID_REAL_USERS(sound) <= 0) { - BKE_libblock_free(bmain, sound); - RNA_POINTER_INVALIDATE(sound_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Sound '%s' must have zero users to be removed, found %d", - sound->id.name + 2, ID_REAL_USERS(sound)); - } -} static Text *rna_Main_texts_new(Main *bmain, const char *name) { return BKE_text_add(bmain, name); } -static void rna_Main_texts_remove(Main *bmain, PointerRNA *text_ptr) -{ - Text *text = text_ptr->data; - BKE_text_unlink(bmain, text); - BKE_libblock_free(bmain, text); - RNA_POINTER_INVALIDATE(text_ptr); -} static Text *rna_Main_texts_load(Main *bmain, ReportList *reports, const char *filepath, int is_internal) { @@ -625,18 +436,6 @@ static bArmature *rna_Main_armatures_new(Main *bmain, const char *name) id_us_min(&arm->id); return arm; } -static void rna_Main_armatures_remove(Main *bmain, ReportList *reports, PointerRNA *arm_ptr) -{ - bArmature *arm = arm_ptr->data; - if (ID_REAL_USERS(arm) <= 0) { - BKE_libblock_free(bmain, arm); - RNA_POINTER_INVALIDATE(arm_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Armature '%s' must have zero users to be removed, found %d", - arm->id.name + 2, ID_REAL_USERS(arm)); - } -} static bAction *rna_Main_actions_new(Main *bmain, const char *name) { @@ -644,18 +443,6 @@ static bAction *rna_Main_actions_new(Main *bmain, const char *name) id_fake_user_clear(&act->id); return act; } -static void rna_Main_actions_remove(Main *bmain, ReportList *reports, PointerRNA *act_ptr) -{ - bAction *act = act_ptr->data; - if (ID_REAL_USERS(act) <= 0) { - BKE_libblock_free(bmain, act); - RNA_POINTER_INVALIDATE(act_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Action '%s' must have zero users to be removed, found %d", - act->id.name + 2, ID_REAL_USERS(act)); - } -} static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) { @@ -663,18 +450,6 @@ static ParticleSettings *rna_Main_particles_new(Main *bmain, const char *name) id_us_min(&part->id); return part; } -static void rna_Main_particles_remove(Main *bmain, ReportList *reports, PointerRNA *part_ptr) -{ - ParticleSettings *part = part_ptr->data; - if (ID_REAL_USERS(part) <= 0) { - BKE_libblock_free(bmain, part); - RNA_POINTER_INVALIDATE(part_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Particle settings '%s' must have zero users to be removed, found %d", - part->id.name + 2, ID_REAL_USERS(part)); - } -} static Palette *rna_Main_palettes_new(Main *bmain, const char *name) { @@ -682,18 +457,6 @@ static Palette *rna_Main_palettes_new(Main *bmain, const char *name) id_us_min(&palette->id); return (Palette *)palette; } -static void rna_Main_palettes_remove(Main *bmain, ReportList *reports, PointerRNA *palette_ptr) -{ - Palette *palette = palette_ptr->data; - if (ID_REAL_USERS(palette) <= 0) { - BKE_libblock_free(bmain, palette); - RNA_POINTER_INVALIDATE(palette_ptr); - } - else { - BKE_reportf(reports, RPT_ERROR, "Palette settings '%s' must have zero users to be removed, found %d", - palette->id.name + 2, ID_REAL_USERS(palette)); - } -} static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, const char *filepath, int check_existing) { @@ -716,14 +479,6 @@ static MovieClip *rna_Main_movieclip_load(Main *bmain, ReportList *reports, cons return clip; } -static void rna_Main_movieclips_remove(Main *bmain, PointerRNA *clip_ptr) -{ - MovieClip *clip = clip_ptr->data; - BKE_movieclip_unlink(bmain, clip); - BKE_libblock_free(bmain, clip); - RNA_POINTER_INVALIDATE(clip_ptr); -} - static Mask *rna_Main_mask_new(Main *bmain, const char *name) { Mask *mask; @@ -733,27 +488,6 @@ static Mask *rna_Main_mask_new(Main *bmain, const char *name) return mask; } -static void rna_Main_masks_remove(Main *bmain, PointerRNA *mask_ptr) -{ - Mask *mask = mask_ptr->data; - BKE_mask_free(bmain, mask); - BKE_libblock_free(bmain, mask); - RNA_POINTER_INVALIDATE(mask_ptr); -} - -static void rna_Main_grease_pencil_remove(Main *bmain, ReportList *reports, PointerRNA *gpd_ptr) -{ - bGPdata *gpd = gpd_ptr->data; - if (ID_REAL_USERS(gpd) <= 0) { - BKE_gpencil_free(gpd); - BKE_libblock_free(bmain, gpd); - RNA_POINTER_INVALIDATE(gpd_ptr); - } - else - BKE_reportf(reports, RPT_ERROR, "Grease pencil '%s' must have zero users to be removed, found %d", - gpd->id.name + 2, ID_REAL_USERS(gpd)); -} - static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name) { FreestyleLineStyle *linestyle = BKE_linestyle_new(bmain, name); @@ -761,17 +495,6 @@ static FreestyleLineStyle *rna_Main_linestyles_new(Main *bmain, const char *name return linestyle; } -static void rna_Main_linestyles_remove(Main *bmain, ReportList *reports, FreestyleLineStyle *linestyle) -{ - if (ID_REAL_USERS(linestyle) <= 0) - BKE_libblock_free(bmain, linestyle); - else - BKE_reportf(reports, RPT_ERROR, "Line style '%s' must have zero users to be removed, found %d", - linestyle->id.name + 2, ID_REAL_USERS(linestyle)); - - /* XXX python now has invalid pointer? */ -} - /* tag and is_updated functions, all the same */ #define RNA_MAIN_ID_TAG_FUNCS_DEF(_func_name, _listbase_name, _id_type) \ static void rna_Main_##_func_name##_tag(Main *bmain, int value) { \ @@ -854,12 +577,15 @@ void RNA_def_main_cameras(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "camera", "Camera", "", "New camera data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_cameras_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a camera from the current blendfile"); parm = RNA_def_pointer(func, "camera", "Camera", "", "Camera to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this camera before deleting it " + "(WARNING: will also delete objects instancing that camera data)"); func = RNA_def_function(srna, "tag", "rna_Main_cameras_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -896,6 +622,7 @@ void RNA_def_main_scenes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "scene", "Scene", "", "Scene to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this scene before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_scenes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -930,12 +657,13 @@ void RNA_def_main_objects(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "object", "Object", "", "New object data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_objects_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a object from the current blendfile"); RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "object", "Object", "", "Object to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this object before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_objects_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -966,12 +694,13 @@ void RNA_def_main_materials(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "material", "Material", "", "New material data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_materials_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a material from the current blendfile"); parm = RNA_def_pointer(func, "material", "Material", "", "Material to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this material before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_materials_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1009,12 +738,13 @@ void RNA_def_main_node_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "tree", "NodeTree", "", "New node tree data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_nodetree_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a node tree from the current blendfile"); parm = RNA_def_pointer(func, "tree", "NodeTree", "", "Node tree to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this node tree before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_node_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1067,12 +797,15 @@ void RNA_def_main_meshes(BlenderRNA *brna, PropertyRNA *cprop) "Mesh created from object, remove it if it is only used for export"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_meshes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a mesh from the current blendfile"); parm = RNA_def_pointer(func, "mesh", "Mesh", "", "Mesh to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this mesh before deleting it " + "(WARNING: will also delete objects instancing that mesh data)"); func = RNA_def_function(srna, "tag", "rna_Main_meshes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1104,12 +837,15 @@ void RNA_def_main_lamps(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lamp", "Lamp", "", "New lamp data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lamps_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lamp from the current blendfile"); parm = RNA_def_pointer(func, "lamp", "Lamp", "", "Lamp to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lamp before deleting it " + "(WARNING: will also delete objects instancing that lamp data)"); func = RNA_def_function(srna, "tag", "rna_Main_lamps_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1219,12 +955,13 @@ void RNA_def_main_images(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "image", "Image", "", "New image data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_images_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove an image from the current blendfile"); parm = RNA_def_pointer(func, "image", "Image", "", "Image to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this image before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_images_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1255,12 +992,15 @@ void RNA_def_main_lattices(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "lattice", "Lattice", "", "New lattices data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_lattices_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a lattice from the current blendfile"); parm = RNA_def_pointer(func, "lattice", "Lattice", "", "Lattice to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this lattice before deleting it " + "(WARNING: will also delete objects instancing that lattice data)"); func = RNA_def_function(srna, "tag", "rna_Main_lattices_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1292,12 +1032,15 @@ void RNA_def_main_curves(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "curve", "Curve", "", "New curve data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_curves_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a curve from the current blendfile"); parm = RNA_def_pointer(func, "curve", "Curve", "", "Curve to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this curve before deleting it " + "(WARNING: will also delete objects instancing that curve data)"); func = RNA_def_function(srna, "tag", "rna_Main_curves_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1327,12 +1070,15 @@ void RNA_def_main_metaballs(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "New metaball data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_metaballs_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a metaball from the current blendfile"); parm = RNA_def_pointer(func, "metaball", "MetaBall", "", "Metaball to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this metaball before deleting it " + "(WARNING: will also delete objects instancing that metaball data)"); func = RNA_def_function(srna, "tag", "rna_Main_metaballs_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1364,12 +1110,13 @@ void RNA_def_main_fonts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "New font data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_fonts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a font from the current blendfile"); parm = RNA_def_pointer(func, "vfont", "VectorFont", "", "Font to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this font before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_fonts_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1401,12 +1148,13 @@ void RNA_def_main_textures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "texture", "Texture", "", "New texture data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_textures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a texture from the current blendfile"); parm = RNA_def_pointer(func, "texture", "Texture", "", "Texture to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this texture before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_textures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1437,12 +1185,13 @@ void RNA_def_main_brushes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "brush", "Brush", "", "New brush data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_brushes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a brush from the current blendfile"); parm = RNA_def_pointer(func, "brush", "Brush", "", "Brush to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this brush before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_brushes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1473,12 +1222,13 @@ void RNA_def_main_worlds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "world", "World", "", "New world data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_worlds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a world from the current blendfile"); parm = RNA_def_pointer(func, "world", "World", "", "World to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this world before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_worlds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1509,11 +1259,13 @@ void RNA_def_main_groups(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "group", "Group", "", "New group data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_groups_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a group from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "group", "Group", "", "Group to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this group before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_groups_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1544,12 +1296,15 @@ void RNA_def_main_speakers(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "speaker", "Speaker", "", "New speaker data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_speakers_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a speaker from the current blendfile"); parm = RNA_def_pointer(func, "speaker", "Speaker", "", "Speaker to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this speaker before deleting it " + "(WARNING: will also delete objects instancing that speaker data)"); func = RNA_def_function(srna, "tag", "rna_Main_speakers_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1580,11 +1335,13 @@ void RNA_def_main_texts(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "text", "Text", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_texts_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_ui_description(func, "Remove a text from the current blendfile"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); parm = RNA_def_pointer(func, "text", "Text", "", "Text to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this text before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_texts_load"); @@ -1628,12 +1385,13 @@ void RNA_def_main_sounds(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "sound", "Sound", "", "New text data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_sounds_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a sound from the current blendfile"); parm = RNA_def_pointer(func, "sound", "Sound", "", "Sound to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this sound before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_sounds_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1664,12 +1422,15 @@ void RNA_def_main_armatures(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "armature", "Armature", "", "New armature data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_armatures_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a armature from the current blendfile"); parm = RNA_def_pointer(func, "armature", "Armature", "", "Armature to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", + "Unlink all usages of this armature before deleting it " + "(WARNING: will also delete objects instancing that armature data)"); func = RNA_def_function(srna, "tag", "rna_Main_armatures_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1699,12 +1460,13 @@ void RNA_def_main_actions(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "action", "Action", "", "New action data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_actions_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a action from the current blendfile"); parm = RNA_def_pointer(func, "action", "Action", "", "Action to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this action before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_actions_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1734,12 +1496,13 @@ void RNA_def_main_particles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "New particle settings data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_particles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a particle settings instance from the current blendfile"); parm = RNA_def_pointer(func, "particle", "ParticleSettings", "", "Particle Settings to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of those particle settings before deleting them"); func = RNA_def_function(srna, "tag", "rna_Main_particles_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1769,12 +1532,13 @@ void RNA_def_main_palettes(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "palette", "Palette", "", "New palette data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_palettes_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a palette from the current blendfile"); parm = RNA_def_pointer(func, "palette", "Palette", "", "Palette to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this palette before deleting it"); func = RNA_def_function(srna, "tag", "rna_Main_palettes_tag"); parm = RNA_def_boolean(func, "value", 0, "Value", ""); @@ -1808,12 +1572,13 @@ void RNA_def_main_gpencil(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "New grease pencil data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_grease_pencil_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a grease pencil instance from the current blendfile"); parm = RNA_def_pointer(func, "grease_pencil", "GreasePencil", "", "Grease Pencil to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this grease pencil before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1836,11 +1601,13 @@ void RNA_def_main_movieclips(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_boolean(func, "value", 0, "Value", ""); RNA_def_property_flag(parm, PROP_REQUIRED); - func = RNA_def_function(srna, "remove", "rna_Main_movieclips_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a movie clip from the current blendfile."); parm = RNA_def_pointer(func, "clip", "MovieClip", "", "Movie clip to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this movie clip before deleting it"); /* load func */ func = RNA_def_function(srna, "load", "rna_Main_movieclip_load"); @@ -1886,11 +1653,13 @@ void RNA_def_main_masks(BlenderRNA *brna, PropertyRNA *cprop) RNA_def_function_return(func, parm); /* remove func */ - func = RNA_def_function(srna, "remove", "rna_Main_masks_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); + RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a masks from the current blendfile."); parm = RNA_def_pointer(func, "mask", "Mask", "", "Mask to remove"); RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this mask before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); @@ -1921,11 +1690,13 @@ void RNA_def_main_linestyles(BlenderRNA *brna, PropertyRNA *cprop) parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "New line style data-block"); RNA_def_function_return(func, parm); - func = RNA_def_function(srna, "remove", "rna_Main_linestyles_remove"); + func = RNA_def_function(srna, "remove", "rna_Main_ID_remove"); RNA_def_function_flag(func, FUNC_USE_REPORTS); RNA_def_function_ui_description(func, "Remove a line style instance from the current blendfile"); parm = RNA_def_pointer(func, "linestyle", "FreestyleLineStyle", "", "Line style to remove"); - RNA_def_property_flag(parm, PROP_REQUIRED); + RNA_def_property_flag(parm, PROP_REQUIRED | PROP_NEVER_NULL | PROP_RNAPTR); + RNA_def_property_clear_flag(parm, PROP_THICK_WRAP); + RNA_def_boolean(func, "do_unlink", false, "", "Unlink all usages of this line style before deleting it"); prop = RNA_def_property(srna, "is_updated", PROP_BOOLEAN, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5a2113f3f95..a23ef6eaa82 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1514,6 +1514,8 @@ static void rna_def_modifier_decimate(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + /* Note, keep in sync with operator 'MESH_OT_decimate' */ + StructRNA *srna; PropertyRNA *prop; @@ -1826,6 +1828,12 @@ static void rna_def_modifier_hook(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Hook Center", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "matrix_inverse", PROP_FLOAT, PROP_MATRIX); + RNA_def_property_float_sdna(prop, NULL, "parentinv"); + RNA_def_property_multi_array(prop, 2, rna_matrix_dimsize_4x4); + RNA_def_property_ui_text(prop, "Matrix", "Reverse the transformation between this object and its target"); + RNA_def_property_update(prop, NC_OBJECT | ND_TRANSFORM, "rna_Modifier_update"); + prop = RNA_def_property(srna, "object", PROP_POINTER, PROP_NONE); RNA_def_property_ui_text(prop, "Object", "Parent Object for hook, also recalculates and clears offset"); RNA_def_property_flag(prop, PROP_EDITABLE | PROP_ID_SELF_CHECK); @@ -1887,6 +1895,12 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) {0, NULL, 0, NULL, NULL} }; + static EnumPropertyItem prop_solver_items[] = { + {eBooleanModifierSolver_BMesh, "BMESH", 0, "BMesh", "Use the BMesh boolean solver"}, + {eBooleanModifierSolver_Carve, "CARVE", 0, "Carve", "Use the Carve boolean solver"}, + {0, NULL, 0, NULL, NULL} + }; + srna = RNA_def_struct(brna, "BooleanModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Boolean Modifier", "Boolean operations modifier"); RNA_def_struct_sdna(srna, "BooleanModifierData"); @@ -1903,35 +1917,17 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Operation", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); -#if 0 /* WITH_MOD_BOOLEAN */ - /* BMesh intersection options */ - prop = RNA_def_property(srna, "use_bmesh", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_Enabled); - RNA_def_property_ui_text(prop, "Use BMesh", "Use BMesh boolean calculation"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "use_bmesh_separate", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_Separate); - RNA_def_property_ui_text(prop, "Separate", "Keep edges separate"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "use_bmesh_dissolve", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoDissolve); - RNA_def_property_ui_text(prop, "Dissolve", "Dissolve verts created from tessellated intersection"); + prop = RNA_def_property(srna, "solver", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, prop_solver_items); + RNA_def_property_ui_text(prop, "Solver", ""); RNA_def_property_update(prop, 0, "rna_Modifier_update"); - prop = RNA_def_property(srna, "use_bmesh_connect_regions", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_negative_sdna(prop, NULL, "bm_flag", eBooleanModifierBMeshFlag_BMesh_NoConnectRegions); - RNA_def_property_ui_text(prop, "Calculate Holes", "Connect regions (needed for hole filling)"); - RNA_def_property_update(prop, 0, "rna_Modifier_update"); - - prop = RNA_def_property(srna, "threshold", PROP_FLOAT, PROP_DISTANCE); - RNA_def_property_float_sdna(prop, NULL, "threshold"); + prop = RNA_def_property(srna, "double_threshold", PROP_FLOAT, PROP_DISTANCE); + RNA_def_property_float_sdna(prop, NULL, "double_threshold"); RNA_def_property_range(prop, 0, 1.0f); - RNA_def_property_ui_range(prop, 0, 1, 1, 7); - RNA_def_property_ui_text(prop, "Threshold", ""); + RNA_def_property_ui_range(prop, 0, 1, 0.0001, 7); + RNA_def_property_ui_text(prop, "Overlap Threshold", "Threshold for checking overlapping geometry"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); -#endif } static void rna_def_modifier_array(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index d493e55fd64..33148549c45 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -3277,12 +3277,14 @@ static EnumPropertyItem node_glossy_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {0, NULL, 0, NULL, NULL} }; static EnumPropertyItem node_anisotropic_items[] = { {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, {SHD_GLOSSY_ASHIKHMIN_SHIRLEY, "ASHIKHMIN_SHIRLEY", 0, "Ashikhmin-Shirley", ""}, {0, NULL, 0, NULL, NULL} }; @@ -3291,6 +3293,14 @@ static EnumPropertyItem node_glass_items[] = { {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, + {SHD_GLOSSY_MULTI_GGX, "MULTI_GGX", 0, "Multiscatter GGX", ""}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem node_refraction_items[] = { + {SHD_GLOSSY_SHARP, "SHARP", 0, "Sharp", ""}, + {SHD_GLOSSY_BECKMANN, "BECKMANN", 0, "Beckmann", ""}, + {SHD_GLOSSY_GGX, "GGX", 0, "GGX", ""}, {0, NULL, 0, NULL, NULL} }; @@ -4243,6 +4253,17 @@ static void def_glass(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_refraction(StructRNA *srna) +{ + PropertyRNA *prop; + + prop = RNA_def_property(srna, "distribution", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "custom1"); + RNA_def_property_enum_items(prop, node_refraction_items); + RNA_def_property_ui_text(prop, "Distribution", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_anisotropic(StructRNA *srna) { PropertyRNA *prop; @@ -6749,7 +6770,8 @@ static void def_cmp_translate(StructRNA *srna) prop = RNA_def_property(srna, "use_relative", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "relative", 1); - RNA_def_property_ui_text(prop, "Relative", "Use relative (percent) values to define blur radius"); + RNA_def_property_ui_text(prop, "Relative", + "Use relative (fraction of input image size) values to define translation"); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "wrap_axis", PROP_ENUM, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index 281ca91d085..e50824da5e9 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -399,7 +399,7 @@ static void rna_Object_data_set(PointerRNA *ptr, PointerRNA value) id_us_plus(id); ob->data = id; - test_object_materials(G.main, id); + test_object_materials(ob, id); if (GS(id->name) == ID_CU) BKE_curve_type_test(ob); @@ -719,10 +719,10 @@ static int rna_Object_active_material_editable(PointerRNA *ptr) bool is_editable; if ((ob->matbits == NULL) || (ob->actcol == 0) || ob->matbits[ob->actcol - 1]) { - is_editable = (ob->id.lib == NULL); + is_editable = !ID_IS_LINKED_DATABLOCK(ob); } else { - is_editable = ob->data ? (((ID *)ob->data)->lib == NULL) : false; + is_editable = ob->data ? !ID_IS_LINKED_DATABLOCK(ob->data) : false; } return is_editable ? PROP_EDITABLE : 0; @@ -1034,7 +1034,7 @@ static void rna_GameObjectSettings_physics_type_set(PointerRNA *ptr, int value) ob->gameflag &= ~(OB_SENSOR | OB_OCCLUDER | OB_DYNAMIC | OB_RIGID_BODY | OB_SOFT_BODY | OB_ACTOR | OB_ANISOTROPIC_FRICTION | OB_DO_FH | OB_ROT_FH | OB_COLLISION_RESPONSE | OB_NAVMESH); /* When we switch to character physics and the collision bounds is set to triangle mesh - we have to change collision bounds because triangle mesh is not supported by Characters*/ + * we have to change collision bounds because triangle mesh is not supported by Characters */ if ((ob->gameflag & OB_BOUNDS) && ob->collision_boundtype == OB_BOUND_TRIANGLE_MESH) { ob->boundtype = ob->collision_boundtype = OB_BOUND_BOX; } diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 3f401a29945..a52473b95f2 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -341,7 +341,7 @@ static void rna_ParticleSystem_co_hair(ParticleSystem *particlesystem, Object *o totchild = (int)((float)particlesystem->totchild * (float)(part->disp) / 100.0f); } - if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem)) + if (part == NULL || pars == NULL || !psys_check_enabled(object, particlesystem, particlesystem->renderdata != NULL)) return; if (part->ren_as == PART_DRAW_OB || part->ren_as == PART_DRAW_GR || part->ren_as == PART_DRAW_NOT) @@ -586,7 +586,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc psys_render_set(object, particlesystem, mat, mat, 1, 1, 0.f); psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(scene, object, particlesystem); + particle_system_update(scene, object, particlesystem, true); } else { ParticleSystemModifierData *psmd = psys_get_modifier(object, particlesystem); @@ -596,7 +596,7 @@ static void rna_ParticleSystem_set_resolution(ParticleSystem *particlesystem, Sc } psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(scene, object, particlesystem); + particle_system_update(scene, object, particlesystem, false); } } @@ -2635,35 +2635,35 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_float_sdna(prop, NULL, "normfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Normal", "Let the surface normal give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "obfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Object", "Let the object give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "factor_random", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "randfac"); /*optional if prop names are the same */ RNA_def_property_range(prop, 0.0f, 200.0f); RNA_def_property_ui_range(prop, 0, 100, 1, 3); - RNA_def_property_ui_text(prop, "Random", "Give the starting speed a random variation"); + RNA_def_property_ui_text(prop, "Random", "Give the starting velocity a random variation"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "particle_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "partfac"); RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -1.0f, 1.0f, 0.1, 3); - RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Particle", "Let the target particle give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_factor", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "tanfac"); RNA_def_property_range(prop, -1000.0f, 1000.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 2); - RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting speed"); + RNA_def_property_ui_text(prop, "Tangent", "Let the surface tangent give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "tangent_phase", PROP_FLOAT, PROP_NONE); @@ -2677,7 +2677,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -10.0f, 10.0f); RNA_def_property_ui_text(prop, "Reactor", "Let the vector away from the target particle's location give the particle " - "a starting speed"); + "a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "object_align_factor", PROP_FLOAT, PROP_VELOCITY); @@ -2686,7 +2686,7 @@ static void rna_def_particle_settings(BlenderRNA *brna) RNA_def_property_range(prop, -200.0f, 200.0f); RNA_def_property_ui_range(prop, -100, 100, 1, 3); RNA_def_property_ui_text(prop, "Object Aligned", - "Let the emitter object orientation give the particle a starting speed"); + "Let the emitter object orientation give the particle a starting velocity"); RNA_def_property_update(prop, 0, "rna_Particle_reset"); prop = RNA_def_property(srna, "angular_velocity_factor", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 533c0f86460..d1f8c4e5bed 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -841,21 +841,12 @@ static int rna_RenderSettings_save_buffers_get(PointerRNA *ptr) RenderData *rd = (RenderData *)ptr->data; Scene *scene = (Scene *)ptr->id.data; - if (rd->mode & R_BORDER) - return 0; - else if (!BKE_scene_use_new_shading_nodes(scene)) + if (!BKE_scene_use_new_shading_nodes(scene)) return (rd->scemode & (R_EXR_TILE_FILE | R_FULL_SAMPLE)) != 0; else return (rd->scemode & R_EXR_TILE_FILE) != 0; } -static int rna_RenderSettings_full_sample_get(PointerRNA *ptr) -{ - RenderData *rd = (RenderData *)ptr->data; - - return (rd->scemode & R_FULL_SAMPLE) && !(rd->mode & R_BORDER); -} - static void rna_ImageFormatSettings_file_format_set(PointerRNA *ptr, int value) { ImageFormatData *imf = (ImageFormatData *)ptr->data; @@ -4381,6 +4372,11 @@ static void rna_def_scene_game_data(BlenderRNA *brna) "Use extra textures like normal or specular maps for GLSL rendering"); RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); + prop = RNA_def_property(srna, "use_glsl_environment_lighting", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_GLSL_NO_ENV_LIGHTING); + RNA_def_property_ui_text(prop, "GLSL Environment Lighting", "Use environment lighting for GLSL rendering"); + RNA_def_property_update(prop, NC_SCENE | NA_EDITED, "rna_Scene_glsl_update"); + prop = RNA_def_property(srna, "use_material_caching", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", GAME_NO_MATERIAL_CACHING); RNA_def_property_ui_text(prop, "Use Material Caching", @@ -5763,7 +5759,6 @@ static void rna_def_scene_render_data(BlenderRNA *brna) prop = RNA_def_property(srna, "use_full_sample", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "scemode", R_FULL_SAMPLE); - RNA_def_property_boolean_funcs(prop, "rna_RenderSettings_full_sample_get", NULL); RNA_def_property_ui_text(prop, "Full Sample", "Save for every anti-aliasing sample the entire RenderLayer results " "(this solves anti-aliasing issues with compositing)"); diff --git a/source/blender/makesrna/intern/rna_scene_api.c b/source/blender/makesrna/intern/rna_scene_api.c index c3c66625c84..1d3537dc9a0 100644 --- a/source/blender/makesrna/intern/rna_scene_api.c +++ b/source/blender/makesrna/intern/rna_scene_api.c @@ -196,7 +196,7 @@ static void rna_Scene_collada_export( int use_ngons, int use_object_instantiation, - int use_blender_profile, + int use_blender_profile, int sort_by_name, int export_transformation_type, int open_sim) diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 2c9ebdd27fe..df589bb1bf1 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -1803,7 +1803,7 @@ static void rna_FileBrowser_FSMenu_active_range( static void rna_FileBrowser_FSMenu_active_update(struct bContext *C, PointerRNA *UNUSED(ptr)) { - ED_file_change_dir(C, true); + ED_file_change_dir(C); } static int rna_FileBrowser_FSMenuSystem_active_get(PointerRNA *ptr) @@ -2447,14 +2447,16 @@ static void rna_def_space_view3d(BlenderRNA *brna) prop = RNA_def_property(srna, "clip_start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "near"); - RNA_def_property_range(prop, 0.001f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 0.1f); RNA_def_property_ui_text(prop, "Clip Start", "3D View near clipping distance (perspective view only)"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); prop = RNA_def_property(srna, "clip_end", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "far"); - RNA_def_property_range(prop, 1.0f, FLT_MAX); + RNA_def_property_range(prop, 1e-6f, FLT_MAX); + RNA_def_property_ui_range(prop, 0.001f, FLT_MAX, 10, 3); RNA_def_property_float_default(prop, 1000.0f); RNA_def_property_ui_text(prop, "Clip End", "3D View far clipping distance"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_VIEW3D, NULL); @@ -3611,6 +3613,12 @@ static void rna_def_space_nla(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Show Control F-Curves", "Show influence F-Curves on strips"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL); + prop = RNA_def_property(srna, "show_local_markers", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOLOCALMARKERS); + RNA_def_property_ui_text(prop, "Show Local Markers", + "Show action-local markers on the strips, useful when synchronising timing across strips"); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NLA, NULL); + /* editing */ prop = RNA_def_property(srna, "use_realtime_update", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SNLA_NOREALTIMEUPDATES); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index 5a1607aa7c7..cbf7bb4d5e0 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -94,6 +94,13 @@ EnumPropertyItem rna_enum_navigation_mode_items[] = { {0, NULL, 0, NULL, NULL} }; +#if defined(WITH_INTERNATIONAL) || !defined(RNA_RUNTIME) +static EnumPropertyItem rna_enum_language_default_items[] = { + {0, "DEFAULT", 0, "Default (Default)", ""}, + {0, NULL, 0, NULL, NULL} +}; +#endif + #ifdef RNA_RUNTIME #include "DNA_object_types.h" @@ -642,7 +649,11 @@ static EnumPropertyItem *rna_userdef_audio_device_itemf(bContext *UNUSED(C), Poi static EnumPropertyItem *rna_lang_enum_properties_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *UNUSED(r_free)) { - return BLT_lang_RNA_enum_properties(); + EnumPropertyItem *items = BLT_lang_RNA_enum_properties(); + if (items == NULL) { + items = rna_enum_language_default_items; + } + return items; } #endif @@ -2779,6 +2790,13 @@ static void rna_def_userdef_theme_space_action(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Keyframe Border Selected", "Color of selected keyframe border"); RNA_def_property_update(prop, 0, "rna_userdef_update"); + prop = RNA_def_property(srna, "keyframe_scale_factor", PROP_FLOAT, PROP_NONE); + RNA_def_property_float_sdna(prop, NULL, "keyframe_scale_fac"); + RNA_def_property_float_default(prop, 1.0f); + RNA_def_property_ui_text(prop, "Keyframe Scale Factor", "Scale factor for adjusting the height of keyframes"); + RNA_def_property_range(prop, 0.8f, 5.0f); /* Note: These limits prevent buttons overlapping (min), and excessive size... (max) */ + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_DOPESHEET, "rna_userdef_update"); + prop = RNA_def_property(srna, "summary", PROP_FLOAT, PROP_COLOR_GAMMA); RNA_def_property_float_sdna(prop, NULL, "anim_active"); @@ -3971,11 +3989,6 @@ static void rna_def_userdef_system(BlenderRNA *brna) {USER_MULTISAMPLE_16, "16", 0, "MultiSample: 16", "Use 16x OpenGL MultiSample (requires restart)"}, {0, NULL, 0, NULL, NULL} }; - - static EnumPropertyItem language_items[] = { - {0, "DEFAULT", 0, "Default (Default)", ""}, - {0, NULL, 0, NULL, NULL} - }; #ifdef WITH_CYCLES static EnumPropertyItem compute_device_items[] = { @@ -4058,7 +4071,7 @@ static void rna_def_userdef_system(BlenderRNA *brna) /* Language Selection */ prop = RNA_def_property(srna, "language", PROP_ENUM, PROP_NONE); - RNA_def_property_enum_items(prop, language_items); + RNA_def_property_enum_items(prop, rna_enum_language_default_items); #ifdef WITH_INTERNATIONAL RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_lang_enum_properties_itemf"); #endif diff --git a/source/blender/makesrna/intern/rna_wm.c b/source/blender/makesrna/intern/rna_wm.c index 0d11414c878..026d2e209a3 100644 --- a/source/blender/makesrna/intern/rna_wm.c +++ b/source/blender/makesrna/intern/rna_wm.c @@ -469,13 +469,15 @@ EnumPropertyItem rna_enum_wm_report_items[] = { static wmOperator *rna_OperatorProperties_find_operator(PointerRNA *ptr) { wmWindowManager *wm = ptr->id.data; - IDProperty *properties = (IDProperty *)ptr->data; - wmOperator *op; - if (wm) - for (op = wm->operators.first; op; op = op->next) - if (op->properties == properties) + if (wm) { + IDProperty *properties = (IDProperty *)ptr->data; + for (wmOperator *op = wm->operators.last; op; op = op->prev) { + if (op->properties == properties) { return op; + } + } + } return NULL; } diff --git a/source/blender/makesrna/intern/rna_world.c b/source/blender/makesrna/intern/rna_world.c index f950ba75c42..7c1ef6b0d87 100644 --- a/source/blender/makesrna/intern/rna_world.c +++ b/source/blender/makesrna/intern/rna_world.c @@ -102,8 +102,7 @@ static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), Poi } #endif -/* so camera mist limits redraw */ -static void rna_World_draw_mist_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) +static void rna_World_draw_update(Main *UNUSED(bmain), Scene *UNUSED(scene), PointerRNA *ptr) { World *wo = ptr->id.data; @@ -264,19 +263,19 @@ static void rna_def_lighting(BlenderRNA *brna) prop = RNA_def_property(srna, "use_environment_light", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_ENV_LIGHT); RNA_def_property_ui_text(prop, "Use Environment Lighting", "Add light coming from the environment"); - RNA_def_property_update(prop, 0, "rna_World_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "environment_energy", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "ao_env_energy"); RNA_def_property_ui_range(prop, 0, FLT_MAX, 1, 3); RNA_def_property_ui_text(prop, "Environment Color", "Defines the strength of environment light"); - RNA_def_property_update(prop, 0, "rna_World_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "environment_color", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "aocolor"); RNA_def_property_enum_items(prop, prop_color_items); RNA_def_property_ui_text(prop, "Environment Color", "Defines where the color of the environment light comes from"); - RNA_def_property_update(prop, 0, "rna_World_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); /* indirect lighting */ prop = RNA_def_property(srna, "use_indirect_light", PROP_BOOLEAN, PROP_NONE); @@ -405,27 +404,27 @@ static void rna_def_world_mist(BlenderRNA *brna) prop = RNA_def_property(srna, "use_mist", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "mode", WO_MIST); RNA_def_property_ui_text(prop, "Use Mist", "Occlude objects with the environment color as they are further away"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "intensity", PROP_FLOAT, PROP_NONE); RNA_def_property_float_sdna(prop, NULL, "misi"); RNA_def_property_range(prop, 0, 1); RNA_def_property_ui_text(prop, "Minimum", "Overall minimum intensity of the mist effect"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "start", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "miststa"); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 10000, 10, 2); RNA_def_property_ui_text(prop, "Start", "Starting distance of the mist, measured from the camera"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "depth", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "mistdist"); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 10000, 10, 2); RNA_def_property_ui_text(prop, "Depth", "Distance over which the mist effect fades in"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "height", PROP_FLOAT, PROP_DISTANCE); RNA_def_property_float_sdna(prop, NULL, "misthi"); @@ -437,7 +436,7 @@ static void rna_def_world_mist(BlenderRNA *brna) RNA_def_property_enum_sdna(prop, NULL, "mistype"); RNA_def_property_enum_items(prop, falloff_items); RNA_def_property_ui_text(prop, "Falloff", "Type of transition used to fade mist"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); } void RNA_def_world(BlenderRNA *brna) @@ -462,19 +461,19 @@ void RNA_def_world(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Horizon Color", "Color at the horizon"); /* RNA_def_property_update(prop, 0, "rna_World_update"); */ /* render-only uses this */ - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "zenith_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "zenr"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Zenith Color", "Color at the zenith"); - RNA_def_property_update(prop, NC_WORLD | ND_WORLD_DRAW, "rna_World_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); prop = RNA_def_property(srna, "ambient_color", PROP_FLOAT, PROP_COLOR); RNA_def_property_float_sdna(prop, NULL, "ambr"); RNA_def_property_array(prop, 3); RNA_def_property_ui_text(prop, "Ambient Color", "Ambient color of the world"); - RNA_def_property_update(prop, 0, "rna_World_draw_mist_update"); + RNA_def_property_update(prop, 0, "rna_World_draw_update"); /* exp, range */ prop = RNA_def_property(srna, "exposure", PROP_FLOAT, PROP_NONE); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index cb313a75c3e..13a8ec927a3 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -33,7 +33,7 @@ */ // #ifdef DEBUG_TIME -// #define USE_BMESH +#define USE_BMESH #ifdef WITH_MOD_BOOLEAN # define USE_CARVE WITH_MOD_BOOLEAN #endif @@ -71,6 +71,14 @@ #include "PIL_time_utildefines.h" #endif +static void initData(ModifierData *md) +{ + BooleanModifierData *bmd = (BooleanModifierData *)md; + + bmd->solver = eBooleanModifierSolver_BMesh; + bmd->double_threshold = 1e-6f; +} + static void copyData(ModifierData *md, ModifierData *target) { #if 0 @@ -222,7 +230,9 @@ static DerivedMesh *applyModifier_bmesh( #ifdef DEBUG_TIME TIMEIT_START(boolean_bmesh); #endif - bm = BM_mesh_create(&allocsize); + bm = BM_mesh_create( + &allocsize, + &((struct BMeshCreateParams){.use_toolflags = false,})); DM_to_bmesh_ex(dm_other, bm, true); DM_to_bmesh_ex(dm, bm, true); @@ -296,16 +306,21 @@ static DerivedMesh *applyModifier_bmesh( * currently this is ok for 'BM_mesh_intersect' */ // BM_mesh_normals_update(bm); + /* change for testing */ + bool use_separate = false; + bool use_dissolve = true; + bool use_island_connect = true; + BM_mesh_intersect( bm, looptris, tottri, bm_face_isect_pair, NULL, false, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_Separate) != 0, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoDissolve) == 0, - (bmd->bm_flag & eBooleanModifierBMeshFlag_BMesh_NoConnectRegions) == 0, + use_separate, + use_dissolve, + use_island_connect, bmd->operation, - bmd->threshold); + bmd->double_threshold); MEM_freeN(looptris); } @@ -409,15 +424,14 @@ static DerivedMesh *applyModifier( ModifierApplyFlag flag) { BooleanModifierData *bmd = (BooleanModifierData *)md; - const int method = (bmd->bm_flag & eBooleanModifierBMeshFlag_Enabled) ? 1 : 0; - switch (method) { + switch (bmd->solver) { #ifdef USE_CARVE - case 0: + case eBooleanModifierSolver_Carve: return applyModifier_carve(md, ob, derivedData, flag); #endif #ifdef USE_BMESH - case 1: + case eBooleanModifierSolver_BMesh: return applyModifier_bmesh(md, ob, derivedData, flag); #endif default: @@ -441,7 +455,7 @@ ModifierTypeInfo modifierType_Boolean = { /* deformMatricesEM */ NULL, /* applyModifier */ applyModifier, /* applyModifierEM */ NULL, - /* initData */ NULL, + /* initData */ initData, /* requiredDataMask */ requiredDataMask, /* freeData */ NULL, /* isDisabled */ isDisabled, diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c index 4046620592b..77fd84a2948 100644 --- a/source/blender/modifiers/intern/MOD_correctivesmooth.c +++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c @@ -1,29 +1,29 @@ /* -* ***** BEGIN GPL LICENSE BLOCK ***** -* -* This program is free software; you can redistribute it and/or -* modify it under the terms of the GNU General Public License -* as published by the Free Software Foundation; either version 2 -* of the License, or (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. -* -* The Original Code is Copyright (C) 2015 by the Blender Foundation. -* All rights reserved. -* -* Contributor(s): Jack Simpson, -* Campbell Barton -* -* ***** END GPL LICENSE BLOCK ***** -* -*/ + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2005 by the Blender Foundation. + * All rights reserved. + * + * Contributor(s): Jack Simpson, + * Campbell Barton + * + * ***** END GPL LICENSE BLOCK ***** + * + */ /** \file blender/modifiers/intern/MOD_correctivesmooth.c * \ingroup modifiers @@ -319,7 +319,7 @@ static void smooth_iter__length_weight( /* fast-path */ for (i = 0; i < numVerts; i++) { struct SmoothingData_Weighted *sd = &smooth_data[i]; - /* divide by sum of all neighbour distances (weighted) and amount of neighbours, (mean average) */ + /* divide by sum of all neighbour distances (weighted) and amount of neighbors, (mean average) */ const float div = sd->edge_length_sum * vertex_edge_count[i]; if (div > eps) { #if 0 diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c index 4791e41d433..d8cccca415c 100644 --- a/source/blender/modifiers/intern/MOD_particlesystem.c +++ b/source/blender/modifiers/intern/MOD_particlesystem.c @@ -101,7 +101,7 @@ static void deformVerts(ModifierData *md, Object *ob, DerivedMesh *derivedData, float (*vertexCos)[3], int UNUSED(numVerts), - ModifierApplyFlag UNUSED(flag)) + ModifierApplyFlag flag) { DerivedMesh *dm = derivedData; ParticleSystemModifierData *psmd = (ParticleSystemModifierData *) md; @@ -114,7 +114,7 @@ static void deformVerts(ModifierData *md, Object *ob, else return; - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, (flag & MOD_APPLY_RENDER) != 0)) return; if (dm == NULL) { @@ -186,7 +186,7 @@ static void deformVerts(ModifierData *md, Object *ob, if (!(ob->transflag & OB_NO_PSYS_UPDATE)) { psmd->flag &= ~eParticleSystemFlag_psys_updated; - particle_system_update(md->scene, ob, psys); + particle_system_update(md->scene, ob, psys, (flag & MOD_APPLY_RENDER) != 0); psmd->flag |= eParticleSystemFlag_psys_updated; } } diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c index 9f1ec4de3d5..8ed623734be 100644 --- a/source/blender/modifiers/intern/MOD_skin.c +++ b/source/blender/modifiers/intern/MOD_skin.c @@ -1745,7 +1745,9 @@ static BMesh *build_skin(SkinNode *skin_nodes, int v; so.smd = smd; - so.bm = BM_mesh_create(&bm_mesh_allocsize_default); + so.bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = true,})); so.mat_nr = 0; /* BMESH_TODO: bumping up the stack level (see MOD_array.c) */ diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c index 527576843e3..911b6997058 100644 --- a/source/blender/modifiers/intern/MOD_solidify.c +++ b/source/blender/modifiers/intern/MOD_solidify.c @@ -141,9 +141,9 @@ static void dm_calc_normal(DerivedMesh *dm, float (*face_nors)[3], float (*r_ver * using the angle between the 2 faces as a weighting */ #if 0 add_v3_v3v3(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); - normalize_v3(edge_normal); - - mul_v3_fl(edge_normal, angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); + normalize_v3_length( + edge_normal, + angle_normalized_v3v3(face_nors[edge_ref->f1], face_nors[edge_ref->f2])); #else mid_v3_v3v3_angle_weighted(edge_normal, face_nors[edge_ref->f1], face_nors[edge_ref->f2]); #endif diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c index 6df9de8e683..ef988b9e542 100644 --- a/source/blender/modifiers/intern/MOD_weightvgmix.c +++ b/source/blender/modifiers/intern/MOD_weightvgmix.c @@ -221,9 +221,11 @@ static void updateDepsgraph(ModifierData *md, WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md; if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_COMPONENT_TRANSFORM, "WeightVGMix Modifier"); + DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_COMPONENT_GEOMETRY, "WeightVGMix Modifier"); } if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { DEG_add_object_relation(node, ob, DEG_COMPONENT_TRANSFORM, "WeightVGMix Modifier"); + DEG_add_object_relation(node, ob, DEG_COMPONENT_GEOMETRY, "WeightVGMix Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c index 71ac5a7efb6..aeb01d37013 100644 --- a/source/blender/modifiers/intern/MOD_weightvgproximity.c +++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c @@ -378,12 +378,15 @@ static void updateDepsgraph(ModifierData *md, WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md; if (wmd->proximity_ob_target != NULL) { DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_COMPONENT_TRANSFORM, "WeightVGProximity Modifier"); + DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_COMPONENT_GEOMETRY, "WeightVGProximity Modifier"); } if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) { DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_COMPONENT_TRANSFORM, "WeightVGProximity Modifier"); + DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_COMPONENT_GEOMETRY, "WeightVGProximity Modifier"); } if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) { DEG_add_object_relation(node, ob, DEG_COMPONENT_TRANSFORM, "WeightVGProximity Modifier"); + DEG_add_object_relation(node, ob, DEG_COMPONENT_GEOMETRY, "WeightVGProximity Modifier"); } } diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c index fe21757d5c2..adadd4834d4 100644 --- a/source/blender/modifiers/intern/MOD_wireframe.c +++ b/source/blender/modifiers/intern/MOD_wireframe.c @@ -1,23 +1,23 @@ /* -* ***** 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 ***** -* -*/ + * ***** 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 ***** + * + */ /** \file blender/modifiers/intern/MOD_wireframe.c * \ingroup modifiers diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index affc176239e..52959a67d74 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -82,7 +82,7 @@ DefNode( ShaderNode, SH_NODE_BSDF_ANISOTROPIC, def_anisotropic, "BS DefNode( ShaderNode, SH_NODE_BSDF_DIFFUSE, 0, "BSDF_DIFFUSE", BsdfDiffuse, "Diffuse BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLOSSY, def_glossy, "BSDF_GLOSSY", BsdfGlossy, "Glossy BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_GLASS, def_glass, "BSDF_GLASS", BsdfGlass, "Glass BSDF", "" ) -DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_glass, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) +DefNode( ShaderNode, SH_NODE_BSDF_REFRACTION, def_refraction, "BSDF_REFRACTION", BsdfRefraction, "Refraction BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSLUCENT, 0, "BSDF_TRANSLUCENT", BsdfTranslucent, "Translucent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_TRANSPARENT, 0, "BSDF_TRANSPARENT", BsdfTransparent, "Transparent BSDF", "" ) DefNode( ShaderNode, SH_NODE_BSDF_VELVET, 0, "BSDF_VELVET", BsdfVelvet, "Velvet BSDF", "" ) diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c index afccef46174..8523b7275bf 100644 --- a/source/blender/nodes/shader/node_shader_tree.c +++ b/source/blender/nodes/shader/node_shader_tree.c @@ -57,6 +57,8 @@ #include "RE_shader_ext.h" +#include "NOD_common.h" + #include "node_common.h" #include "node_exec.h" #include "node_util.h" @@ -323,9 +325,12 @@ static void ntree_shader_link_builtin_group_normal( "NodeSocketVector", "Normal"); /* Need to update tree so all node instances nodes gets proper sockets. */ + bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); + node_group_verify(ntree, group_node, &group_ntree->id); + node_group_input_verify(group_ntree, group_input_node, &group_ntree->id); ntreeUpdateTree(G.main, group_ntree); /* Assumes sockets are always added at the end. */ - bNodeSocket *group_node_normal_socket = (bNodeSocket*)group_node->inputs.last; + bNodeSocket *group_node_normal_socket = group_node->inputs.last; if (displacement_node == group_node) { /* If displacement is coming from this node group we need to perform * some internal re-linking in order to avoid cycles. @@ -346,7 +351,6 @@ static void ntree_shader_link_builtin_group_normal( /* This code is similar to ntree_shader_relink_displacement() */ bNode *group_displacement_node = group_displacement_link->fromnode; bNodeSocket *group_displacement_socket = group_displacement_link->fromsock; - nodeRemLink(group_ntree, group_displacement_link); /* Create and link bump node. * Can't re-use bump node from parent tree because it'll cause cycle. */ @@ -371,7 +375,6 @@ static void ntree_shader_link_builtin_group_normal( nodeAddLink(ntree, node_from, socket_from, group_node, group_node_normal_socket); - bNode *group_input_node = ntreeFindType(group_ntree, NODE_GROUP_INPUT); BLI_assert(group_input_node != NULL); bNodeSocket *group_input_node_normal_socket = nodeFindSocket(group_input_node, @@ -485,7 +488,7 @@ void ntreeGPUMaterialNodes(bNodeTree *ntree, GPUMaterial *mat, short compatibili ntreeExecGPUNodes(exec, mat, 1, compatibility); ntreeShaderEndExecTree(exec); - ntreeFreeTree_ex(localtree, false); + ntreeFreeTree(localtree); MEM_freeN(localtree); } diff --git a/source/blender/nodes/shader/nodes/node_shader_brightness.c b/source/blender/nodes/shader/nodes/node_shader_brightness.c index 8c873b57790..e992c0773c2 100644 --- a/source/blender/nodes/shader/nodes/node_shader_brightness.c +++ b/source/blender/nodes/shader/nodes/node_shader_brightness.c @@ -23,8 +23,7 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - -*/ + */ #include "node_shader_util.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_gamma.c b/source/blender/nodes/shader/nodes/node_shader_gamma.c index 0264abe451f..37439569f77 100644 --- a/source/blender/nodes/shader/nodes/node_shader_gamma.c +++ b/source/blender/nodes/shader/nodes/node_shader_gamma.c @@ -23,8 +23,7 @@ * Contributor(s): none yet. * * ***** END GPL LICENSE BLOCK ***** - -*/ + */ #include "node_shader_util.h" diff --git a/source/blender/nodes/shader/nodes/node_shader_normal_map.c b/source/blender/nodes/shader/nodes/node_shader_normal_map.c index 57014bdc476..48d1688c386 100644 --- a/source/blender/nodes/shader/nodes/node_shader_normal_map.c +++ b/source/blender/nodes/shader/nodes/node_shader_normal_map.c @@ -172,7 +172,8 @@ static int gpu_shader_normal_map(GPUMaterial *mat, bNode *node, bNodeExecData *U break; } - } else { + } + else { /* ************** BLENDER INTERNAL without world space shading flag ******* */ diff --git a/source/blender/nodes/shader/nodes/node_shader_texture.c b/source/blender/nodes/shader/nodes/node_shader_texture.c index 6edf6c2a0b4..b0b25a4878b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_texture.c +++ b/source/blender/nodes/shader/nodes/node_shader_texture.c @@ -33,6 +33,8 @@ #include "node_shader_util.h" +#include "GPU_material.h" + /* **************** TEXTURE ******************** */ static bNodeSocketTemplate sh_node_texture_in[] = { { SOCK_VECTOR, 1, "Vector", 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, /* no limit */ @@ -121,9 +123,20 @@ static int gpu_shader_texture(GPUMaterial *mat, bNode *node, bNodeExecData *UNUS { Tex *tex = (Tex *)node->id; - if (tex && tex->type == TEX_IMAGE && tex->ima) { - GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false); - GPU_stack_link(mat, "texture_image", in, out, texlink); + if (tex && tex->ima && (tex->type == TEX_IMAGE || tex->type == TEX_ENVMAP)) { + if (tex->type == TEX_IMAGE) { + GPUNodeLink *texlink = GPU_image(tex->ima, &tex->iuser, false); + GPU_stack_link(mat, "texture_image", in, out, texlink); + } + else { /* TEX_ENVMAP */ + if (!in[0].link) + in[0].link = GPU_uniform(in[0].vec); + if (!GPU_material_use_world_space_shading(mat)) + GPU_link(mat, "direction_transform_m4v3", in[0].link, GPU_builtin(GPU_INVERSE_VIEW_MATRIX), &in[0].link); + GPU_link(mat, "mtex_cube_map_refl_from_refldir", + GPU_cube_map(tex->ima, &tex->iuser, false), in[0].link, &out[0].link, &out[1].link); + GPU_link(mat, "color_to_normal", out[1].link, &out[2].link); + } ImBuf *ibuf = BKE_image_acquire_ibuf(tex->ima, &tex->iuser, NULL); if (ibuf && (ibuf->colormanage_flag & IMB_COLORMANAGE_IS_DATA) == 0 && diff --git a/source/blender/python/bmesh/bmesh_py_api.c b/source/blender/python/bmesh/bmesh_py_api.c index 7c5d1961849..d5973baeadb 100644 --- a/source/blender/python/bmesh/bmesh_py_api.c +++ b/source/blender/python/bmesh/bmesh_py_api.c @@ -53,17 +53,31 @@ #include "bmesh_py_api.h" /* own include */ PyDoc_STRVAR(bpy_bm_new_doc, -".. method:: new()\n" +".. method:: new(use_operators=True)\n" "\n" +" :arg use_operators: Support calling operators in :mod:`bmesh.ops` (uses some extra memory per vert/edge/face).\n" +" :type use_operators: bool\n" " :return: Return a new, empty BMesh.\n" " :rtype: :class:`bmesh.types.BMesh`\n" ); -static PyObject *bpy_bm_new(PyObject *UNUSED(self)) +static PyObject *bpy_bm_new(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { + static const char *kwlist[] = {"use_operators", NULL}; BMesh *bm; - bm = BM_mesh_create(&bm_mesh_allocsize_default); + bool use_operators = true; + + if (!PyArg_ParseTupleAndKeywords( + args, kw, "|$O&:new", (char **)kwlist, + PyC_ParseBool, &use_operators)) + { + return NULL; + } + + bm = BM_mesh_create( + &bm_mesh_allocsize_default, + &((struct BMeshCreateParams){.use_toolflags = use_operators,})); return BPy_BMesh_CreatePyObject(bm, BPY_BMFLAG_NOP); } @@ -155,7 +169,7 @@ static PyObject *bpy_bm_update_edit_mesh(PyObject *UNUSED(self), PyObject *args, } static struct PyMethodDef BPy_BM_methods[] = { - {"new", (PyCFunction)bpy_bm_new, METH_NOARGS, bpy_bm_new_doc}, + {"new", (PyCFunction)bpy_bm_new, METH_VARARGS | METH_KEYWORDS, bpy_bm_new_doc}, {"from_edit_mesh", (PyCFunction)bpy_bm_from_edit_mesh, METH_O, bpy_bm_from_edit_mesh_doc}, {"update_edit_mesh", (PyCFunction)bpy_bm_update_edit_mesh, METH_VARARGS | METH_KEYWORDS, bpy_bm_update_edit_mesh_doc}, {NULL, NULL, 0, NULL} @@ -193,20 +207,21 @@ PyObject *BPyInit_bmesh(void) /* bmesh.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_bmesh_types())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); + /* bmesh.ops (not a real module, exposes module like access). */ PyModule_AddObject(mod, "ops", (submodule = BPyInit_bmesh_ops())); - /* PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); */ + /* PyDict_SetItemString(sys_modules, PyModule_GetNameObject(submodule), submodule); */ PyDict_SetItemString(sys_modules, "bmesh.ops", submodule); /* fake module */ Py_INCREF(submodule); PyModule_AddObject(mod, "utils", (submodule = BPyInit_bmesh_utils())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); PyModule_AddObject(mod, "geometry", (submodule = BPyInit_bmesh_geometry())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); return mod; diff --git a/source/blender/python/bmesh/bmesh_py_ops_call.c b/source/blender/python/bmesh/bmesh_py_ops_call.c index 1dc70c3d288..551a66d1ed8 100644 --- a/source/blender/python/bmesh/bmesh_py_ops_call.c +++ b/source/blender/python/bmesh/bmesh_py_ops_call.c @@ -698,6 +698,12 @@ PyObject *BPy_BMO_call(BPy_BMeshOpFunc *self, PyObject *args, PyObject *kw) BPY_BM_CHECK_OBJ(py_bm); bm = py_bm->bm; + if (bm->use_toolflags == false) { + PyErr_SetString(PyExc_ValueError, + "bmesh created with 'use_operators=False'"); + return NULL; + } + /* could complain about entering with exceptions... */ BMO_error_clear(bm); } diff --git a/source/blender/python/bmesh/bmesh_py_types.c b/source/blender/python/bmesh/bmesh_py_types.c index fe4360d1e3b..1d951bae48b 100644 --- a/source/blender/python/bmesh/bmesh_py_types.c +++ b/source/blender/python/bmesh/bmesh_py_types.c @@ -1824,7 +1824,7 @@ static PyObject *bpy_bmface_calc_tangent_edge(BPy_BMFace *self) PyDoc_STRVAR(bpy_bmface_calc_tangent_edge_pair_doc, ".. method:: calc_tangent_edge_pair()\n" "\n" -" Return face tangent based on the two longest disconected edges.\n" +" Return face tangent based on the two longest disconnected edges.\n" "\n" " - Tris: Use the edge pair with the most similar lengths.\n" " - Quads: Use the longest edge pair.\n" diff --git a/source/blender/python/generic/bgl.c b/source/blender/python/generic/bgl.c index 4bd2e9d8d62..3ea10228ad4 100644 --- a/source/blender/python/generic/bgl.c +++ b/source/blender/python/generic/bgl.c @@ -983,7 +983,7 @@ static PyObject *Buffer_repr(Buffer *self) switch (self->type) { case GL_BYTE: typestr = "GL_BYTE"; break; case GL_SHORT: typestr = "GL_SHORT"; break; - case GL_INT: typestr = "GL_BYTE"; break; + case GL_INT: typestr = "GL_INT"; break; case GL_FLOAT: typestr = "GL_FLOAT"; break; case GL_DOUBLE: typestr = "GL_DOUBLE"; break; default: typestr = "UNKNOWN"; break; diff --git a/source/blender/python/generic/idprop_py_api.c b/source/blender/python/generic/idprop_py_api.c index db8ed072722..11646f3f3df 100644 --- a/source/blender/python/generic/idprop_py_api.c +++ b/source/blender/python/generic/idprop_py_api.c @@ -1560,7 +1560,7 @@ PyObject *BPyInit_idprop(void) /* idprop.types */ PyModule_AddObject(mod, "types", (submodule = BPyInit_idprop_types())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); return mod; diff --git a/source/blender/python/generic/py_capi_utils.c b/source/blender/python/generic/py_capi_utils.c index 7f13a7a4d94..72dec55e50b 100644 --- a/source/blender/python/generic/py_capi_utils.c +++ b/source/blender/python/generic/py_capi_utils.c @@ -177,7 +177,7 @@ PyObject *PyC_FromArray(const void *array, int length, const PyTypeObject *type, /** * Caller needs to ensure tuple is uninitialized. - * Handy for filling a typle with None for eg. + * Handy for filling a tuple with None for eg. */ void PyC_Tuple_Fill(PyObject *tuple, PyObject *value) { @@ -367,11 +367,12 @@ PyObject *PyC_FrozenSetFromStrings(const char **strings) } -/* similar to PyErr_Format(), +/** + * Similar to #PyErr_Format(), * - * implementation - we cant actually preprend the existing exception, + * Implementation - we cant actually prepend the existing exception, * because it could have _any_ arguments given to it, so instead we get its - * __str__ output and raise our own exception including it. + * ``__str__`` output and raise our own exception including it. */ PyObject *PyC_Err_Format_Prefix(PyObject *exception_type_prefix, const char *format, ...) { @@ -748,6 +749,7 @@ void PyC_RunQuicky(const char *filepath, int n, ...) /* set the value so we can access it */ PyDict_SetItemString(py_dict, "values", values); + Py_DECREF(values); py_result = PyRun_File(fp, filepath, Py_file_input, py_dict, py_dict); diff --git a/source/blender/python/intern/bpy_app.c b/source/blender/python/intern/bpy_app.c index 17617a231b2..727d980b182 100644 --- a/source/blender/python/intern/bpy_app.c +++ b/source/blender/python/intern/bpy_app.c @@ -236,7 +236,7 @@ static int bpy_app_debug_set(PyObject *UNUSED(self), PyObject *value, void *clos PyDoc_STRVAR(bpy_app_binary_path_python_doc, "String, the path to the python executable (read-only)" ); -static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UNUSED(closure)) +static PyObject *bpy_app_binary_path_python_get(PyObject *self, void *UNUSED(closure)) { /* refcount is held in BlenderAppType.tp_dict */ static PyObject *ret = NULL; @@ -248,7 +248,7 @@ static PyObject *bpy_app_binary_path_python_get(PyObject *UNUSED(self), void *UN fullpath, sizeof(fullpath), PY_MAJOR_VERSION, PY_MINOR_VERSION); ret = PyC_UnicodeFromByte(fullpath); - PyDict_SetItemString(BlenderAppType.tp_dict, "binary_path_python", ret); + PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(self), ret); } else { Py_INCREF(ret); @@ -356,10 +356,10 @@ static PyGetSetDef bpy_app_getsets[] = { static void py_struct_seq_getset_init(void) { /* tricky dynamic members, not to py-spec! */ - PyGetSetDef *getset; - - for (getset = bpy_app_getsets; getset->name; getset++) { - PyDict_SetItemString(BlenderAppType.tp_dict, getset->name, PyDescr_NewGetSet(&BlenderAppType, getset)); + for (PyGetSetDef *getset = bpy_app_getsets; getset->name; getset++) { + PyObject *item = PyDescr_NewGetSet(&BlenderAppType, getset); + PyDict_SetItem(BlenderAppType.tp_dict, PyDescr_NAME(item), item); + Py_DECREF(item); } } /* end dynamic bpy.app */ diff --git a/source/blender/python/intern/bpy_driver.c b/source/blender/python/intern/bpy_driver.c index 9b477e384db..65b6bd501ce 100644 --- a/source/blender/python/intern/bpy_driver.c +++ b/source/blender/python/intern/bpy_driver.c @@ -110,9 +110,11 @@ static void bpy_pydriver_update_dict(const float evaltime) bpy_pydriver_InternStr__frame = PyUnicode_FromString("frame"); } + PyObject *item = PyFloat_FromDouble(evaltime); PyDict_SetItem(bpy_pydriver_Dict, bpy_pydriver_InternStr__frame, - PyFloat_FromDouble(evaltime)); + item); + Py_DECREF(item); bpy_pydriver_evaltime_prev = evaltime; } @@ -301,7 +303,10 @@ float BPY_driver_exec(ChannelDriver *driver, const float evaltime) /* try to add to dictionary */ /* if (PyDict_SetItemString(driver_vars, dvar->name, driver_arg)) { */ - if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) < 0) { + if (PyDict_SetItem(driver_vars, PyTuple_GET_ITEM(expr_vars, i++), driver_arg) != -1) { + Py_DECREF(driver_arg); + } + else { /* this target failed - bad name */ if (targets_ok) { /* first one - print some extra info for easier identification */ diff --git a/source/blender/python/intern/bpy_interface.c b/source/blender/python/intern/bpy_interface.c index 11af0836e1c..311f621e13b 100644 --- a/source/blender/python/intern/bpy_interface.c +++ b/source/blender/python/intern/bpy_interface.c @@ -901,8 +901,8 @@ static void bpy_module_free(void *UNUSED(mod)) bool BPY_string_is_keyword(const char *str) { /* list is from... - * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist]) - */ + * ", ".join(['"%s"' % kw for kw in __import__("keyword").kwlist]) + */ const char *kwlist[] = { "False", "None", "True", "and", "as", "assert", "break", diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index a120e4886e0..37a7e0e23dd 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -39,7 +39,6 @@ #include "BLO_readfile.h" -#include "BKE_global.h" #include "BKE_main.h" #include "BKE_library.h" #include "BKE_idcode.h" @@ -186,6 +185,7 @@ PyDoc_STRVAR(bpy_lib_load_doc, static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject *kwds) { static const char *kwlist[] = {"filepath", "link", "relative", NULL}; + Main *bmain = CTX_data_main(BPy_GetContext()); BPy_Library *ret; const char *filename = NULL; bool is_rel = false, is_link = false; @@ -204,7 +204,7 @@ static PyObject *bpy_lib_load(PyObject *UNUSED(self), PyObject *args, PyObject * BLI_strncpy(ret->relpath, filename, sizeof(ret->relpath)); BLI_strncpy(ret->abspath, filename, sizeof(ret->abspath)); - BLI_path_abs(ret->abspath, G.main->name); + BLI_path_abs(ret->abspath, bmain->name); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | @@ -222,19 +222,16 @@ static PyObject *_bpy_names(BPy_Library *self, int blocktype) int totnames; names = BLO_blendhandle_get_datablock_names(self->blo_handle, blocktype, &totnames); + list = PyList_New(totnames); if (names) { int counter = 0; - list = PyList_New(totnames); for (l = names; l; l = l->next) { PyList_SET_ITEM(list, counter, PyUnicode_FromString((char *)l->link)); counter++; } BLI_linklist_free(names, free); /* free linklist *and* each node's data */ } - else { - list = PyList_New(0); - } return list; } @@ -264,8 +261,13 @@ static PyObject *bpy_lib_enter(BPy_Library *self, PyObject *UNUSED(args)) if (BKE_idcode_is_linkable(code)) { const char *name_plural = BKE_idcode_to_name_plural(code); PyObject *str = PyUnicode_FromString(name_plural); - PyDict_SetItem(self->dict, str, PyList_New(0)); - PyDict_SetItem(from_dict, str, _bpy_names(self, code)); + PyObject *item; + + PyDict_SetItem(self->dict, str, item = PyList_New(0)); + Py_DECREF(item); + PyDict_SetItem(from_dict, str, item = _bpy_names(self, code)); + Py_DECREF(item); + Py_DECREF(str); } } @@ -346,48 +348,44 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* loop */ Py_ssize_t size = PyList_GET_SIZE(ls); Py_ssize_t i; - PyObject *item; - const char *item_str; for (i = 0; i < size; i++) { - item = PyList_GET_ITEM(ls, i); - item_str = _PyUnicode_AsString(item); + PyObject *item_src = PyList_GET_ITEM(ls, i); + PyObject *item_dst; /* must be set below */ + const char *item_idname = _PyUnicode_AsString(item_src); - // printf(" %s\n", item_str); + // printf(" %s\n", item_idname); - if (item_str) { - ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_str); + if (item_idname) { + ID *id = BLO_library_link_named_part(mainl, &(self->blo_handle), idcode, item_idname); if (id) { #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ - Py_DECREF(item); - item = PyCapsule_New((void *)id, NULL, NULL); + item_dst = PyCapsule_New((void *)id, NULL, NULL); +#else + /* leave as is */ + continue; #endif } else { - bpy_lib_exit_warn_idname(self, name_plural, item_str); + bpy_lib_exit_warn_idname(self, name_plural, item_idname); /* just warn for now */ /* err = -1; */ -#ifdef USE_RNA_DATABLOCKS - item = Py_INCREF_RET(Py_None); -#endif + item_dst = Py_INCREF_RET(Py_None); } /* ID or None */ } else { /* XXX, could complain about this */ - bpy_lib_exit_warn_type(self, item); + bpy_lib_exit_warn_type(self, item_src); PyErr_Clear(); - -#ifdef USE_RNA_DATABLOCKS - item = Py_INCREF_RET(Py_None); -#endif + item_dst = Py_INCREF_RET(Py_None); } -#ifdef USE_RNA_DATABLOCKS - PyList_SET_ITEM(ls, i, item); -#endif + /* item_dst must be new or already incref'd */ + Py_DECREF(item_src); + PyList_SET_ITEM(ls, i, item_dst); } } } @@ -410,7 +408,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* copied from wm_operator.c */ { /* mark all library linked objects to be updated */ - BKE_main_lib_objects_recalc_all(G.main); + BKE_main_lib_objects_recalc_all(bmain); /* append, rather than linking */ if ((self->flag & FILE_LINK) == 0) { @@ -422,6 +420,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) /* finally swap the capsules for real bpy objects * important since BLO_library_append_end initializes NodeTree types used by srna->refine */ +#ifdef USE_RNA_DATABLOCKS { int idcode_step = 0, idcode; while ((idcode = BKE_idcode_iter_step(&idcode_step))) { @@ -451,6 +450,7 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) } } } +#endif /* USE_RNA_DATABLOCKS */ Py_RETURN_NONE; } diff --git a/source/blender/python/intern/bpy_operator.c b/source/blender/python/intern/bpy_operator.c index d6c57f4c302..eaa96e6243c 100644 --- a/source/blender/python/intern/bpy_operator.c +++ b/source/blender/python/intern/bpy_operator.c @@ -264,6 +264,11 @@ static PyObject *pyop_call(PyObject *UNUSED(self), PyObject *args) if ((reports->flag & RPT_FREE) == 0) { MEM_freeN(reports); } + else { + /* The WM is now responsible for running the modal operator, + * show reports in the info window. */ + reports->flag &= ~RPT_OP_HOLD; + } } WM_operator_properties_free(&ptr); diff --git a/source/blender/python/intern/bpy_props.c b/source/blender/python/intern/bpy_props.c index bce1d923462..3baeae0384a 100644 --- a/source/blender/python/intern/bpy_props.c +++ b/source/blender/python/intern/bpy_props.c @@ -2627,17 +2627,29 @@ PyDoc_STRVAR(BPy_EnumProperty_doc, " Returns a new enumerator property definition.\n" "\n" " :arg items: sequence of enum items formatted:\n" -" [(identifier, name, description, icon, number), ...] where the identifier is used\n" -" for python access and other values are used for the interface.\n" -" The three first elements of the tuples are mandatory.\n" -" The fourth one is either the (unique!) number id of the item or, if followed by a fith element\n" -" (which must be the numid), an icon string identifier or integer icon value (e.g. returned by icon()...).\n" -" Note the item is optional.\n" +" ``[(identifier, name, description, icon, number), ...]``.\n" +"\n" +" The first three elements of the tuples are mandatory.\n" +"\n" +" :identifier: The identifier is used for Python access.\n" +" :name: Name for the interace.\n" +" :description: Used for documentation and tooltips.\n" +" :icon: An icon string identifier or integer icon value\n" +" (e.g. returned by :class:`bpy.types.UILayout.icon`)\n" +" :number: Unique value used as the identifier for this item (stored in file data).\n" +" Use when the identifier may need to change.\n" +"\n" +" When an item only contains 4 items they define ``(identifier, name, description, number)``.\n" +"\n" " For dynamic values a callback can be passed which returns a list in\n" " the same format as the static list.\n" -" This function must take 2 arguments (self, context), **context may be None**.\n" -" WARNING: There is a known bug with using a callback,\n" -" Python must keep a reference to the strings returned or Blender will crash.\n" +" This function must take 2 arguments ``(self, context)``, **context may be None**.\n" +"\n" +" .. warning::\n" +"\n" +" There is a known bug with using a callback,\n" +" Python must keep a reference to the strings returned or Blender will crash.\n" +"\n" " :type items: sequence of string tuples or a function\n" BPY_PROPDEF_NAME_DOC BPY_PROPDEF_DESC_DOC @@ -2986,7 +2998,7 @@ static struct PyModuleDef props_module = { "This module defines properties to extend Blender's internal data. The result of these functions" " is used to assign properties to classes registered with Blender and can't be used directly.\n" "\n" - ".. warning:: All parameters to these functions must be passed as keywords.\n", + ".. note:: All parameters to these functions must be passed as keywords.\n", -1, /* multiple "initialization" just copies the module dict. */ props_methods, NULL, NULL, NULL, NULL diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index b8fd8aa5788..e59b01b8f1d 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -5220,7 +5220,7 @@ static PyObject *pyrna_param_to_py(PointerRNA *ptr, PropertyRNA *prop, void *dat } case PROP_COLLECTION: { - ListBase *lb = (ListBase *)data; + CollectionListBase *lb = (CollectionListBase *)data; CollectionPointerLink *link; ret = PyList_New(0); diff --git a/source/blender/python/intern/gpu.c b/source/blender/python/intern/gpu.c index c3bb588f7eb..50dd4618166 100644 --- a/source/blender/python/intern/gpu.c +++ b/source/blender/python/intern/gpu.c @@ -330,10 +330,10 @@ PyObject *GPU_initPython(void) /* gpu.offscreen */ PyModule_AddObject(module, "offscreen", (submodule = BPyInit_gpu_offscreen())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); - PyDict_SetItemString(PyImport_GetModuleDict(), "gpu", module); + PyDict_SetItem(PyImport_GetModuleDict(), PyModule_GetNameObject(module), module); return module; } diff --git a/source/blender/python/mathutils/mathutils.c b/source/blender/python/mathutils/mathutils.c index 635090869ea..5c505247a97 100644 --- a/source/blender/python/mathutils/mathutils.c +++ b/source/blender/python/mathutils/mathutils.c @@ -638,30 +638,30 @@ PyMODINIT_FUNC PyInit_mathutils(void) /* XXX, python doesnt do imports with this usefully yet * 'from mathutils.geometry import PolyFill' * ...fails without this. */ - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); PyModule_AddObject(mod, "interpolate", (submodule = PyInit_mathutils_interpolate())); /* XXX, python doesnt do imports with this usefully yet * 'from mathutils.geometry import PolyFill' * ...fails without this. */ - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); #ifndef MATH_STANDALONE /* Noise submodule */ PyModule_AddObject(mod, "noise", (submodule = PyInit_mathutils_noise())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); /* BVHTree submodule */ PyModule_AddObject(mod, "bvhtree", (submodule = PyInit_mathutils_bvhtree())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); /* KDTree submodule */ PyModule_AddObject(mod, "kdtree", (submodule = PyInit_mathutils_kdtree())); - PyDict_SetItemString(sys_modules, PyModule_GetName(submodule), submodule); + PyDict_SetItem(sys_modules, PyModule_GetNameObject(submodule), submodule); Py_INCREF(submodule); #endif diff --git a/source/blender/quicktime/apple/qtkit_import.m b/source/blender/quicktime/apple/qtkit_import.m index d42d0ee8ebb..ba7ee0a8936 100644 --- a/source/blender/quicktime/apple/qtkit_import.m +++ b/source/blender/quicktime/apple/qtkit_import.m @@ -200,7 +200,7 @@ static ImBuf *nsImageToiBuf(NSImage *sourceImage, int width, int height) /* Convert the image in a RGBA 32bit format */ /* As Core Graphics does not support contextes 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 */ blBitmapFormatImageRGB = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL diff --git a/source/blender/render/extern/include/RE_pipeline.h b/source/blender/render/extern/include/RE_pipeline.h index ce0691b7632..39f62f9fc33 100644 --- a/source/blender/render/extern/include/RE_pipeline.h +++ b/source/blender/render/extern/include/RE_pipeline.h @@ -231,8 +231,9 @@ struct RenderStats *RE_GetStats(struct Render *re); void RE_ResultGet32(struct Render *re, unsigned int *rect); void RE_AcquiredResultGet32(struct Render *re, struct RenderResult *result, unsigned int *rect, const int view_id); -void RE_render_result_rect_from_ibuf(struct RenderResult *rr, struct RenderData *rd, - struct ImBuf *ibuf, const int view_id); +void RE_render_result_rect_from_ibuf( + struct RenderResult *rr, struct RenderData *rd, + struct ImBuf *ibuf, const int view_id); struct RenderLayer *RE_GetRenderLayer(struct RenderResult *rr, const char *name); float *RE_RenderLayerGetPass(volatile struct RenderLayer *rl, int passtype, const char *viewname); @@ -249,8 +250,8 @@ struct Object *RE_GetCamera(struct Render *re); /* return camera override if set void RE_SetOverrideCamera(struct Render *re, struct Object *camera); void RE_SetCamera(struct Render *re, struct Object *camera); void RE_SetEnvmapCamera(struct Render *re, struct Object *cam_ob, float viewscale, float clipsta, float clipend); -void RE_SetWindow(struct Render *re, rctf *viewplane, float clipsta, float clipend); -void RE_SetOrtho(struct Render *re, rctf *viewplane, float clipsta, float clipend); +void RE_SetWindow(struct Render *re, const rctf *viewplane, float clipsta, float clipend); +void RE_SetOrtho(struct Render *re, const rctf *viewplane, float clipsta, float clipend); void RE_SetPixelSize(struct Render *re, float pixsize); /* option to set viewmatrix before making dbase */ @@ -258,10 +259,12 @@ void RE_SetView(struct Render *re, float mat[4][4]); /* get current view and window transform */ void RE_GetView(struct Render *re, float mat[4][4]); -void RE_GetViewPlane(struct Render *re, rctf *viewplane, rcti *disprect); +void RE_GetViewPlane(struct Render *re, rctf *r_viewplane, rcti *r_disprect); /* make or free the dbase */ -void RE_Database_FromScene(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, int use_camera_view); +void RE_Database_FromScene( + struct Render *re, struct Main *bmain, struct Scene *scene, + unsigned int lay, int use_camera_view); void RE_Database_Preprocess(struct Render *re); void RE_Database_Free(struct Render *re); @@ -304,11 +307,16 @@ void RE_SetReports(struct Render *re, struct ReportList *reports); void RE_PreviewRender(struct Render *re, struct Main *bmain, struct Scene *scene); bool RE_ReadRenderResult(struct Scene *scene, struct Scene *scenode); -bool RE_WriteRenderResult(struct ReportList *reports, RenderResult *rr, const char *filename, struct ImageFormatData *imf, const bool multiview, const char *view); -struct RenderResult *RE_MultilayerConvert(void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); +bool RE_WriteRenderResult( + struct ReportList *reports, RenderResult *rr, const char *filename, + struct ImageFormatData *imf, const bool multiview, const char *view); +struct RenderResult *RE_MultilayerConvert( + void *exrhandle, const char *colorspace, bool predivide, int rectx, int recty); extern const float default_envmap_layout[]; -bool RE_WriteEnvmapResult(struct ReportList *reports, struct Scene *scene, struct EnvMap *env, const char *relpath, const char imtype, float layout[12]); +bool RE_WriteEnvmapResult( + struct ReportList *reports, struct Scene *scene, struct EnvMap *env, + const char *relpath, const char imtype, float layout[12]); /* do a full sample buffer compo */ void RE_MergeFullSample(struct Render *re, struct Main *bmain, struct Scene *sce, struct bNodeTree *ntree); @@ -326,7 +334,9 @@ void RE_current_scene_update_cb(struct Render *re, void *handle, void (*f)(void /* should move to kernel once... still unsure on how/where */ float RE_filter_value(int type, float x); /* vector blur zbuffer method */ -void RE_zbuf_accumulate_vecblur(struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect); +void RE_zbuf_accumulate_vecblur( + struct NodeBlurData *nbd, int xsize, int ysize, float *newrect, + const float *imgrect, float *vecbufrect, const float *zbufrect); int RE_seq_render_active(struct Scene *scene, struct RenderData *rd); @@ -351,7 +361,9 @@ struct RenderPass *RE_pass_find_by_type(volatile struct RenderLayer *rl, int pas #define RE_BAKE_DERIVATIVE 13 #define RE_BAKE_VERTEX_COLORS 14 -void RE_Database_Baking(struct Render *re, struct Main *bmain, struct Scene *scene, unsigned int lay, const int type, struct Object *actob); +void RE_Database_Baking( + struct Render *re, struct Main *bmain, struct Scene *scene, + unsigned int lay, const int type, struct Object *actob); void RE_DataBase_GetView(struct Render *re, float mat[4][4]); void RE_GetCameraWindow(struct Render *re, struct Object *camera, int frame, float mat[4][4]); diff --git a/source/blender/render/intern/include/pixelblending.h b/source/blender/render/intern/include/pixelblending.h index 19759bf3e97..17a872a0676 100644 --- a/source/blender/render/intern/include/pixelblending.h +++ b/source/blender/render/intern/include/pixelblending.h @@ -38,7 +38,7 @@ */ void add_filt_fmask(unsigned int mask, const float col[4], float *rowbuf, int row_w); void add_filt_fmask_pixsize(unsigned int mask, float *in, float *rowbuf, int row_w, int pixsize); -void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y); +void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask); void mask_array(unsigned int mask, float filt[3][3]); /** diff --git a/source/blender/render/intern/include/render_types.h b/source/blender/render/intern/include/render_types.h index 6de5da3795a..b3a5ccdae17 100644 --- a/source/blender/render/intern/include/render_types.h +++ b/source/blender/render/intern/include/render_types.h @@ -180,6 +180,7 @@ struct Render { float jit[32][2]; float mblur_jit[32][2]; ListBase *qmcsamplers; + int num_qmc_samplers; /* shadow counter, detect shadow-reuse for shaders */ int shadowsamplenr[BLENDER_MAX_THREADS]; diff --git a/source/blender/render/intern/include/rendercore.h b/source/blender/render/intern/include/rendercore.h index 308903c6c6d..7254fd25ee6 100644 --- a/source/blender/render/intern/include/rendercore.h +++ b/source/blender/render/intern/include/rendercore.h @@ -90,7 +90,7 @@ extern void ray_shadow(ShadeInput *shi, LampRen *lar, float shadfac[4]); extern void ray_trace(ShadeInput *shi, ShadeResult *); extern void ray_ao(ShadeInput *shi, float ao[3], float env[3]); extern void init_jitter_plane(LampRen *lar); -extern void init_ao_sphere(struct World *wrld); +extern void init_ao_sphere(Render *re, struct World *wrld); extern void init_render_qmcsampler(Render *re); extern void free_render_qmcsampler(Render *re); diff --git a/source/blender/render/intern/raytrace/rayobject.cpp b/source/blender/render/intern/raytrace/rayobject.cpp index f511042749e..2104315dc00 100644 --- a/source/blender/render/intern/raytrace/rayobject.cpp +++ b/source/blender/render/intern/raytrace/rayobject.cpp @@ -145,8 +145,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v2, face->v3, &l, uv)) { /* check if intersection is within ray length */ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - r_uv[0] = uv[0]; - r_uv[1] = uv[1]; + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; *lambda = l; return 1; } @@ -157,8 +157,8 @@ MALWAYS_INLINE int isec_tri_quad(float start[3], const struct IsectRayPrecalc *i if (isect_ray_tri_watertight_v3(start, isect_precalc, face->v1, face->v3, face->v4, &l, uv)) { /* check if intersection is within ray length */ if (l > -RE_RAYTRACE_EPSILON && l < *lambda) { - r_uv[0] = uv[0]; - r_uv[1] = uv[1]; + r_uv[0] = -uv[0]; + r_uv[1] = -uv[1]; *lambda = l; return 2; } diff --git a/source/blender/render/intern/raytrace/rayobject_instance.cpp b/source/blender/render/intern/raytrace/rayobject_instance.cpp index d080ddcc375..349f0fc6844 100644 --- a/source/blender/render/intern/raytrace/rayobject_instance.cpp +++ b/source/blender/render/intern/raytrace/rayobject_instance.cpp @@ -125,6 +125,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } + // Pre-calculate orientation for watertight intersection checks. + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + // raycast res = RE_rayobject_intersect(obj->target, isec); @@ -168,6 +171,9 @@ static int RE_rayobject_instance_intersect(RayObject *o, Isect *isec) isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1]; } + // Pre-calculate orientation for watertight intersection checks. + isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir); + return res; } diff --git a/source/blender/render/intern/source/convertblender.c b/source/blender/render/intern/source/convertblender.c index b6ee88de290..ab828a0c04e 100644 --- a/source/blender/render/intern/source/convertblender.c +++ b/source/blender/render/intern/source/convertblender.c @@ -1330,7 +1330,7 @@ static int render_new_particle_system(Render *re, ObjectRen *obr, ParticleSystem part=psys->part; pars=psys->particles; - if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys)) + if (part==NULL || pars==NULL || !psys_check_enabled(ob, psys, G.is_rendering)) return 0; if (part->ren_as==PART_DRAW_OB || part->ren_as==PART_DRAW_GR || part->ren_as==PART_DRAW_NOT) @@ -2816,7 +2816,7 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag || timeoffset==0) { + if (dl->bevel_split || timeoffset == 0) { const int startvlak= obr->totvlak; for (a=0; a<dl->parts; a++) { @@ -2856,10 +2856,15 @@ static void init_render_curve(Render *re, ObjectRen *obr, int timeoffset) } } - if (dl->bevelSplitFlag) { - for (a=0; a<dl->parts-1+!!(dl->flag&DL_CYCL_V); a++) - if (dl->bevelSplitFlag[a>>5]&(1<<(a&0x1F))) - split_v_renderfaces(obr, startvlak, startvert, dl->parts, dl->nr, a, dl->flag&DL_CYCL_V, dl->flag&DL_CYCL_U); + if (dl->bevel_split) { + for (a = 0; a < dl->parts - 1 + !!(dl->flag & DL_CYCL_V); a++) { + if (BLI_BITMAP_TEST(dl->bevel_split, a)) { + split_v_renderfaces( + obr, startvlak, startvert, dl->parts, dl->nr, a, + /* intentionally swap (v, u) --> (u, v) */ + dl->flag & DL_CYCL_V, dl->flag & DL_CYCL_U); + } + } } /* vertex normals */ @@ -3167,9 +3172,8 @@ static void init_render_mesh(Render *re, ObjectRen *obr, int timeoffset) /* exception for tangent space baking */ if (me->mtpoly==NULL) { need_orco= 1; - need_tangent= 1; } - need_nmap_tangent_concrete = true; + need_tangent= 1; } /* check autosmooth and displacement, we then have to skip only-verts optimize @@ -4697,7 +4701,7 @@ static void add_render_object(Render *re, Object *ob, Object *par, DupliObject * if (ob->particlesystem.first) { psysindex= 1; for (psys=ob->particlesystem.first; psys; psys=psys->next, psysindex++) { - if (!psys_check_enabled(ob, psys)) + if (!psys_check_enabled(ob, psys, G.is_rendering)) continue; obr= RE_addRenderObject(re, ob, par, index, psysindex, ob->lay); @@ -5226,7 +5230,7 @@ void RE_Database_FromScene(Render *re, Main *bmain, Scene *scene, unsigned int l if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) - init_ao_sphere(&re->wrld); + init_ao_sphere(re, &re->wrld); } /* still bad... doing all */ @@ -5952,7 +5956,7 @@ void RE_Database_Baking(Render *re, Main *bmain, Scene *scene, unsigned int lay, if (re->wrld.mode & (WO_AMB_OCC|WO_ENV_LIGHT|WO_INDIRECT_LIGHT)) if (re->wrld.ao_samp_method == WO_AOSAMP_CONSTANT) - init_ao_sphere(&re->wrld); + init_ao_sphere(re, &re->wrld); } /* still bad... doing all */ diff --git a/source/blender/render/intern/source/envmap.c b/source/blender/render/intern/source/envmap.c index b1afb86e5af..d97e18d6511 100644 --- a/source/blender/render/intern/source/envmap.c +++ b/source/blender/render/intern/source/envmap.c @@ -52,6 +52,7 @@ #include "BKE_main.h" #include "BKE_image.h" /* BKE_imbuf_write */ #include "BKE_texture.h" +#include "BKE_scene.h" /* this module */ #include "render_types.h" @@ -737,21 +738,28 @@ int envmaptex(Tex *tex, const float texvec[3], float dxt[3], float dyt[3], int o /* rotate to envmap space, if object is set */ copy_v3_v3(vec, texvec); - if (env->object) mul_m3_v3(env->obimat, vec); - else mul_mat3_m4_v3(R.viewinv, vec); + if (env->object) { + mul_m3_v3(env->obimat, vec); + if (osatex) { + mul_m3_v3(env->obimat, dxt); + mul_m3_v3(env->obimat, dyt); + } + } + else { + if (!BKE_scene_use_world_space_shading(R.scene)) { + // texvec is in view space + mul_mat3_m4_v3(R.viewinv, vec); + if (osatex) { + mul_mat3_m4_v3(R.viewinv, dxt); + mul_mat3_m4_v3(R.viewinv, dyt); + } + } + } face = envcube_isect(env, vec, sco); ibuf = env->cube[face]; if (osatex) { - if (env->object) { - mul_m3_v3(env->obimat, dxt); - mul_m3_v3(env->obimat, dyt); - } - else { - mul_mat3_m4_v3(R.viewinv, dxt); - mul_mat3_m4_v3(R.viewinv, dyt); - } set_dxtdyt(dxts, dyts, dxt, dyt, face); imagewraposa(tex, NULL, ibuf, sco, dxts, dyts, texres, pool, skip_load_image); diff --git a/source/blender/render/intern/source/multires_bake.c b/source/blender/render/intern/source/multires_bake.c index 8c6d9c5f951..fba5836ac32 100644 --- a/source/blender/render/intern/source/multires_bake.c +++ b/source/blender/render/intern/source/multires_bake.c @@ -864,8 +864,7 @@ static void apply_tangmat_callback(DerivedMesh *lores_dm, DerivedMesh *hires_dm, lvl, lt, uv[0], uv[1], NULL, n); mul_v3_m3v3(vec, tangmat, n); - normalize_v3(vec); - mul_v3_fl(vec, 0.5); + normalize_v3_length(vec, 0.5); add_v3_v3(vec, tmp); if (ibuf->rect_float) { diff --git a/source/blender/render/intern/source/occlusion.c b/source/blender/render/intern/source/occlusion.c index c5c3b6bbf94..b3d31e3b93a 100644 --- a/source/blender/render/intern/source/occlusion.c +++ b/source/blender/render/intern/source/occlusion.c @@ -115,6 +115,8 @@ typedef struct OcclusionTree { int doindirect; OcclusionCache *cache; + + int num_threads; } OcclusionTree; typedef struct OcclusionThread { @@ -641,6 +643,7 @@ static void occ_build_sh_normalize(OccNode *node) static OcclusionTree *occ_tree_build(Render *re) { + const int num_threads = re->r.threads; OcclusionTree *tree; ObjectInstanceRen *obi; ObjectRen *obr; @@ -679,7 +682,7 @@ static OcclusionTree *occ_tree_build(Render *re) BLI_memarena_use_calloc(tree->arena); if (re->wrld.aomode & WO_AOCACHE) - tree->cache = MEM_callocN(sizeof(OcclusionCache) * BLENDER_MAX_THREADS, "OcclusionCache"); + tree->cache = MEM_callocN(sizeof(OcclusionCache) * num_threads, "OcclusionCache"); tree->face = MEM_callocN(sizeof(OccFace) * totface, "OcclusionFace"); tree->co = MEM_callocN(sizeof(float) * 3 * totface, "OcclusionCo"); @@ -730,9 +733,11 @@ static OcclusionTree *occ_tree_build(Render *re) if (!(re->test_break(re->tbh))) occ_build_sh_normalize(tree->root); - for (a = 0; a < BLENDER_MAX_THREADS; a++) + for (a = 0; a < num_threads; a++) tree->stack[a] = MEM_callocN(sizeof(OccNode) * TOTCHILD * (tree->maxdepth + 1), "OccStack"); + tree->num_threads = num_threads; + return tree; } @@ -742,7 +747,7 @@ static void occ_free_tree(OcclusionTree *tree) if (tree) { if (tree->arena) BLI_memarena_free(tree->arena); - for (a = 0; a < BLENDER_MAX_THREADS; a++) + for (a = 0; a < tree->num_threads; a++) if (tree->stack[a]) MEM_freeN(tree->stack[a]); if (tree->occlusion) MEM_freeN(tree->occlusion); diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c index c88e3b36e27..1ee905c596c 100644 --- a/source/blender/render/intern/source/pipeline.c +++ b/source/blender/render/intern/source/pipeline.c @@ -66,6 +66,7 @@ #include "BKE_global.h" #include "BKE_image.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_modifier.h" #include "BKE_node.h" @@ -354,7 +355,7 @@ Scene *RE_GetScene(Render *re) * Same as #RE_AcquireResultImage but creating the necessary views to store the result * fill provided result struct with a copy of thew views of what is done so far the * #RenderResult.views #ListBase needs to be freed after with #RE_ReleaseResultImageViews -*/ + */ void RE_AcquireResultImageViews(Render *re, RenderResult *rr) { memset(rr, 0, sizeof(RenderResult)); @@ -633,12 +634,6 @@ static int check_mode_full_sample(RenderData *rd) #ifdef WITH_OPENEXR if (scemode & R_FULL_SAMPLE) scemode |= R_EXR_TILE_FILE; /* enable automatic */ - - /* Until use_border is made compatible with save_buffers/full_sample, render without the later instead of not rendering at all.*/ - if (rd->mode & R_BORDER) { - scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE); - } - #else /* can't do this without openexr support */ scemode &= ~(R_EXR_TILE_FILE | R_FULL_SAMPLE); @@ -727,6 +722,13 @@ void RE_InitState(Render *re, Render *source, RenderData *rd, re->r.size = source->r.size; } + /* disable border if it's a full render anyway */ + if (re->r.border.xmin == 0.0f && re->r.border.xmax == 1.0f && + re->r.border.ymin == 0.0f && re->r.border.ymax == 1.0f) + { + re->r.mode &= ~R_BORDER; + } + re_init_resolution(re, source, winx, winy, disprect); if (re->rectx < 1 || re->recty < 1 || (BKE_imtype_is_movie(rd->im_format.imtype) && @@ -929,7 +931,7 @@ void render_update_anim_renderdata(Render *re, RenderData *rd) BLI_duplicatelist(&re->r.views, &rd->views); } -void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) +void RE_SetWindow(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -944,7 +946,7 @@ void RE_SetWindow(Render *re, rctf *viewplane, float clipsta, float clipend) } -void RE_SetOrtho(Render *re, rctf *viewplane, float clipsta, float clipend) +void RE_SetOrtho(Render *re, const rctf *viewplane, float clipsta, float clipend) { /* re->ok flag? */ @@ -965,15 +967,17 @@ void RE_SetView(Render *re, float mat[4][4]) invert_m4_m4(re->viewinv, re->viewmat); } -void RE_GetViewPlane(Render *re, rctf *viewplane, rcti *disprect) +void RE_GetViewPlane(Render *re, rctf *r_viewplane, rcti *r_disprect) { - *viewplane = re->viewplane; + *r_viewplane = re->viewplane; /* make disprect zero when no border render, is needed to detect changes in 3d view render */ - if (re->r.mode & R_BORDER) - *disprect = re->disprect; - else - BLI_rcti_init(disprect, 0, 0, 0, 0); + if (re->r.mode & R_BORDER) { + *r_disprect = re->disprect; + } + else { + BLI_rcti_init(r_disprect, 0, 0, 0, 0); + } } void RE_GetView(Render *re, float mat[4][4]) @@ -1828,6 +1832,53 @@ static void render_result_disprect_to_full_resolution(Render *re) re->recty = re->winy; } +static void render_result_uncrop(Render *re) +{ + /* when using border render with crop disabled, insert render result into + * full size with black pixels outside */ + if (re->result && (re->r.mode & R_BORDER)) { + if ((re->r.mode & R_CROP) == 0) { + RenderResult *rres; + + /* backup */ + const rcti orig_disprect = re->disprect; + const int orig_rectx = re->rectx, orig_recty = re->recty; + + BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); + + /* sub-rect for merge call later on */ + re->result->tilerect = re->disprect; + + /* weak is: it chances disprect from border */ + render_result_disprect_to_full_resolution(re); + + rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); + + render_result_merge(rres, re->result); + render_result_free(re->result); + re->result = rres; + + /* weak... the display callback wants an active renderlayer pointer... */ + re->result->renlay = render_get_active_layer(re, re->result); + + BLI_rw_mutex_unlock(&re->resultmutex); + + re->display_init(re->dih, re->result); + re->display_update(re->duh, re->result, NULL); + + /* restore the disprect from border */ + re->disprect = orig_disprect; + re->rectx = orig_rectx; + re->recty = orig_recty; + } + else { + /* set offset (again) for use in compositor, disprect was manipulated. */ + re->result->xof = 0; + re->result->yof = 0; + } + } +} + /* main render routine, no compositing */ static void do_render_fields_blur_3d(Render *re) { @@ -1850,49 +1901,7 @@ static void do_render_fields_blur_3d(Render *re) do_render_3d(re); /* when border render, check if we have to insert it in black */ - if (re->result) { - if (re->r.mode & R_BORDER) { - if ((re->r.mode & R_CROP) == 0) { - RenderResult *rres; - - /* backup */ - const rcti orig_disprect = re->disprect; - const int orig_rectx = re->rectx, orig_recty = re->recty; - - BLI_rw_mutex_lock(&re->resultmutex, THREAD_LOCK_WRITE); - - /* sub-rect for merge call later on */ - re->result->tilerect = re->disprect; - - /* weak is: it chances disprect from border */ - render_result_disprect_to_full_resolution(re); - - rres = render_result_new(re, &re->disprect, 0, RR_USE_MEM, RR_ALL_LAYERS, RR_ALL_VIEWS); - - render_result_merge(rres, re->result); - render_result_free(re->result); - re->result = rres; - - /* weak... the display callback wants an active renderlayer pointer... */ - re->result->renlay = render_get_active_layer(re, re->result); - - BLI_rw_mutex_unlock(&re->resultmutex); - - re->display_init(re->dih, re->result); - re->display_update(re->duh, re->result, NULL); - - /* restore the disprect from border */ - re->disprect = orig_disprect; - re->rectx = orig_rectx; - re->recty = orig_recty; - } - else { - /* set offset (again) for use in compositor, disprect was manipulated. */ - re->result->xof = 0; - re->result->yof = 0; - } - } - } + render_result_uncrop(re); } @@ -2177,12 +2186,12 @@ static void init_freestyle(Render *re) re->freestyle_bmain = BKE_main_new(); /* We use the same window manager for freestyle bmain as - * real bmain uses. This is needed because freestyle's - * bmain could be used to tag scenes for update, which - * implies call of ED_render_scene_update in some cases - * and that function requires proper window manager - * to present (sergey) - */ + * real bmain uses. This is needed because freestyle's + * bmain could be used to tag scenes for update, which + * implies call of ED_render_scene_update in some cases + * and that function requires proper window manager + * to present (sergey) + */ re->freestyle_bmain->wm = re->main->wm; FRS_init_stroke_renderer(re); @@ -2267,7 +2276,8 @@ static void free_all_freestyle_renders(void) if (freestyle_render) { freestyle_scene = freestyle_render->scene; RE_FreeRender(freestyle_render); - BKE_scene_unlink(re1->freestyle_bmain, freestyle_scene, NULL); + BKE_libblock_unlink(re1->freestyle_bmain, freestyle_scene, false, false); + BKE_libblock_free(re1->freestyle_bmain, freestyle_scene); } } BLI_freelistN(&re1->freestyle_renders); @@ -2290,6 +2300,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) { ListBase *rectfs; RenderView *rv; + rcti filter_mask = re->disprect; float *rectf, filt[3][3]; int x, y, sample; int nr, numviews; @@ -2315,7 +2326,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) rv = MEM_callocN(sizeof(RenderView), "fullsample renderview"); /* we accumulate in here */ - rv->rectf = MEM_mapallocN(re->rectx * re->recty * sizeof(float) * 4, "fullsample rgba"); + rv->rectf = MEM_mapallocN(re->result->rectx * re->result->recty * sizeof(float) * 4, "fullsample rgba"); BLI_addtail(rectfs, rv); } @@ -2345,6 +2356,7 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) composite_freestyle_renders(re1, sample); #endif BLI_rw_mutex_unlock(&re->resultmutex); + render_result_uncrop(re1); } ntreeCompositTagRender(re1->scene); /* ensure node gets exec to put buffers on stack */ } @@ -2371,17 +2383,17 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) mask = (1 << sample); mask_array(mask, filt); - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; - float *col = rres.rectf + 4 * y * re->rectx; + for (y = 0; y < re->result->recty; y++) { + float *rf = rectf + 4 * y * re->result->rectx; + float *col = rres.rectf + 4 * y * re->result->rectx; - for (x = 0; x < re->rectx; x++, rf += 4, col += 4) { + for (x = 0; x < re->result->rectx; x++, rf += 4, col += 4) { /* clamping to 1.0 is needed for correct AA */ CLAMP(col[0], 0.0f, 1.0f); CLAMP(col[1], 0.0f, 1.0f); CLAMP(col[2], 0.0f, 1.0f); - add_filt_fmask_coord(filt, col, rf, re->rectx, re->recty, x, y); + add_filt_fmask_coord(filt, col, rf, re->result->rectx, x, y, &filter_mask); } } @@ -2401,10 +2413,10 @@ static void do_merge_fullsample(Render *re, bNodeTree *ntree) rectf = ((RenderView *)BLI_findlink(rectfs, nr))->rectf; /* clamp alpha and RGB to 0..1 and 0..inf, can go outside due to filter */ - for (y = 0; y < re->recty; y++) { - float *rf = rectf + 4 * y * re->rectx; + for (y = 0; y < re->result->recty; y++) { + float *rf = rectf + 4 * y * re->result->rectx; - for (x = 0; x < re->rectx; x++, rf += 4) { + for (x = 0; x < re->result->rectx; x++, rf += 4) { rf[0] = MAX2(rf[0], 0.0f); rf[1] = MAX2(rf[1], 0.0f); rf[2] = MAX2(rf[2], 0.0f); @@ -3845,6 +3857,8 @@ bool RE_ReadRenderResult(Scene *scene, Scene *scenode) success = render_result_exr_file_cache_read(re); BLI_rw_mutex_unlock(&re->resultmutex); + render_result_uncrop(re); + return success; } diff --git a/source/blender/render/intern/source/pixelblending.c b/source/blender/render/intern/source/pixelblending.c index 32fb196e1f3..fc79786e5c7 100644 --- a/source/blender/render/intern/source/pixelblending.c +++ b/source/blender/render/intern/source/pixelblending.c @@ -240,7 +240,7 @@ void mask_array(unsigned int mask, float filt[3][3]) * </pre> */ -void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_w, int col_h, int x, int y) +void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, int row_stride, int x, int y, rcti *mask) { float *fpoin[3][3]; float val, r, g, b, al, lfilt[3][3]; @@ -252,9 +252,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i memcpy(lfilt, filt, sizeof(lfilt)); - fpoin[0][1] = rowbuf - 4 * row_w; + fpoin[0][1] = rowbuf - 4 * row_stride; fpoin[1][1] = rowbuf; - fpoin[2][1] = rowbuf + 4 * row_w; + fpoin[2][1] = rowbuf + 4 * row_stride; fpoin[0][0] = fpoin[0][1] - 4; fpoin[1][0] = fpoin[1][1] - 4; @@ -264,7 +264,9 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i fpoin[1][2] = fpoin[1][1] + 4; fpoin[2][2] = fpoin[2][1] + 4; - if (y == 0) { + /* limit filtering to withing a mask for border rendering, so pixels don't + * leak outside of the border */ + if (y <= mask->ymin) { fpoin[0][0] = fpoin[1][0]; fpoin[0][1] = fpoin[1][1]; fpoin[0][2] = fpoin[1][2]; @@ -273,7 +275,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i lfilt[0][1] = filt[2][1]; lfilt[0][2] = filt[2][2]; } - else if (y == col_h - 1) { + else if (y >= mask->ymax - 1) { fpoin[2][0] = fpoin[1][0]; fpoin[2][1] = fpoin[1][1]; fpoin[2][2] = fpoin[1][2]; @@ -283,7 +285,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i lfilt[2][2] = filt[0][2]; } - if (x == 0) { + if (x <= mask->xmin) { fpoin[2][0] = fpoin[2][1]; fpoin[1][0] = fpoin[1][1]; fpoin[0][0] = fpoin[0][1]; @@ -292,7 +294,7 @@ void add_filt_fmask_coord(float filt[3][3], const float col[4], float *rowbuf, i lfilt[1][0] = filt[1][2]; lfilt[0][0] = filt[0][2]; } - else if (x == row_w - 1) { + else if (x >= mask->xmax - 1) { fpoin[2][2] = fpoin[2][1]; fpoin[1][2] = fpoin[1][1]; fpoin[0][2] = fpoin[0][1]; diff --git a/source/blender/render/intern/source/pointdensity.c b/source/blender/render/intern/source/pointdensity.c index 59aaad661c9..e4da4302efe 100644 --- a/source/blender/render/intern/source/pointdensity.c +++ b/source/blender/render/intern/source/pointdensity.c @@ -211,7 +211,7 @@ static void pointdensity_cache_psys(Scene *scene, CD_MASK_BAREMESH | CD_MASK_MTFACE | CD_MASK_MCOL); } - if (!psys_check_enabled(ob, psys)) { + if (!psys_check_enabled(ob, psys, use_render_params)) { psys_render_restore(ob, psys); return; } diff --git a/source/blender/render/intern/source/rayshade.c b/source/blender/render/intern/source/rayshade.c index 9aac5ed1f1d..26a0b0c71b4 100644 --- a/source/blender/render/intern/source/rayshade.c +++ b/source/blender/render/intern/source/rayshade.c @@ -174,10 +174,11 @@ void freeraytree(Render *re) #ifdef RE_RAYCOUNTER { + const int num_threads = re->r.threads; RayCounter sum; memset(&sum, 0, sizeof(sum)); int i; - for (i=0; i<BLENDER_MAX_THREADS; i++) + for (i=0; i<num_threads; i++) RE_RC_MERGE(&sum, re_rc_counter+i); RE_RC_INFO(&sum); } @@ -1186,7 +1187,9 @@ static void QMC_sampleHemiCosine(float vec[3], QMCSampler *qsa, int thread, int /* called from convertBlenderScene.c */ void init_render_qmcsampler(Render *re) { - re->qmcsamplers= MEM_callocN(sizeof(ListBase)*BLENDER_MAX_THREADS, "QMCListBase"); + const int num_threads = re->r.threads; + re->qmcsamplers= MEM_callocN(sizeof(ListBase)*num_threads, "QMCListBase"); + re->num_qmc_samplers = num_threads; } static QMCSampler *get_thread_qmcsampler(Render *re, int thread, int type, int tot) @@ -1220,7 +1223,7 @@ void free_render_qmcsampler(Render *re) if (re->qmcsamplers) { QMCSampler *qsa, *next; int a; - for (a=0; a<BLENDER_MAX_THREADS; a++) { + for (a = 0; a < re->num_qmc_samplers; a++) { for (qsa=re->qmcsamplers[a].first; qsa; qsa=next) { next= qsa->next; QMC_freeSampler(qsa); @@ -1695,9 +1698,10 @@ static void DS_energy(float *sphere, int tot, float vec[3]) /* called from convertBlenderScene.c */ /* creates an equally distributed spherical sample pattern */ /* and allocates threadsafe memory */ -void init_ao_sphere(World *wrld) +void init_ao_sphere(Render *re, World *wrld) { /* fixed random */ + const int num_threads = re->r.threads; RNG *rng; float *fp; int a, tot, iter= 16; @@ -1721,7 +1725,7 @@ void init_ao_sphere(World *wrld) } /* tables */ - wrld->aotables= MEM_mallocN(BLENDER_MAX_THREADS*3*tot*sizeof(float), "AO tables"); + wrld->aotables= MEM_mallocN(num_threads*3*tot*sizeof(float), "AO tables"); BLI_rng_free(rng); } diff --git a/source/blender/render/intern/source/render_texture.c b/source/blender/render/intern/source/render_texture.c index 21e5d4e6cf3..c378afa74f1 100644 --- a/source/blender/render/intern/source/render_texture.c +++ b/source/blender/render/intern/source/render_texture.c @@ -1720,6 +1720,21 @@ static void texco_mapping(ShadeInput *shi, Tex *tex, MTex *mtex, } else dxt[2]= dyt[2] = 0.f; } + + if (mtex->tex->type == TEX_ENVMAP) { + EnvMap *env = tex->env; + if (!env->object) { + // env->object is a view point for envmap rendering + // if it's not set, return the result depending on the world_space_shading flag + if (BKE_scene_use_world_space_shading(R.scene)) { + mul_mat3_m4_v3(R.viewinv, texvec); + if (shi->osatex) { + mul_mat3_m4_v3(R.viewinv, dxt); + mul_mat3_m4_v3(R.viewinv, dyt); + } + } + } + } } } @@ -2480,8 +2495,7 @@ void do_material_tex(ShadeInput *shi, Render *re) /* can be optimized... (ton) */ mul_mat3_m4_v3(shi->obr->ob->obmat, texres.nor); mul_mat3_m4_v3(re->viewmat, texres.nor); - normalize_v3(texres.nor); - mul_v3_fl(texres.nor, len); + normalize_v3_length(texres.nor, len); } } } @@ -3639,7 +3653,8 @@ void render_realtime_texture(ShadeInput *shi, Image *ima) if (firsttime) { BLI_lock_thread(LOCK_IMAGE); if (firsttime) { - for (a=0; a<BLENDER_MAX_THREADS; a++) { + const int num_threads = BLI_system_thread_count(); + for (a = 0; a < num_threads; a++) { memset(&imatex[a], 0, sizeof(Tex)); BKE_texture_default(&imatex[a]); imatex[a].type= TEX_IMAGE; @@ -3806,6 +3821,7 @@ void RE_sample_material_free(Material *mat) MTex *mtex= mat->mtex[tex_nr]; if (mtex->tex) { + /* don't update user counts as we are freeing a duplicate */ BKE_texture_free(mtex->tex); MEM_freeN(mtex->tex); mtex->tex = NULL; @@ -3814,7 +3830,7 @@ void RE_sample_material_free(Material *mat) } /* don't update user counts as we are freeing a duplicate */ - BKE_material_free_ex(mat, false); + BKE_material_free(mat); MEM_freeN(mat); } diff --git a/source/blender/render/intern/source/sss.c b/source/blender/render/intern/source/sss.c index 553710b4367..26ca3ad50e0 100644 --- a/source/blender/render/intern/source/sss.c +++ b/source/blender/render/intern/source/sss.c @@ -279,13 +279,19 @@ static void build_Rd_table(ScatterSettings *ss) for (i= 0; i < size; i++) { r= i*(RD_TABLE_RANGE/RD_TABLE_SIZE); - /*if (r < ss->invsigma_t_*ss->invsigma_t_) - r= ss->invsigma_t_*ss->invsigma_t_;*/ +#if 0 + if (r < ss->invsigma_t_*ss->invsigma_t_) { + r= ss->invsigma_t_*ss->invsigma_t_; + } +#endif ss->tableRd[i]= Rd(ss, sqrtf(r)); r= i*(RD_TABLE_RANGE_2/RD_TABLE_SIZE); - /*if (r < ss->invsigma_t_) - r= ss->invsigma_t_;*/ +#if 0 + if (r < ss->invsigma_t_) { + r= ss->invsigma_t_; + } +#endif ss->tableRd2[i]= Rd(ss, r); } } diff --git a/source/blender/render/intern/source/zbuf.c b/source/blender/render/intern/source/zbuf.c index d3a1dcfd8ce..9f777631e52 100644 --- a/source/blender/render/intern/source/zbuf.c +++ b/source/blender/render/intern/source/zbuf.c @@ -2883,14 +2883,17 @@ static void set_quad_bezier_ipo(float fac, float *data) data[2]= fac*fac; } -void RE_zbuf_accumulate_vecblur(NodeBlurData *nbd, int xsize, int ysize, float *newrect, float *imgrect, float *vecbufrect, float *zbufrect) +void RE_zbuf_accumulate_vecblur( + NodeBlurData *nbd, int xsize, int ysize, float *newrect, + const float *imgrect, float *vecbufrect, const float *zbufrect) { ZSpan zspan; DrawBufPixel *rectdraw, *dr; static float jit[256][2]; float v1[3], v2[3], v3[3], v4[3], fx, fy; - float *rectvz, *dvz, *dimg, *dvec1, *dvec2, *dz, *dz1, *dz2, *rectz; - float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm, *ro; + const float *dimg, *dz, *ro; + float *rectvz, *dvz, *dvec1, *dvec2, *dz1, *dz2, *rectz; + float *minvecbufrect= NULL, *rectweight, *rw, *rectmax, *rm; float maxspeedsq= (float)nbd->maxspeed*nbd->maxspeed; int y, x, step, maxspeed=nbd->maxspeed, samples= nbd->samples; int tsktsk= 0; diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 388837af67a..7a247d9791b 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -191,7 +191,7 @@ void WM_ndof_deadzone_set(float deadzone); void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference); void WM_main_add_notifier(unsigned int type, void *reference); void WM_main_remove_notifier_reference(const void *reference); -void WM_main_remove_editor_id_reference(const struct ID *id); +void WM_main_remap_editor_id_reference(struct ID *old_id, struct ID *new_id); /* reports */ void WM_report_banner_show(void); @@ -413,12 +413,6 @@ void wmOrtho2 (float x1, float x2, float y1, float y2); void wmOrtho2_region_pixelspace(const struct ARegion *ar); void wmOrtho2_pixelspace(const float x, const float y); - /* utilities */ -void WM_framebuffer_index_set(int index); -void WM_framebuffer_index_get(int index, int *r_col); -int WM_framebuffer_to_index(unsigned int col); -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size); - /* threaded Jobs Manager */ enum { WM_JOB_PRIORITY = (1 << 0), diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 4f9d48450f6..4515ae92f66 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -241,7 +241,7 @@ void WM_main_remove_notifier_reference(const void *reference) } } -void WM_main_remove_editor_id_reference(const ID *id) +void WM_main_remap_editor_id_reference(ID *old_id, ID *new_id) { Main *bmain = G.main; bScreen *sc; @@ -253,7 +253,7 @@ void WM_main_remove_editor_id_reference(const ID *id) SpaceLink *sl; for (sl = sa->spacedata.first; sl; sl = sl->next) { - ED_spacedata_id_unref(sl, id); + ED_spacedata_id_remap(sa, sl, old_id, new_id); } } } @@ -793,7 +793,10 @@ static int wm_operator_exec(bContext *C, wmOperator *op, const bool repeat, cons wm_operator_finished(C, op, repeat); } else if (repeat == 0) { - WM_operator_free(op); + /* warning: modal from exec is bad practice, but avoid crashing. */ + if (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) { + WM_operator_free(op); + } } return retval | OPERATOR_HANDLED; diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 729af731dfe..fe257cc4c41 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -482,8 +482,6 @@ static void wm_file_read_post(bContext *C, bool is_startup_file) BPY_python_reset(C); addons_loaded = true; } -#else - UNUSED_VARS(is_startup_file); #endif /* WITH_PYTHON */ WM_operatortype_last_properties_clear_all(); @@ -492,8 +490,12 @@ static void wm_file_read_post(bContext *C, bool is_startup_file) BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_VERSION_UPDATE); BLI_callback_exec(CTX_data_main(C), NULL, BLI_CB_EVT_LOAD_POST); - /* would otherwise be handled by event loop */ - if (G.background) { + /* Would otherwise be handled by event loop. + * + * Disabled for startup file, since it causes problems when PyDrivers are used in the startup file. + * While its possible state of startup file may be wrong, + * in this case users nearly always load a file to replace the startup file. */ + if (G.background && (is_startup_file == false)) { Main *bmain = CTX_data_main(C); BKE_scene_update_tagged(bmain->eval_ctx, bmain, CTX_data_scene(C)); } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 2e4a4b63b7a..12ad8f91064 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -61,6 +61,7 @@ #include "BKE_context.h" #include "BKE_depsgraph.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_global.h" #include "BKE_main.h" #include "BKE_report.h" @@ -211,7 +212,8 @@ static WMLinkAppendDataItem *wm_link_append_data_item_add( } static void wm_link_do( - WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d) + WMLinkAppendData *lapp_data, ReportList *reports, Main *bmain, Scene *scene, View3D *v3d, + const bool use_placeholders, const bool force_indirect) { Main *mainl; BlendHandle *bh; @@ -258,9 +260,11 @@ static void wm_link_do( continue; } - new_id = BLO_library_link_named_part_ex(mainl, &bh, item->idcode, item->name, flag, scene, v3d); + new_id = BLO_library_link_named_part_ex( + mainl, &bh, item->idcode, item->name, flag, scene, v3d, use_placeholders, force_indirect); + if (new_id) { - /* If the link is sucessful, clear item's libs 'todo' flags. + /* 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; @@ -401,7 +405,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, CTX_wm_view3d(C)); + wm_link_do(lapp_data, op->reports, bmain, scene, CTX_wm_view3d(C), false, false); /* BKE_main_unlock(bmain); */ @@ -518,3 +522,393 @@ void WM_OT_append(wmOperatorType *ot) RNA_def_boolean(ot->srna, "use_recursive", true, "Localize All", "Localize all appended data, including those indirectly linked from other libraries"); } + +/** \name Reload/relocate libraries. + * + * \{ */ + +static int wm_lib_relocate_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + Library *lib; + char lib_name[MAX_NAME]; + + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name); + + if (lib) { + if (lib->parent) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", lib->filepath); + return OPERATOR_CANCELLED; + } + RNA_string_set(op->ptr, "filepath", lib->filepath); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + } + + return OPERATOR_CANCELLED; +} + +/* Note that IDs listed in lapp_data items *must* have been removed from bmain by caller. */ +static void lib_relocate_do(Main *bmain, WMLinkAppendData *lapp_data, ReportList *reports, const bool do_reload) +{ + ListBase *lbarray[MAX_LIBARRAY]; + int lba_idx; + + LinkNode *itemlink; + int item_idx; + + BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); + + /* We do not want any instanciation here! */ + wm_link_do(lapp_data, reports, bmain, NULL, NULL, do_reload, do_reload); + + 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); + } + + /* Note that in reload case, we also want to replace indirect usages. */ + const short remap_flags = ID_REMAP_SKIP_NEVER_NULL_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; + + 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) { +#ifdef PRINT_DEBUG + printf("before remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); +#endif + 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); + } + +#ifdef PRINT_DEBUG + printf("after remap, old_id users: %d, new_id users: %d\n", old_id->us, new_id->us); +#endif + + /* 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(0); /* 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; + } + else 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); + + BKE_reportf(reports, RPT_WARNING, + "Lib Reload: Replacing all references to old datablock '%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); + } + } + + 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_libblock_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_libblock_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_libblock_free(bmain, (ID *)lib); + } + } + } +} + +static int wm_lib_relocate_exec_do(bContext *C, wmOperator *op, bool do_reload) +{ + Library *lib; + char lib_name[MAX_NAME]; + + RNA_string_get(op->ptr, "library", lib_name); + lib = (Library *)BKE_libblock_find_name_ex(CTX_data_main(C), ID_LI, lib_name); + + if (lib) { + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + PropertyRNA *prop; + WMLinkAppendData *lapp_data; + + ListBase *lbarray[MAX_LIBARRAY]; + int lba_idx; + + char path[FILE_MAX], root[FILE_MAXDIR], libname[FILE_MAX], relname[FILE_MAX]; + short flag = 0; + + if (RNA_boolean_get(op->ptr, "relative_path")) { + flag |= FILE_RELPATH; + } + + if (lib->parent && !do_reload) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Cannot relocate indirectly linked library '%s'", lib->filepath); + return OPERATOR_CANCELLED; + } + + RNA_string_get(op->ptr, "directory", root); + RNA_string_get(op->ptr, "filename", libname); + + if (!BLO_has_bfile_extension(libname)) { + BKE_report(op->reports, RPT_ERROR, "Not a library"); + return OPERATOR_CANCELLED; + } + + BLI_join_dirfile(path, sizeof(path), root, libname); + + if (!BLI_exists(path)) { + BKE_reportf(op->reports, RPT_ERROR_INVALID_INPUT, + "Trying to reload or relocate library '%s' to invalid path '%s'", lib->id.name, path); + return OPERATOR_CANCELLED; + } + + if (BLI_path_cmp(lib->filepath, path) == 0) { +#ifdef PRINT_DEBUG + printf("We are supposed to reload '%s' lib (%d)...\n", lib->filepath, lib->id.us); +#endif + + do_reload = true; + + lapp_data = wm_link_append_data_new(flag); + wm_link_append_data_library_add(lapp_data, path); + } + else { + int totfiles = 0; + +#ifdef PRINT_DEBUG + printf("We are supposed to relocate '%s' lib to new '%s' one...\n", lib->filepath, libname); +#endif + + /* Check if something is indicated for relocate. */ + prop = RNA_struct_find_property(op->ptr, "files"); + if (prop) { + totfiles = RNA_property_collection_length(op->ptr, prop); + if (totfiles == 0) { + if (!libname[0]) { + BKE_report(op->reports, RPT_ERROR, "Nothing indicated"); + return OPERATOR_CANCELLED; + } + } + } + + lapp_data = wm_link_append_data_new(flag); + + if (totfiles) { + RNA_BEGIN (op->ptr, itemptr, "files") + { + RNA_string_get(&itemptr, "name", relname); + + BLI_join_dirfile(path, sizeof(path), root, relname); + + if (BLI_path_cmp(path, lib->filepath) == 0 || !BLO_has_bfile_extension(relname)) { + continue; + } + +#ifdef PRINT_DEBUG + printf("\t candidate new lib to reload datablocks from: %s\n", path); +#endif + wm_link_append_data_library_add(lapp_data, path); + } + RNA_END; + } + else { +#ifdef PRINT_DEBUG + printf("\t candidate new lib to reload datablocks from: %s\n", path); +#endif + wm_link_append_data_library_add(lapp_data, path); + } + } + + 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_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 == lib) { + 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 explicitely linked here... */ + BLI_remlink(lbarray[lba_idx], 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); + +#ifdef PRINT_DEBUG + printf("\tdatablock to seek for: %s\n", id->name); +#endif + } + } + } + + lib_relocate_do(bmain, lapp_data, op->reports, do_reload); + + wm_link_append_data_free(lapp_data); + + BKE_main_lib_objects_recalc_all(bmain); + IMB_colormanagement_check_file_config(bmain); + + /* important we unset, otherwise these object wont + * 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 */ + DAG_scene_relations_rebuild(bmain, scene); + + /* free gpu materials, some materials depend on existing objects, such as lamps so freeing correctly refreshes */ + GPU_materials_free(); + + /* XXX TODO: align G.lib with other directory storage (like last opened image etc...) */ + BLI_strncpy(G.lib, root, FILE_MAX); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; + } + + return OPERATOR_CANCELLED; +} + +static int wm_lib_relocate_exec(bContext *C, wmOperator *op) +{ + return wm_lib_relocate_exec_do(C, op, false); +} + +void WM_OT_lib_relocate(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Relocate Library"; + ot->idname = "WM_OT_lib_relocate"; + ot->description = "Relocate the given library to one or several others"; + + ot->invoke = wm_lib_relocate_invoke; + ot->exec = wm_lib_relocate_exec; + + ot->flag |= OPTYPE_UNDO; + + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to relocate"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + WM_operator_properties_filesel( + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_FILES | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); +} + +static int wm_lib_reload_exec(bContext *C, wmOperator *op) +{ + return wm_lib_relocate_exec_do(C, op, true); +} + +void WM_OT_lib_reload(wmOperatorType *ot) +{ + PropertyRNA *prop; + + ot->name = "Reload Library"; + ot->idname = "WM_OT_lib_reload"; + ot->description = "Reload the given library"; + + ot->exec = wm_lib_reload_exec; + + ot->flag |= OPTYPE_UNDO; + + prop = RNA_def_string(ot->srna, "library", NULL, MAX_NAME, "Library", "Library to reload"); + RNA_def_property_flag(prop, PROP_HIDDEN); + + WM_operator_properties_filesel( + ot, FILE_TYPE_FOLDER | FILE_TYPE_BLENDER, FILE_BLENDER, FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_DIRECTORY | WM_FILESEL_FILENAME | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, FILE_SORT_ALPHA); +} + +/** \} */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index 6300d2ed3c7..3022d865460 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -40,6 +40,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_genfile.h" #include "DNA_scene_types.h" #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" @@ -61,6 +62,7 @@ #include "BKE_global.h" #include "BKE_icons.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_main.h" #include "BKE_mball_tessellate.h" #include "BKE_node.h" @@ -140,6 +142,11 @@ static void wm_free_reports(bContext *C) BKE_reports_clear(reports); } +static void wm_undo_kill_callback(bContext *C) +{ + WM_jobs_kill_all_except(CTX_wm_manager(C), CTX_wm_screen(C)); +} + bool wm_start_with_console = false; /* used in creator.c */ /* only called once, for startup */ @@ -158,11 +165,13 @@ void WM_init(bContext *C, int argc, const char **argv) WM_menutype_init(); WM_uilisttype_init(); + BKE_undo_callback_wm_kill_jobs_set(wm_undo_kill_callback); + BKE_library_callback_free_window_manager_set(wm_close_and_free); /* library.c */ BKE_library_callback_free_notifier_reference_set(WM_main_remove_notifier_reference); /* library.c */ - BKE_library_callback_free_editor_id_reference_set(WM_main_remove_editor_id_reference); /* library.c */ + BKE_library_callback_remap_editor_id_reference_set(WM_main_remap_editor_id_reference); /* library.c */ BKE_blender_callback_test_break_set(wm_window_testbreak); /* blender.c */ - BKE_spacedata_callback_id_unref_set(ED_spacedata_id_unref); /* screen.c */ + BKE_spacedata_callback_id_remap_set(ED_spacedata_id_remap); /* screen.c */ DAG_editors_update_cb(ED_render_id_flush_update, ED_render_scene_update, ED_render_scene_update_pre); /* depsgraph.c */ @@ -533,7 +542,7 @@ void WM_exit_ext(bContext *C, const bool do_python) #ifdef WITH_PYTHON /* option not to close python so we can use 'atexit' */ - if (do_python) { + if (do_python && ((C == NULL) || CTX_py_init_get(C))) { /* XXX - old note */ /* before BKE_blender_free so py's gc happens while library still exists */ /* needed at least for a rare sigsegv that can happen in pydrivers */ @@ -576,8 +585,12 @@ void WM_exit_ext(bContext *C, const bool do_python) GHOST_DisposeSystemPaths(); + DNA_sdna_current_free(); + BLI_threadapi_exit(); + BKE_blender_atexit(); + if (MEM_get_memory_blocks_in_use() != 0) { size_t mem_in_use = MEM_get_memory_in_use() + MEM_get_memory_in_use(); printf("Error: Not freed memory blocks: %u, total unfreed memory %f MB\n", diff --git a/source/blender/windowmanager/intern/wm_keymap.c b/source/blender/windowmanager/intern/wm_keymap.c index 72b26cc6207..a11733c060b 100644 --- a/source/blender/windowmanager/intern/wm_keymap.c +++ b/source/blender/windowmanager/intern/wm_keymap.c @@ -1787,7 +1787,17 @@ wmKeyMap *WM_keymap_guess_opname(const bContext *C, const char *opname) } /* UV Editor */ else if (STRPREFIX(opname, "UV_OT")) { - km = WM_keymap_find_all(C, "UV Editor", 0, 0); + /* Hack to allow using UV unwrapping ops from 3DView/editmode. + * Mesh keymap is probably not ideal, but best place I could find to put those. */ + if (sl->spacetype == SPACE_VIEW3D) { + km = WM_keymap_find_all(C, "Mesh", 0, 0); + if (km && km->poll && !km->poll((bContext *)C)) { + km = NULL; + } + } + if (!km) { + km = WM_keymap_find_all(C, "UV Editor", 0, 0); + } } /* Node Editor */ else if (STRPREFIX(opname, "NODE_OT")) { diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 866e332b34f..78273615602 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -2851,8 +2851,8 @@ void WM_OT_straightline_gesture(wmOperatorType *ot) /* *********************** radial control ****************** */ -#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200 * U.pixelsize) -#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35 * U.pixelsize) +#define WM_RADIAL_CONTROL_DISPLAY_SIZE (200) +#define WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE (35) #define WM_RADIAL_CONTROL_DISPLAY_WIDTH (WM_RADIAL_CONTROL_DISPLAY_SIZE - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) #define WM_RADIAL_MAX_STR 10 @@ -2929,7 +2929,7 @@ static void radial_control_set_initial_mouse(RadialControl *rc, const wmEvent *e case PROP_NONE: case PROP_DISTANCE: case PROP_PIXEL: - d[0] = rc->initial_value * U.pixelsize; + d[0] = rc->initial_value; break; case PROP_PERCENTAGE: d[0] = (rc->initial_value) / 100.0f * WM_RADIAL_CONTROL_DISPLAY_WIDTH + WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE; @@ -3055,8 +3055,8 @@ static void radial_control_paint_cursor(bContext *C, int x, int y, void *customd case PROP_NONE: case PROP_DISTANCE: case PROP_PIXEL: - r1 = rc->current_value * U.pixelsize; - r2 = rc->initial_value * U.pixelsize; + r1 = rc->current_value; + r2 = rc->initial_value; tex_radius = r1; alpha = 0.75; break; @@ -3538,7 +3538,6 @@ static int radial_control_modal(bContext *C, wmOperator *op, const wmEvent *even case PROP_PIXEL: new_value = dist; if (snap) new_value = ((int)new_value + 5) / 10 * 10; - new_value /= U.pixelsize; break; case PROP_PERCENTAGE: new_value = ((dist - WM_RADIAL_CONTROL_DISPLAY_MIN_SIZE) / WM_RADIAL_CONTROL_DISPLAY_WIDTH) * 100.0f; @@ -3884,7 +3883,7 @@ static void previews_id_ensure(bContext *C, Scene *scene, ID *id) /* Only preview non-library datablocks, lib ones do not pertain to this .blend file! * Same goes for ID with no user. */ - if (!id->lib && (id->us != 0)) { + if (!ID_IS_LINKED_DATABLOCK(id) && (id->us != 0)) { UI_id_icon_render(C, scene, id, false, false); UI_id_icon_render(C, scene, id, true, false); } @@ -4127,6 +4126,8 @@ void wm_operatortype_init(void) WM_operatortype_append(WM_OT_revert_mainfile); WM_operatortype_append(WM_OT_link); WM_operatortype_append(WM_OT_append); + WM_operatortype_append(WM_OT_lib_relocate); + WM_operatortype_append(WM_OT_lib_reload); WM_operatortype_append(WM_OT_recover_last_session); WM_operatortype_append(WM_OT_recover_auto_save); WM_operatortype_append(WM_OT_save_as_mainfile); @@ -4206,7 +4207,8 @@ static void gesture_circle_modal_keymap(wmKeyConfig *keyconf) WM_modalkeymap_assign(keymap, "MASK_OT_select_circle"); WM_modalkeymap_assign(keymap, "NODE_OT_select_circle"); WM_modalkeymap_assign(keymap, "GPENCIL_OT_select_circle"); - WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "GRAPH_OT_select_circle"); + WM_modalkeymap_assign(keymap, "ACTION_OT_select_circle"); } @@ -4466,7 +4468,7 @@ static EnumPropertyItem *rna_id_itemf(bContext *UNUSED(C), PointerRNA *UNUSED(pt int i = 0; for (; id; id = id->next) { - if (local == false || id->lib == NULL) { + if (local == false || !ID_IS_LINKED_DATABLOCK(id)) { item_tmp.identifier = item_tmp.name = id->name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); diff --git a/source/blender/windowmanager/intern/wm_subwindow.c b/source/blender/windowmanager/intern/wm_subwindow.c index 6526d419914..458ac4a121a 100644 --- a/source/blender/windowmanager/intern/wm_subwindow.c +++ b/source/blender/windowmanager/intern/wm_subwindow.c @@ -378,149 +378,5 @@ void wmOrtho2_pixelspace(const float x, const float y) wmOrtho2_offset(x, y, -GLA_PIXEL_OFS); } -/* *************************** Framebuffer color depth, for selection codes ********************** */ - -#ifdef __APPLE__ - -/* apple seems to round colors to below and up on some configs */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x070707; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x030303; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x010101; - break; - } - - return i; -} - -#else - -/* this is the old method as being in use for ages.... seems to work? colors are rounded to lower values */ - -unsigned int index_to_framebuffer(int index) -{ - unsigned int i = index; - - switch (GPU_color_depth()) { - case 8: - i = ((i & 48) << 18) + ((i & 12) << 12) + ((i & 3) << 6); - i |= 0x3F3F3F; - break; - case 12: - i = ((i & 0xF00) << 12) + ((i & 0xF0) << 8) + ((i & 0xF) << 4); - /* sometimes dithering subtracts! */ - i |= 0x0F0F0F; - break; - case 15: - case 16: - i = ((i & 0x7C00) << 9) + ((i & 0x3E0) << 6) + ((i & 0x1F) << 3); - i |= 0x070707; - break; - case 24: - break; - default: /* 18 bits... */ - i = ((i & 0x3F000) << 6) + ((i & 0xFC0) << 4) + ((i & 0x3F) << 2); - i |= 0x030303; - break; - } - - return i; -} - -#endif - -void WM_framebuffer_index_set(int index) -{ - const int col = index_to_framebuffer(index); - cpack(col); -} - -void WM_framebuffer_index_get(int index, int *r_col) -{ - const int col = index_to_framebuffer(index); - char *c_col = (char *)r_col; - c_col[0] = (col & 0xFF); /* red */ - c_col[1] = ((col >> 8) & 0xFF); /* green */ - c_col[2] = ((col >> 16) & 0xFF); /* blue */ - c_col[3] = 0xFF; /* alpha */ -} - - - -#define INDEX_FROM_BUF_8(col) (((col & 0xC00000) >> 18) + ((col & 0xC000) >> 12) + ((col & 0xC0) >> 6)) -#define INDEX_FROM_BUF_12(col) (((col & 0xF00000) >> 12) + ((col & 0xF000) >> 8) + ((col & 0xF0) >> 4)) -#define INDEX_FROM_BUF_15_16(col) (((col & 0xF80000) >> 9) + ((col & 0xF800) >> 6) + ((col & 0xF8) >> 3)) -#define INDEX_FROM_BUF_18(col) (((col & 0xFC0000) >> 6) + ((col & 0xFC00) >> 4) + ((col & 0xFC) >> 2)) -#define INDEX_FROM_BUF_24(col) (col & 0xFFFFFF) - -int WM_framebuffer_to_index(unsigned int col) -{ - if (col == 0) { - return 0; - } - - switch (GPU_color_depth()) { - case 8: return INDEX_FROM_BUF_8(col); - case 12: return INDEX_FROM_BUF_12(col); - case 15: - case 16: return INDEX_FROM_BUF_15_16(col); - case 24: return INDEX_FROM_BUF_24(col); - default: return INDEX_FROM_BUF_18(col); - } -} - -void WM_framebuffer_to_index_array(unsigned int *col, const unsigned int size) -{ -#define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \ - for (i = size; i--; col++) { \ - if ((c = *col)) { \ - *col = INDEX_FROM_BUF_BITS(c); \ - } \ - } ((void)0) - - if (size > 0) { - unsigned int i, c; - - switch (GPU_color_depth()) { - case 8: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_8); - break; - case 12: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_12); - break; - case 15: - case 16: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_15_16); - break; - case 24: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_24); - break; - default: - INDEX_BUF_ARRAY(INDEX_FROM_BUF_18); - break; - } - } - -#undef INDEX_BUF_ARRAY -} - - /* ********** END MY WINDOW ************** */ diff --git a/source/blender/windowmanager/wm_files.h b/source/blender/windowmanager/wm_files.h index 2eae9cdb012..396907a3f6d 100644 --- a/source/blender/windowmanager/wm_files.h +++ b/source/blender/windowmanager/wm_files.h @@ -59,5 +59,8 @@ void WM_OT_save_mainfile(struct wmOperatorType *ot); void WM_OT_link(struct wmOperatorType *ot); void WM_OT_append(struct wmOperatorType *ot); +void WM_OT_lib_relocate(struct wmOperatorType *ot); +void WM_OT_lib_reload(struct wmOperatorType *ot); + #endif /* __WM_FILES_H__ */ diff --git a/source/blender/windowmanager/wm_subwindow.h b/source/blender/windowmanager/wm_subwindow.h index 2a8118a726b..cc9abf87514 100644 --- a/source/blender/windowmanager/wm_subwindow.h +++ b/source/blender/windowmanager/wm_subwindow.h @@ -48,7 +48,5 @@ void wm_subwindow_matrix_get(wmWindow *win, int swinid, float mat[4][4]); void wm_subwindow_rect_get(wmWindow *win, int swinid, struct rcti *r_rect); void wm_subwindow_rect_set(wmWindow *win, int swinid, const rcti *rect); -unsigned int index_to_framebuffer(int index); - #endif /* __WM_SUBWINDOW_H__ */ diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt index 9d73f0291a1..d7d65629928 100644 --- a/source/blenderplayer/CMakeLists.txt +++ b/source/blenderplayer/CMakeLists.txt @@ -63,6 +63,8 @@ if(WIN32 AND NOT UNIX) COMPONENT Blenderplayer DESTINATION ".") +add_cc_flags_custom_test(blenderplayer) + elseif(APPLE) add_executable(blenderplayer ${EXETYPE} bad_level_call_stubs/stubs.c) # setup Info.plist diff --git a/source/blenderplayer/bad_level_call_stubs/stubs.c b/source/blenderplayer/bad_level_call_stubs/stubs.c index 95abfdc4f4c..7c7958a4acd 100644 --- a/source/blenderplayer/bad_level_call_stubs/stubs.c +++ b/source/blenderplayer/bad_level_call_stubs/stubs.c @@ -326,8 +326,6 @@ bool WM_uilisttype_add(struct uiListType *ult) RET_ZERO void WM_uilisttype_freelink(struct uiListType *ult) RET_NONE void WM_uilisttype_free(void) RET_NONE -void WM_framebuffer_index_get(int index, int *r_col) RET_NONE - struct wmKeyMapItem *WM_keymap_item_find_id(struct wmKeyMap *keymap, int id) RET_NULL int WM_enum_search_invoke(struct bContext *C, struct wmOperator *op, const struct wmEvent *event) RET_ZERO void WM_event_add_notifier(const struct bContext *C, unsigned int type, void *reference) RET_NONE @@ -380,7 +378,7 @@ void ED_area_tag_redraw_regiontype(struct ScrArea *sa, int regiontype) RET_NONE void ED_render_engine_changed(struct Main *bmain) RET_NONE void ED_file_read_bookmarks(void) RET_NONE -void ED_file_change_dir(struct bContext *C, const bool checkdir) RET_NONE +void ED_file_change_dir(struct bContext *C) RET_NONE void ED_preview_kill_jobs(struct wmWindowManager *wm, struct Main *bmain) RET_NONE struct FSMenu *ED_fsmenu_get(void) RET_NULL struct FSMenuEntry *ED_fsmenu_get_category(struct FSMenu *fsmenu, FSMenuCategory category) RET_NULL @@ -526,7 +524,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( struct Main *bmain, struct Scene *scene, int flag) RET_NULL SnapObjectContext *ED_transform_snap_object_context_create_view3d( struct Main *bmain, struct Scene *scene, int flag, - struct ARegion *ar, struct View3D *v3d) RET_NULL + const struct ARegion *ar, const struct View3D *v3d) RET_NULL void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx) RET_NONE bool ED_transform_snap_object_project_ray_ex( struct SnapObjectContext *sctx, diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt index 5bae9fc6349..032a04bb315 100644 --- a/source/creator/CMakeLists.txt +++ b/source/creator/CMakeLists.txt @@ -173,18 +173,28 @@ if(WITH_BUILDINFO) include_directories(${CMAKE_CURRENT_BINARY_DIR}) - # XXX, "_buildinfo.h" is used twice here, + # XXX, ${buildinfo_h_fake} is used here, # because we rely on that file being detected as missing # every build so that the real header "buildinfo.h" is updated. # # Keep this until we find a better way to resolve! + set(buildinfo_h_real "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h") + set(buildinfo_h_fake "${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h_fake") + + if(EXISTS ${buildinfo_h_fake}) + message(FATAL_ERROR "File \"${buildinfo_h_fake}\" found, this should never be created, remove!") + endif() + # a custom target that is always built add_custom_target(buildinfo ALL - DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h) + DEPENDS ${buildinfo_h_fake}) # creates buildinfo.h using cmake script - add_custom_command(OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/_buildinfo.h + add_custom_command( + OUTPUT + ${buildinfo_h_fake} # ensure we always run + ${buildinfo_h_real} COMMAND ${CMAKE_COMMAND} -DSOURCE_DIR=${CMAKE_SOURCE_DIR} # overrides only used when non-empty strings @@ -193,10 +203,14 @@ if(WITH_BUILDINFO) -P ${CMAKE_SOURCE_DIR}/build_files/cmake/buildinfo.cmake) # buildinfo.h is a generated file - set_source_files_properties(${CMAKE_CURRENT_BINARY_DIR}/buildinfo.h + set_source_files_properties( + ${buildinfo_h_real} PROPERTIES GENERATED TRUE HEADER_FILE_ONLY TRUE) + unset(buildinfo_h_real) + unset(buildinfo_h_fake) + # add deps below, after adding blender # -------------- done with header values. @@ -209,6 +223,8 @@ if(WITH_BUILDINFO) add_dependencies(buildinfoobj buildinfo) endif() +add_cc_flags_custom_test(blender) + # message(STATUS "Configuring blender") if(WITH_PYTHON_MODULE) add_definitions(-DWITH_PYTHON_MODULE) @@ -231,7 +247,7 @@ if(WITH_PYTHON_MODULE) set_target_properties( blender PROPERTIES - MACOSX_BUNDLE + MACOSX_BUNDLE TRUE LINK_FLAGS_RELEASE "${PLATFORM_LINKFLAGS}" LINK_FLAGS_DEBUG "${PLATFORM_LINKFLAGS_DEBUG}" ) @@ -339,6 +355,8 @@ if(WITH_PYTHON) DIRECTORY ${CMAKE_SOURCE_DIR}/release/scripts DESTINATION ${TARGETDIR_VER} PATTERN ".git" EXCLUDE + PATTERN ".gitignore" EXCLUDE + PATTERN ".arcconfig" EXCLUDE PATTERN "__pycache__" EXCLUDE PATTERN "${ADDON_EXCLUDE_CONDITIONAL}" EXCLUDE PATTERN "${FREESTYLE_EXCLUDE_CONDITIONAL}" EXCLUDE @@ -539,6 +557,7 @@ if(UNIX AND NOT APPLE) DIRECTORY ${PYTHON_LIBPATH}/python${PYTHON_VERSION} DESTINATION ${TARGETDIR_VER}/python/${_target_LIB} PATTERN "__pycache__" EXCLUDE # * any cache * + PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib PATTERN "lib2to3" EXCLUDE # ./lib2to3 PATTERN "site-packages/*" EXCLUDE # ./site-packages/* PATTERN "tkinter" EXCLUDE # ./tkinter @@ -915,6 +934,7 @@ elseif(APPLE) PATTERN "__pycache__" EXCLUDE PATTERN "__MACOSX" EXCLUDE PATTERN ".DS_Store" EXCLUDE + PATTERN "config-${PYTHON_VERSION}m/*.a" EXCLUDE # static lib ) endmacro() diff --git a/source/creator/creator.c b/source/creator/creator.c index 0cf43dfc7fe..066b0b0ddb3 100644 --- a/source/creator/creator.c +++ b/source/creator/creator.c @@ -42,6 +42,8 @@ #include "MEM_guardedalloc.h" +#include "DNA_genfile.h" + #include "BLI_args.h" #include "BLI_threads.h" #include "BLI_utildefines.h" @@ -150,6 +152,35 @@ static void main_callback_setup(void) MEM_set_error_callback(callback_mem_error); } +/* free data on early exit (if Python calls 'sys.exit()' while parsing args for eg). */ +struct CreatorAtExitData { + bArgs *ba; +#ifdef WIN32 + const char **argv; + int argv_num; +#endif +}; + +static void callback_main_atexit(void *user_data) +{ + struct CreatorAtExitData *app_init_data = user_data; + + if (app_init_data->ba) { + BLI_argsFree(app_init_data->ba); + app_init_data->ba = NULL; + } + +#ifdef WIN32 + if (app_init_data->argv) { + while (app_init_data->argv_num) { + free(app_init_data->argv[--app_init_data->argv_num]); + } + free(app_init_data->argv); + app_init_data->argv = NULL; + } +#endif +} + /** \} */ @@ -201,6 +232,9 @@ int main( /* --- end declarations --- */ + /* ensure we free data on early-exit */ + struct CreatorAtExitData app_init_data = {NULL}; + BKE_blender_atexit_register(callback_main_atexit, &app_init_data); #ifdef WIN32 /* We delay loading of openmp so we can set the policy here. */ @@ -224,6 +258,10 @@ int main( argv[argv_num] = alloc_utf_8_from_16(argv_16[argv_num], 0); } LocalFree(argv_16); + + /* free on early-exit */ + app_init_data.argv = argv; + app_init_data.argv_num = argv_num; } #endif /* WIN32 */ @@ -316,6 +354,8 @@ int main( BLI_threadapi_init(); + DNA_sdna_current_init(); + BKE_blender_globals_init(); /* blender.c */ IMB_init(); @@ -338,6 +378,10 @@ int main( /* first test for background */ #ifndef WITH_PYTHON_MODULE ba = BLI_argsInit(argc, (const char **)argv); /* skip binary path */ + + /* ensure we free on early exit */ + app_init_data.ba = ba; + main_args_setup(C, ba, &syshandle); BLI_argsParse(ba, 1, NULL, NULL); @@ -435,16 +479,22 @@ int main( #endif + /* Explicitly free data allocated for argument parsing: + * - 'ba' + * - 'argv' on WIN32. + */ + callback_main_atexit(&app_init_data); + BKE_blender_atexit_unregister(callback_main_atexit, &app_init_data); + + /* paranoid, avoid accidental re-use */ #ifndef WITH_PYTHON_MODULE - BLI_argsFree(ba); + ba = NULL; + (void)ba; #endif #ifdef WIN32 - while (argv_num) { - free(argv[--argv_num]); - } - free(argv); argv = NULL; + (void)argv; #endif #ifdef WITH_PYTHON_MODULE diff --git a/source/creator/creator_args.c b/source/creator/creator_args.c index 969cbdc4b27..27d3b9218f2 100644 --- a/source/creator/creator_args.c +++ b/source/creator/creator_args.c @@ -739,8 +739,6 @@ static const char arg_handle_debug_mode_generic_set_doc_handlers[] = "\n\tEnable debug messages for event handling"; static const char arg_handle_debug_mode_generic_set_doc_wm[] = "\n\tEnable debug messages for the window manager, also prints every operator call"; -static const char arg_handle_debug_mode_generic_set_doc_all[] = -"\n\tEnable all debug messages (excludes libmv)"; static const char arg_handle_debug_mode_generic_set_doc_jobs[] = "\n\tEnable time profiling for background jobs."; static const char arg_handle_debug_mode_generic_set_doc_gpu[] = @@ -758,6 +756,20 @@ static int arg_handle_debug_mode_generic_set(int UNUSED(argc), const char **UNUS return 0; } +static const char arg_handle_debug_mode_all_doc[] = +"\n\tEnable all debug messages"; +static int arg_handle_debug_mode_all(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data)) +{ + G.debug |= G_DEBUG_ALL; +#ifdef WITH_LIBMV + libmv_startDebugLogging(); +#endif +#ifdef WITH_CYCLES_LOGGING + CCL_start_debug_logging(); +#endif + return 0; +} + #ifdef WITH_LIBMV static const char arg_handle_debug_mode_libmv_doc[] = "\n\tEnable debug messages from libmv library" @@ -1791,8 +1803,7 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle) CB_EX(arg_handle_debug_mode_generic_set, handlers), (void *)G_DEBUG_HANDLERS); BLI_argsAdd(ba, 1, NULL, "--debug-wm", CB_EX(arg_handle_debug_mode_generic_set, wm), (void *)G_DEBUG_WM); - BLI_argsAdd(ba, 1, NULL, "--debug-all", - CB_EX(arg_handle_debug_mode_generic_set, all), (void *)G_DEBUG_ALL); + BLI_argsAdd(ba, 1, NULL, "--debug-all", CB(arg_handle_debug_mode_all), NULL); BLI_argsAdd(ba, 1, NULL, "--debug-fpe", CB(arg_handle_debug_fpe_set), NULL); diff --git a/source/gameengine/Converter/BL_ArmatureObject.cpp b/source/gameengine/Converter/BL_ArmatureObject.cpp index a1819a8dc92..a5af525e13a 100644 --- a/source/gameengine/Converter/BL_ArmatureObject.cpp +++ b/source/gameengine/Converter/BL_ArmatureObject.cpp @@ -233,8 +233,8 @@ BL_ArmatureObject::BL_ArmatureObject( m_lastapplyframe(0.0) { m_origObjArma = armature; // Keep a copy of the original armature so we can fix drivers later - m_objArma = BKE_object_copy(armature); - m_objArma->data = BKE_armature_copy((bArmature *)armature->data); + m_objArma = BKE_object_copy(G.main, armature); + m_objArma->data = BKE_armature_copy(G.main, (bArmature *)armature->data); // During object replication ob->data is increase, we decrease it now because we get a copy. id_us_min(&((bArmature *)m_origObjArma->data)->id); m_pose = m_objArma->pose; @@ -433,8 +433,8 @@ void BL_ArmatureObject::ProcessReplica() KX_GameObject::ProcessReplica(); bArmature* tmp = (bArmature*)m_objArma->data; - m_objArma = BKE_object_copy(m_objArma); - m_objArma->data = BKE_armature_copy(tmp); + m_objArma = BKE_object_copy(G.main, m_objArma); + m_objArma->data = BKE_armature_copy(G.main, tmp); m_pose = m_objArma->pose; } diff --git a/source/gameengine/Converter/BL_BlenderDataConversion.cpp b/source/gameengine/Converter/BL_BlenderDataConversion.cpp index 14dc0d71b83..4751e60996d 100644 --- a/source/gameengine/Converter/BL_BlenderDataConversion.cpp +++ b/source/gameengine/Converter/BL_BlenderDataConversion.cpp @@ -1366,7 +1366,7 @@ static void BL_CreatePhysicsObjectNew(KX_GameObject* gameobj, /* When the parent is not OB_DYNAMIC and has no OB_COLLISION then it gets no bullet controller * and cant be apart of the parents compound shape, same goes for OB_SOFT_BODY */ if (parent && (parent->gameflag & (OB_DYNAMIC | OB_COLLISION))) { - if( (parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) { + if ((parent->gameflag & OB_CHILD)!=0 && (blenderobject->gameflag & OB_CHILD) && !(parent->gameflag & OB_SOFT_BODY)) { isCompoundChild = true; } } diff --git a/source/gameengine/Converter/BL_ShapeDeformer.cpp b/source/gameengine/Converter/BL_ShapeDeformer.cpp index 5e31dabfab1..94256a64d75 100644 --- a/source/gameengine/Converter/BL_ShapeDeformer.cpp +++ b/source/gameengine/Converter/BL_ShapeDeformer.cpp @@ -75,7 +75,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, m_useShapeDrivers(false), m_lastShapeUpdate(-1) { - m_key = BKE_key_copy(m_bmesh->key); + m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL; }; /* this second constructor is needed for making a mesh deformable on the fly. */ @@ -91,7 +91,7 @@ BL_ShapeDeformer::BL_ShapeDeformer(BL_DeformableGameObject *gameobj, m_useShapeDrivers(false), m_lastShapeUpdate(-1) { - m_key = BKE_key_copy(m_bmesh->key); + m_key = m_bmesh->key ? BKE_key_copy(G.main, m_bmesh->key) : NULL; }; BL_ShapeDeformer::~BL_ShapeDeformer() @@ -117,7 +117,7 @@ void BL_ShapeDeformer::ProcessReplica() BL_SkinDeformer::ProcessReplica(); m_lastShapeUpdate = -1; - m_key = BKE_key_copy(m_key); + m_key = m_key ? BKE_key_copy(G.main, m_key) : NULL; } bool BL_ShapeDeformer::LoadShapeDrivers(KX_GameObject* parent) diff --git a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp index b97d0b2a85d..08b569fa4c2 100644 --- a/source/gameengine/Converter/KX_BlenderSceneConverter.cpp +++ b/source/gameengine/Converter/KX_BlenderSceneConverter.cpp @@ -1425,7 +1425,7 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, #ifdef DEBUG printf("Mesh has a user \"%s\"\n", name); #endif - me = (ID*)BKE_mesh_copy_ex(from_maggie, (Mesh*)me); + me = (ID*)BKE_mesh_copy(from_maggie, (Mesh*)me); id_us_min(me); } BLI_remlink(&from_maggie->mesh, me); /* even if we made the copy it needs to be removed */ @@ -1447,12 +1447,12 @@ RAS_MeshObject *KX_BlenderSceneConverter::ConvertMeshSpecial(KX_Scene *kx_scene, /* if its tagged its a replaced material */ if (mat_old && (mat_old->id.tag & LIB_TAG_DOIT) == 0) { Material *mat_old = mesh->mat[i]; - Material *mat_new = BKE_material_copy(mat_old); + Material *mat_new = BKE_material_copy(from_maggie, mat_old); mat_new->id.tag |= LIB_TAG_DOIT; id_us_min(&mat_old->id); - BLI_remlink(&G.main->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex + BLI_remlink(&from_maggie->mat, mat_new); // BKE_material_copy uses G.main, and there is no BKE_material_copy_ex BLI_addtail(&maggie->mat, mat_new); mesh->mat[i] = mat_new; diff --git a/source/gameengine/Converter/KX_ConvertActuators.cpp b/source/gameengine/Converter/KX_ConvertActuators.cpp index 455fef0aceb..974dcbca95b 100644 --- a/source/gameengine/Converter/KX_ConvertActuators.cpp +++ b/source/gameengine/Converter/KX_ConvertActuators.cpp @@ -394,8 +394,9 @@ void BL_ConvertActuators(const char* maggiename, soundActuatorType); // if we made it mono, we have to free it - if(sound && snd_sound && snd_sound != sound->playback_handle) + if (sound && snd_sound && snd_sound != sound->playback_handle) { AUD_Sound_free(snd_sound); + } tmpsoundact->SetName(bact->name); baseact = tmpsoundact; diff --git a/source/gameengine/Expressions/EXP_PyObjectPlus.h b/source/gameengine/Expressions/EXP_PyObjectPlus.h index dd612a08494..32dc79cf6eb 100644 --- a/source/gameengine/Expressions/EXP_PyObjectPlus.h +++ b/source/gameengine/Expressions/EXP_PyObjectPlus.h @@ -73,7 +73,7 @@ typedef struct { wlink.warn_done = true; \ wlink.link = NULL; \ \ - if(wlink_last) { \ + if (wlink_last) { \ wlink_last->link= (void *)&(wlink); \ PyObjectPlus::SetDeprecationWarningLinkLast(&(wlink)); \ } \ @@ -195,7 +195,7 @@ public: \ PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ static PyObject * \ sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); \ @@ -208,7 +208,7 @@ public: \ PyObject *Py##method_name(PyObject *args); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -220,7 +220,7 @@ public: \ PyObject *Py##method_name(); \ static PyObject* \ sPy##method_name(PyObject *self) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -232,7 +232,7 @@ public: \ PyObject *Py##method_name(PyObject *value); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *value) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(value) - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -244,7 +244,7 @@ public: \ PyObject *Py##method_name(PyObject *args, PyObject *kwds); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args, PyObject *kwds) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(...) - " \ BGE_PROXY_ERROR_MSG); return NULL; \ @@ -257,7 +257,7 @@ public: \ PyObject *Py##method_name(PyObject *args); \ static PyObject* \ sPy##method_name(PyObject *self, PyObject *args) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(...) - " \ BGE_PROXY_ERROR_MSG); \ @@ -271,7 +271,7 @@ public: \ PyObject *Py##method_name(PyObject *value); \ static PyObject * \ sPy##method_name(PyObject *self, PyObject *value) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "(value) - " \ BGE_PROXY_ERROR_MSG); \ @@ -285,7 +285,7 @@ public: \ PyObject *Py##method_name(); \ static PyObject * \ sPy##method_name(PyObject *self) { \ - if(BGE_PROXY_REF(self)==NULL) { \ + if (BGE_PROXY_REF(self)==NULL) { \ PyErr_SetString(PyExc_RuntimeError, \ #class_name "." #method_name "() - " \ BGE_PROXY_ERROR_MSG); \ diff --git a/source/gameengine/Expressions/intern/IntValue.cpp b/source/gameengine/Expressions/intern/IntValue.cpp index 25aff5b32ab..7b2e841f13f 100644 --- a/source/gameengine/Expressions/intern/IntValue.cpp +++ b/source/gameengine/Expressions/intern/IntValue.cpp @@ -3,17 +3,17 @@ */ // IntValue.cpp: implementation of the CIntValue class. /* -* Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> -* -* Permission to use, copy, modify, distribute and sell this software -* and its documentation for any purpose is hereby granted without fee, -* provided that the above copyright notice appear in all copies and -* that both that copyright notice and this permission notice appear -* in supporting documentation. Erwin Coumans makes no -* representations about the suitability of this software for any -* purpose. It is provided "as is" without express or implied warranty. -* -*/ + * Copyright (c) 1996-2000 Erwin Coumans <coockie@acm.org> + * + * Permission to use, copy, modify, distribute and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appear in all copies and + * that both that copyright notice and this permission notice appear + * in supporting documentation. Erwin Coumans makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + */ #include <stdio.h> diff --git a/source/gameengine/GameLogic/SCA_PropertySensor.cpp b/source/gameengine/GameLogic/SCA_PropertySensor.cpp index 82f3bee86b2..abb64cf1733 100644 --- a/source/gameengine/GameLogic/SCA_PropertySensor.cpp +++ b/source/gameengine/GameLogic/SCA_PropertySensor.cpp @@ -199,7 +199,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() const float max = m_checkpropmaxval.ToFloat(); float val; - if (orgprop->GetValueType() == VALUE_STRING_TYPE){ + if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = orgprop->GetText().ToFloat(); } else { @@ -240,7 +240,7 @@ bool SCA_PropertySensor::CheckPropertyCondition() const float ref = m_checkpropval.ToFloat(); float val; - if (orgprop->GetValueType() == VALUE_STRING_TYPE){ + if (orgprop->GetValueType() == VALUE_STRING_TYPE) { val = orgprop->GetText().ToFloat(); } else { diff --git a/source/gameengine/GameLogic/SCA_PythonController.cpp b/source/gameengine/GameLogic/SCA_PythonController.cpp index 25936b34fde..fd2e723741c 100644 --- a/source/gameengine/GameLogic/SCA_PythonController.cpp +++ b/source/gameengine/GameLogic/SCA_PythonController.cpp @@ -163,7 +163,9 @@ void SCA_PythonController::SetNamespace(PyObject* pythondictionary) /* Without __file__ set the sys.argv[0] is used for the filename * which ends up with lines from the blender binary being printed in the console */ - PyDict_SetItemString(m_pythondictionary, "__file__", PyUnicode_From_STR_String(m_scriptName)); + PyObject *value = PyUnicode_From_STR_String(m_scriptName); + PyDict_SetItemString(m_pythondictionary, "__file__", value); + Py_DECREF(value); } #endif diff --git a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp index 19aae46f2a3..9a96a7b0334 100644 --- a/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp +++ b/source/gameengine/GameLogic/SCA_PythonKeyboard.cpp @@ -113,11 +113,15 @@ PyObject *SCA_PythonKeyboard::pyattr_get_events(void *self_v, const KX_PYATTRIBU { SCA_PythonKeyboard* self = static_cast<SCA_PythonKeyboard*>(self_v); - for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++) - { + for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); } Py_INCREF(self->m_event_dict); return self->m_event_dict; @@ -129,12 +133,18 @@ PyObject *SCA_PythonKeyboard::pyattr_get_active_events(void *self_v, const KX_PY PyDict_Clear(self->m_event_dict); - for (int i=SCA_IInputDevice::KX_BEGINKEY; i<=SCA_IInputDevice::KX_ENDKEY; i++) - { + for (int i = SCA_IInputDevice::KX_BEGINKEY; i <= SCA_IInputDevice::KX_ENDKEY; i++) { const SCA_InputEvent & inevent = self->m_keyboard->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); + } } Py_INCREF(self->m_event_dict); return self->m_event_dict; diff --git a/source/gameengine/GameLogic/SCA_PythonMouse.cpp b/source/gameengine/GameLogic/SCA_PythonMouse.cpp index 1617f714113..184b306a665 100644 --- a/source/gameengine/GameLogic/SCA_PythonMouse.cpp +++ b/source/gameengine/GameLogic/SCA_PythonMouse.cpp @@ -96,11 +96,15 @@ PyObject *SCA_PythonMouse::pyattr_get_events(void *self_v, const KX_PYATTRIBUTE_ { SCA_PythonMouse* self = static_cast<SCA_PythonMouse*>(self_v); - for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++) - { - const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { + const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); } Py_INCREF(self->m_event_dict); return self->m_event_dict; @@ -112,12 +116,19 @@ PyObject *SCA_PythonMouse::pyattr_get_active_events(void *self_v, const KX_PYATT PyDict_Clear(self->m_event_dict); - for (int i=SCA_IInputDevice::KX_BEGINMOUSE; i<=SCA_IInputDevice::KX_ENDMOUSE; i++) - { - const SCA_InputEvent & inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); + for (int i = SCA_IInputDevice::KX_BEGINMOUSE; i <= SCA_IInputDevice::KX_ENDMOUSE; i++) { + const SCA_InputEvent &inevent = self->m_mouse->GetEventValue((SCA_IInputDevice::KX_EnumInputs)i); - if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) - PyDict_SetItem(self->m_event_dict, PyLong_FromLong(i), PyLong_FromLong(inevent.m_status)); + if (inevent.m_status != SCA_InputEvent::KX_NO_INPUTSTATUS) { + + PyObject *key = PyLong_FromLong(i); + PyObject *value = PyLong_FromLong(inevent.m_status); + + PyDict_SetItem(self->m_event_dict, key, value); + + Py_DECREF(key); + Py_DECREF(value); + } } Py_INCREF(self->m_event_dict); return self->m_event_dict; diff --git a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp index 1b52c61b816..e697306e038 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_Application.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_Application.cpp @@ -633,7 +633,9 @@ bool GPG_Application::initEngine(GHOST_IWindow* window, const int stereoMode) if (!m_rasterizer) goto initFailed; - + + m_rasterizer->PrintHardwareInfo(); + // create the inputdevices m_keyboard = new GPG_KeyboardDevice(); if (!m_keyboard) diff --git a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp index fb99211e3bf..9acd4e441b6 100644 --- a/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp +++ b/source/gameengine/GamePlayer/ghost/GPG_ghost.cpp @@ -46,8 +46,8 @@ #include "KX_PyConstraintBinding.h" // for PHY_SetActiveEnvironment /********************************** -* Begin Blender include block -**********************************/ + * Begin Blender include block + **********************************/ #ifdef __cplusplus extern "C" { @@ -74,6 +74,7 @@ extern "C" #include "BKE_node.h" #include "BKE_report.h" #include "BKE_library.h" +#include "BKE_library_remap.h" #include "BKE_modifier.h" #include "BKE_material.h" #include "BKE_text.h" @@ -104,8 +105,8 @@ extern char datatoc_bmonofont_ttf[]; #include "GPU_draw.h" /********************************** -* End Blender include block -**********************************/ + * End Blender include block + **********************************/ #include "BL_System.h" #include "GPG_Application.h" @@ -464,8 +465,8 @@ int main( /* Win32 Unicode Args */ /* NOTE: cannot use guardedalloc malloc here, as it's not yet initialized - * (it depends on the args passed in, which is what we're getting here!) - */ + * (it depends on the args passed in, which is what we're getting here!) + */ { wchar_t **argv_16 = CommandLineToArgvW(GetCommandLineW(), &argc); argv = (char**)malloc(argc * sizeof(char *)); @@ -711,7 +712,7 @@ int main( { i++; if ( (i + 1) <= validArguments ) - parentWindow = atoi(argv[i++]); + parentWindow = (GHOST_TEmbedderWindowID)atoll(argv[i++]); else { error = true; printf("error: too few options for parent window argument.\n"); diff --git a/source/gameengine/Ketsji/BL_Action.cpp b/source/gameengine/Ketsji/BL_Action.cpp index 45946f30827..7175eb877dd 100644 --- a/source/gameengine/Ketsji/BL_Action.cpp +++ b/source/gameengine/Ketsji/BL_Action.cpp @@ -161,7 +161,7 @@ bool BL_Action::Play(const char* name, BKE_libblock_free(G.main, m_tmpaction); m_tmpaction = NULL; } - m_tmpaction = BKE_action_copy(m_action); + m_tmpaction = BKE_action_copy(G.main, m_action); // First get rid of any old controllers ClearControllerList(); diff --git a/source/gameengine/Ketsji/KX_GameObject.cpp b/source/gameengine/Ketsji/KX_GameObject.cpp index 69c1af35bd9..3244400e1bd 100644 --- a/source/gameengine/Ketsji/KX_GameObject.cpp +++ b/source/gameengine/Ketsji/KX_GameObject.cpp @@ -142,7 +142,7 @@ KX_GameObject::~KX_GameObject() } // Unregister collision callbacks // Do this before we start freeing physics information like m_pClient_info - if (m_collisionCallbacks){ + if (m_collisionCallbacks) { UnregisterCollisionCallbacks(); Py_CLEAR(m_collisionCallbacks); } @@ -1564,7 +1564,7 @@ void KX_GameObject::UnregisterCollisionCallbacks() PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); PHY_IPhysicsController* spc = GetPhysicsController(); // If we are the last to unregister on this physics controller - if (pe->RemoveCollisionCallback(spc)){ + if (pe->RemoveCollisionCallback(spc)) { // If we are a sensor object if (m_pClient_info->isSensor()) // Remove sensor body from physics world @@ -1584,7 +1584,7 @@ void KX_GameObject::RegisterCollisionCallbacks() PHY_IPhysicsEnvironment* pe = scene->GetPhysicsEnvironment(); PHY_IPhysicsController* spc = GetPhysicsController(); // If we are the first to register on this physics controller - if (pe->RequestCollisionCallback(spc)){ + if (pe->RequestCollisionCallback(spc)) { // If we are a sensor object if (m_pClient_info->isSensor()) // Add sensor body to physics world diff --git a/source/gameengine/Ketsji/KX_Light.cpp b/source/gameengine/Ketsji/KX_Light.cpp index 9ccf60b15ce..5f490747c2b 100644 --- a/source/gameengine/Ketsji/KX_Light.cpp +++ b/source/gameengine/Ketsji/KX_Light.cpp @@ -195,7 +195,7 @@ int KX_LightObject::pyattr_set_layer(void *self_v, const KX_PYATTRIBUTE_DEF *att PyErr_Format(PyExc_TypeError, "expected an integer greater than 1 for attribute \"%s\"", attrdef->m_name); return PY_SET_ATTR_FAIL; } - else if(layer > MAX_LIGHT_LAYERS) { + else if (layer > MAX_LIGHT_LAYERS) { PyErr_Format(PyExc_TypeError, "expected an integer less than %i for attribute \"%s\"", MAX_LIGHT_LAYERS, attrdef->m_name); return PY_SET_ATTR_FAIL; } diff --git a/source/gameengine/Ketsji/KX_Scene.cpp b/source/gameengine/Ketsji/KX_Scene.cpp index 47ba2c4343f..c0d99d16a4c 100644 --- a/source/gameengine/Ketsji/KX_Scene.cpp +++ b/source/gameengine/Ketsji/KX_Scene.cpp @@ -1785,7 +1785,7 @@ void KX_Scene::UpdateObjectLods(void) for (int i = 0; i < this->GetObjectList()->GetCount(); i++) { gameobj = (KX_GameObject*) GetObjectList()->GetValue(i); - if (!gameobj->GetCulled()){ + if (!gameobj->GetCulled()) { gameobj->UpdateLod(cam_pos); } } diff --git a/source/gameengine/Ketsji/KX_SoundActuator.cpp b/source/gameengine/Ketsji/KX_SoundActuator.cpp index 1c42d65ae75..a27f37c0441 100644 --- a/source/gameengine/Ketsji/KX_SoundActuator.cpp +++ b/source/gameengine/Ketsji/KX_SoundActuator.cpp @@ -79,21 +79,18 @@ KX_SoundActuator::KX_SoundActuator(SCA_IObject* gameobj, KX_SoundActuator::~KX_SoundActuator() { - if(m_handle) - { + if (m_handle) { AUD_Handle_stop(m_handle); } - if(m_sound) - { + if (m_sound) { AUD_Sound_free(m_sound); } } void KX_SoundActuator::play() { - if(m_handle) - { + if (m_handle) { AUD_Handle_stop(m_handle); m_handle = NULL; } @@ -130,10 +127,8 @@ void KX_SoundActuator::play() if(sound != m_sound) AUD_Sound_free(sound); - if (m_handle != NULL) - { - if (m_is3d) - { + if (m_handle != NULL) { + if (m_is3d) { AUD_Handle_setRelative(m_handle, true); AUD_Handle_setVolumeMaximum(m_handle, m_3d.max_gain); AUD_Handle_setVolumeMinimum(m_handle, m_3d.min_gain); diff --git a/source/gameengine/Ketsji/KX_TrackToActuator.cpp b/source/gameengine/Ketsji/KX_TrackToActuator.cpp index beccdfaad93..a8fa9b0815d 100644 --- a/source/gameengine/Ketsji/KX_TrackToActuator.cpp +++ b/source/gameengine/Ketsji/KX_TrackToActuator.cpp @@ -207,7 +207,7 @@ static MT_Matrix3x3 vectomat(MT_Vector3 vec, short axis, short upflag, short thr vec = vec.safe_normalized_vec(z); /* if 2D doesn't move the up vector */ - if (!threedimup){ + if (!threedimup) { vec.setValue(MT_Scalar(vec[0]), MT_Scalar(vec[1]), MT_Scalar(0.0f)); vec = (vec - z.dot(vec)*z).safe_normalized_vec(z); } diff --git a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp index c1af6de127e..ddae645802c 100644 --- a/source/gameengine/Ketsji/KX_VehicleWrapper.cpp +++ b/source/gameengine/Ketsji/KX_VehicleWrapper.cpp @@ -89,17 +89,17 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) if (gameOb->GetSGNode()) { MT_Vector3 attachPos,attachDir,attachAxle; - if(!PyVecTo(pylistPos,attachPos)) { + if (!PyVecTo(pylistPos,attachPos)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. attachPos must be a vector with 3 elements."); return NULL; } - if(!PyVecTo(pylistDir,attachDir)) { + if (!PyVecTo(pylistDir,attachDir)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. downDir must be a vector with 3 elements."); return NULL; } - if(!PyVecTo(pylistAxleDir,attachAxle)) { + if (!PyVecTo(pylistAxleDir,attachAxle)) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. axleDir must be a vector with 3 elements."); return NULL; @@ -108,7 +108,7 @@ PyObject *KX_VehicleWrapper::PyAddWheel(PyObject *args) //someone reverse some conventions inside Bullet (axle winding) attachAxle = -attachAxle; - if(wheelRadius<=0) { + if (wheelRadius <= 0) { PyErr_SetString(PyExc_AttributeError, "addWheel(...) Unable to add wheel. wheelRadius must be positive."); return NULL; diff --git a/source/gameengine/Physics/Bullet/CcdPhysicsController.h b/source/gameengine/Physics/Bullet/CcdPhysicsController.h index 58ea5e2e390..831e7346df7 100644 --- a/source/gameengine/Physics/Bullet/CcdPhysicsController.h +++ b/source/gameengine/Physics/Bullet/CcdPhysicsController.h @@ -430,7 +430,7 @@ public: // PHY_ICharacter interface virtual void Jump() { jump(); } - virtual bool OnGround(){ return onGround(); } + virtual bool OnGround() { return onGround(); } virtual float GetGravity() { return getGravity(); } virtual void SetGravity(float gravity) { setGravity(gravity); } virtual unsigned char GetMaxJumps() { return getMaxJumps(); } @@ -542,14 +542,14 @@ protected: CcdPhysicsController (const CcdConstructionInfo& ci); /** - * Delete the current Bullet shape used in the rigid body. - */ + * Delete the current Bullet shape used in the rigid body. + */ bool DeleteControllerShape(); /** - * Delete the old Bullet shape and set the new Bullet shape : newShape - * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape - */ + * Delete the old Bullet shape and set the new Bullet shape : newShape + * \param newShape The new Bullet shape to set, if is NULL we create a new Bullet shape + */ bool ReplaceControllerShape(btCollisionShape *newShape); virtual ~CcdPhysicsController(); diff --git a/source/gameengine/Physics/common/PHY_ICharacter.h b/source/gameengine/Physics/common/PHY_ICharacter.h index 81c567ef08a..1a924904b7d 100644 --- a/source/gameengine/Physics/common/PHY_ICharacter.h +++ b/source/gameengine/Physics/common/PHY_ICharacter.h @@ -15,7 +15,7 @@ class PHY_ICharacter { public: - virtual ~PHY_ICharacter(){}; + virtual ~PHY_ICharacter() {}; virtual void Jump()= 0; virtual bool OnGround()= 0; diff --git a/source/gameengine/Physics/common/PHY_IController.h b/source/gameengine/Physics/common/PHY_IController.h index 284d77ca221..741fae8d2ad 100644 --- a/source/gameengine/Physics/common/PHY_IController.h +++ b/source/gameengine/Physics/common/PHY_IController.h @@ -48,7 +48,7 @@ class PHY_IPhysicsEnvironment; class PHY_IController { public: - virtual ~PHY_IController(){}; + virtual ~PHY_IController() {}; // clientinfo for raycasts for example virtual void* GetNewClientInfo()=0; virtual void SetNewClientInfo(void* clientinfo)=0; diff --git a/source/gameengine/Physics/common/PHY_IMotionState.h b/source/gameengine/Physics/common/PHY_IMotionState.h index d40b8da9451..e803d658713 100644 --- a/source/gameengine/Physics/common/PHY_IMotionState.h +++ b/source/gameengine/Physics/common/PHY_IMotionState.h @@ -44,7 +44,7 @@ class PHY_IMotionState { public: - virtual ~PHY_IMotionState(){}; + virtual ~PHY_IMotionState() {}; virtual void GetWorldPosition(float& posX,float& posY,float& posZ)=0; virtual void GetWorldScaling(float& scaleX,float& scaleY,float& scaleZ)=0; diff --git a/source/gameengine/Physics/common/PHY_IPhysicsController.h b/source/gameengine/Physics/common/PHY_IPhysicsController.h index 62b163536dd..4c6e8c71ef7 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsController.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsController.h @@ -53,7 +53,7 @@ class PHY_IPhysicsController : public PHY_IController { public: - virtual ~PHY_IPhysicsController(){}; + virtual ~PHY_IPhysicsController() {}; /** * SynchronizeMotionStates ynchronizes dynas, kinematic and deformable entities (and do 'late binding') */ diff --git a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h index 2997048805f..72ec7b1edd0 100644 --- a/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h +++ b/source/gameengine/Physics/common/PHY_IPhysicsEnvironment.h @@ -116,7 +116,7 @@ public: class PHY_IPhysicsEnvironment { public: - virtual ~PHY_IPhysicsEnvironment(){} + virtual ~PHY_IPhysicsEnvironment() {} virtual void BeginFrame() = 0; virtual void EndFrame() = 0; /// Perform an integration step of duration 'timeStep'. diff --git a/source/gameengine/Physics/common/PHY_IVehicle.h b/source/gameengine/Physics/common/PHY_IVehicle.h index 1dcec69a335..7e4a49e923e 100644 --- a/source/gameengine/Physics/common/PHY_IVehicle.h +++ b/source/gameengine/Physics/common/PHY_IVehicle.h @@ -18,7 +18,7 @@ class PHY_IMotionState; class PHY_IVehicle { public: - virtual ~PHY_IVehicle(){}; + virtual ~PHY_IVehicle() {}; virtual void AddWheel( PHY_IMotionState* motionState, diff --git a/source/gameengine/Rasterizer/RAS_IOffScreen.h b/source/gameengine/Rasterizer/RAS_IOffScreen.h index e5f3dc43e5f..d61a31504b8 100644 --- a/source/gameengine/Rasterizer/RAS_IOffScreen.h +++ b/source/gameengine/Rasterizer/RAS_IOffScreen.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_ISync.h b/source/gameengine/Rasterizer/RAS_ISync.h index b9987dc1cad..7e34172c2a3 100644 --- a/source/gameengine/Rasterizer/RAS_ISync.h +++ b/source/gameengine/Rasterizer/RAS_ISync.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp index 26ece47d8b3..e589bffcaf1 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.cpp @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h index 94d0d4aa105..3f6845f1e21 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLOffScreen.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp index fcb11ce2355..3f82c513f7d 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLRasterizer.cpp @@ -141,8 +141,6 @@ RAS_OpenGLRasterizer::RAS_OpenGLRasterizer(RAS_ICanvas* canvas, RAS_STORAGE_TYPE glGetIntegerv(GL_MAX_LIGHTS, (GLint *) &m_numgllights); if (m_numgllights < 8) m_numgllights = 8; - - PrintHardwareInfo(); } diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp index ebb4a9a3ca1..d54b3232067 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.cpp @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h index 9b6340b04ac..4ba96903856 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_OpenGLSync.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h index 34fdca23ee6..a5a3170ed77 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVA.h @@ -45,7 +45,7 @@ public: virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; + virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; protected: int m_drawingmode; diff --git a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h index 9cb3449bed5..4c8e4a8931c 100644 --- a/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h +++ b/source/gameengine/Rasterizer/RAS_OpenGLRasterizer/RAS_StorageVBO.h @@ -76,7 +76,7 @@ public: virtual void IndexPrimitives(RAS_MeshSlot& ms); - virtual void SetDrawingMode(int drawingmode){m_drawingmode=drawingmode;}; + virtual void SetDrawingMode(int drawingmode) {m_drawingmode = drawingmode;}; protected: int m_drawingmode; diff --git a/source/gameengine/VideoTexture/DeckLink.cpp b/source/gameengine/VideoTexture/DeckLink.cpp index 0506756ef2d..fa8ab8c641c 100644 --- a/source/gameengine/VideoTexture/DeckLink.cpp +++ b/source/gameengine/VideoTexture/DeckLink.cpp @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/VideoTexture/DeckLink.h b/source/gameengine/VideoTexture/DeckLink.h index 1c96af7b4bc..4528fe7cec0 100644 --- a/source/gameengine/VideoTexture/DeckLink.h +++ b/source/gameengine/VideoTexture/DeckLink.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/VideoTexture/VideoDeckLink.cpp b/source/gameengine/VideoTexture/VideoDeckLink.cpp index c8d3c28c551..4f5e34896fc 100644 --- a/source/gameengine/VideoTexture/VideoDeckLink.cpp +++ b/source/gameengine/VideoTexture/VideoDeckLink.cpp @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/gameengine/VideoTexture/VideoDeckLink.h b/source/gameengine/VideoTexture/VideoDeckLink.h index be81f63d93c..50099d2ead4 100644 --- a/source/gameengine/VideoTexture/VideoDeckLink.h +++ b/source/gameengine/VideoTexture/VideoDeckLink.h @@ -15,12 +15,12 @@ * 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) 2015, Blender Foundation -* All rights reserved. -* -* The Original Code is: all of this file. -* -* Contributor(s): Blender Foundation. + * The Original Code is Copyright (C) 2015, Blender Foundation + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): Blender Foundation. * * ***** END GPL LICENSE BLOCK ***** */ diff --git a/source/tools b/source/tools new file mode 160000 +Subproject 373945d0978b6601c55c9d5879e0f488b18515c diff --git a/tests/gtests/blenlib/BLI_array_utils_test.cc b/tests/gtests/blenlib/BLI_array_utils_test.cc index e532419691a..eabf5bc72cf 100644 --- a/tests/gtests/blenlib/BLI_array_utils_test.cc +++ b/tests/gtests/blenlib/BLI_array_utils_test.cc @@ -5,6 +5,7 @@ extern "C" { #include "BLI_utildefines.h" #include "BLI_array_utils.h" +#include "BLI_stackdefines.h" } /* -------------------------------------------------------------------- */ @@ -44,33 +45,102 @@ TEST(array_utils, ReverseInt4) TEST(array_utils, FindIndexStringEmpty) { char data[] = "", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexStringSingle) { char data[] = "0", find = '0'; - EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(0, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexStringSingleMissing) { char data[] = "1", find = '0'; - EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(-1, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexString4) { char data[] = "0123", find = '3'; - EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data) - 1, &find)); } TEST(array_utils, FindIndexInt4) { - int data[] = {0, 1, 2, 3}, find = 2; - EXPECT_EQ(2, BLI_array_findindex(data, ARRAY_SIZE(data) - 1, &find)); + int data[] = {0, 1, 2, 3}, find = 3; + EXPECT_EQ(3, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); } +TEST(array_utils, FindIndexInt4_DupeEnd) +{ + int data[] = {0, 1, 2, 0}, find = 0; + EXPECT_EQ(0, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(3, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); +} + +TEST(array_utils, FindIndexInt4_DupeMid) +{ + int data[] = {1, 0, 0, 3}, find = 0; + EXPECT_EQ(1, BLI_array_findindex(data, ARRAY_SIZE(data), &find)); + EXPECT_EQ(2, BLI_array_rfindindex(data, ARRAY_SIZE(data), &find)); +} + +TEST(array_utils, FindIndexPointer) +{ + const char *data[4] = {NULL}; + STACK_DECLARE(data); + + STACK_INIT(data, ARRAY_SIZE(data)); + + const char *a = "a", *b = "b", *c = "c", *d = "d"; + +#define STACK_PUSH_AND_CHECK_FORWARD(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + +#define STACK_PUSH_AND_CHECK_BACKWARD(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + +#define STACK_PUSH_AND_CHECK_BOTH(v, i) { \ + STACK_PUSH(data, v); \ + EXPECT_EQ(i, BLI_array_findindex(data, STACK_SIZE(data), &(v))); \ + EXPECT_EQ(i, BLI_array_rfindindex(data, STACK_SIZE(data), &(v))); \ +} ((void)0) + + STACK_PUSH_AND_CHECK_BOTH(a, 0); + STACK_PUSH_AND_CHECK_BOTH(b, 1); + STACK_PUSH_AND_CHECK_BOTH(c, 2); + STACK_PUSH_AND_CHECK_BOTH(d, 3); + + STACK_POP(data); + STACK_PUSH_AND_CHECK_BACKWARD(a, 3); + + STACK_POP(data); + STACK_PUSH_AND_CHECK_FORWARD(a, 0); + + STACK_POP(data); + STACK_POP(data); + + STACK_PUSH_AND_CHECK_BACKWARD(b, 2); + STACK_PUSH_AND_CHECK_BACKWARD(a, 3); + +#undef STACK_PUSH_AND_CHECK_FORWARD +#undef STACK_PUSH_AND_CHECK_BACKWARD +#undef STACK_PUSH_AND_CHECK_BOTH + +} + + + /* BLI_array_binary_and */ #define BINARY_AND_TEST(data_cmp, data_a, data_b, data_combine, length) \ { \ diff --git a/tests/gtests/bmesh/bmesh_core_test.cc b/tests/gtests/bmesh/bmesh_core_test.cc index 0cbb6ca343e..f386abc0b2b 100644 --- a/tests/gtests/bmesh/bmesh_core_test.cc +++ b/tests/gtests/bmesh/bmesh_core_test.cc @@ -9,7 +9,9 @@ TEST(bmesh_core, BMVertCreate) { BMVert *bv1, *bv2, *bv3; const float co1[3] = {1.0f, 2.0f, 0.0f}; - bm = BM_mesh_create(&bm_mesh_allocsize_default); + BMeshCreateParams bm_params; + bm_params.use_toolflags = true; + bm = BM_mesh_create(&bm_mesh_allocsize_default, &bm_params); EXPECT_EQ(0, bm->totvert); /* make a custom layer so we can see if it is copied properly */ BM_data_layer_add(bm, &bm->vdata, CD_PROP_FLT); diff --git a/tests/python/cycles_render_tests.py b/tests/python/cycles_render_tests.py index 36fad175cfa..e1b5e2d1d23 100755 --- a/tests/python/cycles_render_tests.py +++ b/tests/python/cycles_render_tests.py @@ -3,6 +3,7 @@ import argparse import os +import shutil import subprocess import sys import tempfile @@ -53,19 +54,24 @@ def verify_output(filepath): dirpath = os.path.dirname(filepath) reference_dirpath = os.path.join(dirpath, "reference_renders") reference_image = os.path.join(reference_dirpath, testname + ".png") + failed_image = os.path.join(reference_dirpath, testname + ".fail.png") if not os.path.exists(reference_image): return False command = ( IDIFF, - "-fail", "0.01", + "-fail", "0.015", "-failpercent", "1", reference_image, TEMP_FILE, ) try: subprocess.check_output(command) + if os.path.exists(failed_image): + os.remove(failed_image) return True except subprocess.CalledProcessError as e: + if e.returncode != 1: + shutil.copy(TEMP_FILE, failed_image) if VERBOSE: print(e.output.decode("utf-8")) return e.returncode == 1 |